美文网首页
Java8——Lambda表达式

Java8——Lambda表达式

作者: 程序员小杰 | 来源:发表于2020-10-20 21:48 被阅读0次

    为什么使用Lamdba表达式

    我来举一个范例就知道了

    使用匿名内部类

        public void test1(){
            Comparator<Integer> com = new Comparator<Integer>() {
                @Override
                public int compare(Integer o1, Integer o2) {
                    return Integer.compare(o2,o1);
                }
            };
        }
    

    上面那么多的代码其实就一句话有用Integer.compare(o2,o1);

    使用Lambda表达式

       public void test2(){
            Comparator<Integer> com = (o1, o2) -> Integer.compare(o1, o2);
        }
    

    是不是很方便了。但可能也会有人觉得并没有什么太大的简便。那么下面再给出一个例子来引入Lambda表达式。
    创建Employee类,有name、age、salary三个属性

    public class Employee {
        private String name;
        private int age;
        private double salary;
    
        public Employee() {
        }
        public Employee(String name, int age, double salary) {
            this.name = name;
            this.age = age;
            this.salary = salary;
        }
        public String getName() {
            return name;
        }
        public int getAge() {
            return age;
        }
        public double getSalary() {
            return salary;
        }
    
        @Override
        public String toString() {
            return "name='" + name + '\'' +
                    ", age=" + age +
                    ", salary=" + salary;
        }
    }
    
    • 需求1:获取员工年龄大于35的员工信息

    我们模拟一下数据库,所以准备一个List集合

    //Arrays.asList 将数组转换成集合
    List<Employee> employees = Arrays.asList(
        new Employee("张三",18,9999.99),
        new Employee("李四",38,5555.55),
        new Employee("王五",50,6666.66),
        new Employee("赵六",16,3333.33),
        new Employee("田七",8,7777.77)
    );
    

    既然来了需求那我们就要开发呀

      /**
         * 获取员工年龄大于35的员工信息
         * @param list
         * @return
         */
        public List<Employee> findEmployeesByAge(List<Employee>list){
            List<Employee>emps = new ArrayList<>();
            for(Employee emp : list){
                if(emp.getAge() > 35){
                    emps.add(emp);
                }
            }
            return emps;
        }
    

    并且来波开发自测

     @Test
        public void test3(){
            List<Employee> employeesByAge = findEmployeesByAge(employees);
            for (Employee employee : employeesByAge) {
                System.out.println(employee);
            }
        }
    
    输出结果
    name='李四', age=38, salary=5555.55
    name='王五', age=50, salary=6666.66
    

    完美!!!美滋滋。完成任务

    • 需求2:获取公司中工资大于5000的员工信息
     public List<Employee> findEmployeesBySalary(List<Employee>list){
            List<Employee>emps = new ArrayList<>();
            for(Employee emp : list){
                if(emp.getSalary() > 5000){
                    emps.add(emp);
                }
            }
            return emps;
        }
    

    你写完之后发现,特么...就改了个方法名和判断条件,聪明的你发现这代码不能这么写。为什么不能这么写呢!如果你牛逼的客户**,突然又来了一个需求,获取年龄大于20的,薪资大于3000的。你第一个想到的是将判断条件提取为参数,你有推翻了这种想法,你觉得这样不够灵活。突然,你想到了设计模式。

    优化一:设计模式之策略模式

    创建查询行为的接口

    public interface MyPredicate<T> {
        public boolean test();
    }
    

    并创建相关的实现类代表不同的行为: (分别是年龄> 35和工资> 5000的 )

    //获取员工年龄大于35的员工信息
    public class FindEmployeesByAge implements MyPredicate<Employee>{
        @Override
        public boolean test(Employee emp) {
            return emp.getAge() > 35;
        }
    }
    
    
    //获取公司中工资大于5000的员工信息
    public class FindEmployeesBySalary implements MyPredicate<Employee>{
        @Override
        public boolean test(Employee emp) {
            return emp.getSalary() > 5000;
        }
    }
    

    给外部提供一个通用方法

    public List<Employee> filterEmployees(List<Employee>list,MyPredicate<Employee>mp){
        List<Employee>emps = new ArrayList<>();
        for(Employee emp : list){
            if(mp.test(emp)){  //重点代码
                emps.add(emp);
            }
        }
        return emps;
    }
    

    写了这么久自测一下

      @Test
       public void test4(){
           List<Employee> employees = filterEmployees(this.employees, new FindEmployeesByAge());
           for (Employee employee : employees) {
               System.out.println(employee);
           }
       }
    
    输出结果
    name='李四', age=38, salary=5555.55
    name='王五', age=50, salary=6666.66
    

    如果想要测试工资大于5000的员工信息,只需要换掉 filterEmployees(this.employees, new FindEmployeesByAge())中的FindEmployeesByAgeFindEmployeesBySalary

    优化二:匿名内部类

    好处:不需要创建接口的具体的实现类(但还是需要MyPredicate接口和filterEmployees()方法):

      @Test
        public void test5(){
            List<Employee> employees = filterEmployees(this.employees, new MyPredicate<Employee>() {
                @Override
                public boolean test(Employee employee) {
                    return employee.getAge() >= 18;
                }
            });
            for (Employee employee : employees) {
                System.out.println(employee);
            }
        }
    输出结果
    name='张三', age=18, salary=9999.99
    name='李四', age=38, salary=5555.55
    name='王五', age=50, salary=6666.66
    

    优化三:Lambda表达式

    哈哈哈,优化优化就回到了开头那个例子(*^▽^*),Lambda表达式省去匿名内部类的没用的代码,提高了代码的整洁性和可读性(注需要那个filterEmployees方法)

     @Test
        public void test6(){
            List<Employee> employees = filterEmployees(this.employees, (e) -> e.getAge() > 15);
            for (Employee employee : employees) {
                System.out.println(employee);
            }
        }
    输出结果
    name='张三', age=18, salary=9999.99
    name='李四', age=38, salary=5555.55
    name='王五', age=50, salary=6666.66
    name='赵六', age=16, salary=3333.33
    

    优化四:使用Stream API

    使用该方式,不需要我们上面所创建的所有方法,包括接口、实现类。当然数据还是要的。

      @Test
        public void test7(){
            employees.stream()
                    .filter((e) -> e.getAge() > 35)
                    .forEach(System.out::println);
        }
    输出结果
    name='李四', age=38, salary=5555.55
    name='王五', age=50, salary=6666.66
    

    Lambda表达式基础语法

    Java8中引入了一个新的操作符,"->",该操作符称为箭头操作符或者Lambda操作符,箭头操作符将Lambda表达式拆分成两部分:

    • 左侧: Lambda表达式的参数列表,也就是接口中抽象方法的参数列表
    • 右侧: Lambda表达式中所需要执行的功能(即:Lambda体),对应的是对抽象方法的实现
      注:Lambda表达式需要函数式接口的支持。所谓函数式接口就是接口中只能有一个抽象方法

    基础语法

    • 语法格式一:无参数,无返回值
      @Test
        public void test1(){
    
            Runnable runnable = new Runnable() {
                @Override
                public void run() {
                    System.out.println("普通 Runnable");
                }
            };
            runnable.run();
    
            System.out.println("=============我是分割线=============");
    
            Runnable runnable1 = () -> System.out.println("Lambda Runnable");System.out.println("Lambda Runnable");
            runnable1.run();
        }
    
    输出
    普通 Runnable
    =============我是分割线=============
    Lambda Runnable
    
    • 语法格式二:一个参数、无返回值(参数列表中有且只有一个参数,那么小括号可以省略不写)
    
        @Test
        public void test2(){
            Consumer con = (x) -> System.out.println(x);
        //Consumer con = x -> System.out.println(x);
            con.accept("NiuBi Class");
        }
    
    • 语法格式三: 多个参数,有返回值,Lambda体只有一条语句(大括号和return可以省略)
       @Test
        public void test3(){
           Comparator<Integer> com = (x,y) -> Integer.compare(x, y);
        }
    
    • 语法格式四:多个参数,有返回值,Lambda体有多条语句(要用大括号括起来,并且要写上return)
    @Test
      public void test4(){
            Comparator<Integer>com = (x,y) -> {
                System.out.println("函数式接口");
                return Integer.compare(x,y);
            };
    }
    
    • 语法格式五:Lambda表达式的参数列表的数据类型可以省略不写,因为JVM编译器通过上下文推断出数据类型,这过程称之为"类型推断",例如:(Integer x,Integer y ) -> Integer.compare(x,y); 可以简写成(x,y) -> Integer.compare(x,y);

    函数式接口

    • 接口中只有一个抽象方法的接口称为函数式接口
    • 使用注解@FunctionlInterface来检查是否是函数式接口
      需求: 对一个数进行+-*/的运算:
      函数式接口:
    @FunctionalInterface
    public interface MyFun {
        Integer getValue(Integer num);
    }
    

    通用方法:

     public Integer operation(Integer num,MyFun mf){
            return mf.getValue(num);
        }
    

    测试:

     @Test
        public void test5(){
            System.out.println(this.operation(100,(x) -> x * x ));
        }
    

    四大内置函数式接口

    我们发现,如果使用Lambda还要自己写一个接口的话太麻烦,所以Java8提供四大内置函数式接口,只有一小部分比较特殊得情况需要我们自己去定义函数式接口

    • Consumer<T> 消费型接口 void accept(T t); :对类型为T的对象应用操作
    • Supplier<T> 供给型接口 T get(); :返回类型为T的对象
    • Function<T, R> 函数型接口 R apply (T t);:对类型为T的对象应用操作,并返回结果,结果是R类型的对象
    • Predicate<T> 断言形接口 boolean test(T t);:确定类型为T的对象是否满足某约束,并返回boolean值
      image.png

    Consumer<T> 消费型接口 void accept(T t);

    @Test
        public void test1() {
           //例子1
            happy(1000,(x)->System.out.println("你在我这消费了" + x + "元"));
            //例子2
            List<String> list = Arrays.asList("1", "2", "3");
            list.forEach((obj) -> System.out.println(obj));
        }
    

    Supplier<T> 供给型接口 T get();

    需求: 产生指定个数的整数,并放入集合中

    @Test
       public void test2(){
           List<Integer> numList = getNumList(5, () -> (int) (Math.random() * 100));
           numList.forEach((obj)->System.out.println(obj));
       }
    
        public List<Integer> getNumList(int num, Supplier<Integer> sup){
            ArrayList<Integer> list = new ArrayList<>();
            for (int i = 0; i < num; i++) {
                Integer value = sup.get();
                list.add(value);
            }
            return list;
        }
    

    Function<T, R> 函数型接口 R apply (T t);

     @Test
        public void test3(){
            //去掉空格
            System.out.println(strHandler("    gongj   ",(str) -> str.trim()));
            //转换大小写
            System.out.println(strHandler("gongj", (str) -> str.toUpperCase()));
        }
    
        private String strHandler(String str, Function<String,String> fun){
            return fun.apply(str);
        }
    

    Predicate<T> 断言形接口 boolean test(T t);

    @Test
        public void test4(){
            List<String> list = Arrays.asList("gongj", "yuanj", "xdd");
            System.out.println( filterStr(list,(str) -> str.length() > 3));
        }
        //判断长度>3的字符串
        public List<String> filterStr(List<String> strs, Predicate<String> pre){
            ArrayList<String> arrayList = new ArrayList<>();
            for (String str : strs) {
                if(pre.test(str)){
                    arrayList.add(str);
                }
            }
            return arrayList;
        }
    

    其他类型的函数式接口

    image.png
    https://blog.csdn.net/zxzxzx0119/article/details/82392396
    https://blog.csdn.net/rubulai/article/details/88899892

    相关文章

      网友评论

          本文标题:Java8——Lambda表达式

          本文链接:https://www.haomeiwen.com/subject/wncgpktx.html