个人理解

Lambda表达式是一种简洁高效的实现匿名内部类的一种方式.可以使代码变得更清晰、更灵活.大大增加代码可读性.

下面进行匿名内部类和Lambda表达式的比较,效果一目了然.

在java8之前使用匿名内部类是这样的

public void Test3() {
    List<Student> list = fitterStudent(students, new MyPredicate<Student>() {
        @Override
        public boolean judge(Student stu) {
            return stu.getSex().equals("男");
        }
    });
}

可以看到真正有用的只有return stu.getSex().equals("男");这一行代码,但是因为格式,确不得不把其他的好多行都写出来,毫无疑问这样的话,代码的可读性会大大降低.

下面来看一下使用Lambda表达式的效果

public void Test2() {
        List<Student> list = fitterStudent(students, (stu) -> stu.getSex().equals("女"));
    } 

看到效果了吧,原来的6=行代码,现在只需要1行.是不是很nb…

Lambda表达式的基本语法

java8中引入一个新的操作符”->”,称为箭头操作符或者为lambda操作符

箭头操作符将拉lambda表达式拆分成两个部分
左侧:参数列表,所实现接口抽象方法的参数列表(函数式接口)
右侧:所需执行的功能,称为lambda体
lambda表达式需要"函数式接口"(接口中只有一个抽象方法)支持
可以使用注解@FunctionalInterface 帮忙检查是否是函数式接口

  • 语法格式一:无参数,无返回值
  •     /**
         * @Description 创建一个线程输出语句
         * @Author xw
         * @Date 10:20 2020/2/15
         * @Param []
         * @return void
         **/
        @Test
        public void test1() {
            Runnable r0 = new Runnable() {
                @Override
                public void run() {
                    System.out.println("匿名内部类的方式:Hello Lambda!");
                }
            };
            r0.run();
            //语法格式一:无参数,无返回值
            Runnable r1 = () -> System.out.println("Lambda表达式的方法:Hello Lambda!");
            r1.run();
        }

  • 语法格式二: 有一个参数,无返回值
  •     /**
         * @Description 参数是啥输出啥 
         * @Author xw
         * @Date 10:23 2020/2/15
         * @Param []
         * @return void
         **/
        @Test
        public void test2(){
            //声明一个消费型接口(有一个参数,但是无返回值)调用accept方法,传入一个参数
            Consumer<String> con = (x) -> System.out.println(x);
            //语法格式二: 有一个参数,无返回值
            con.accept("Hello Lambda!");
        }

  • 语法格式三: 若只有一个参数则参数的小括号可以不写,(推荐还是写上)
  • Consumer<String> con = (x) -> System.out.println(x);
    上面的语句等价于
    Consumer<String> con = x -> System.out.println(x);

  • 语法格式四: 有多个参数,并且lambda体中有多个语句,并且有返回值
  •     /**
         * @Description 比较两个整数
         * @Author xw
         * @Date 10:38 2020/2/15
         * @Param []
         * @return void
         **/
        @Test
        public void test4(){
            //用于比较的接口Comparable,提供了一个比较的方法
            Comparator<Integer> com = (x, y) -> {
                //有多个参数,并且lambda体中有多个语句,必须使用大括号,并且有返回值
                System.out.println("x = " + x);
                System.out.println("y = " + y);
                //Integer类就是Comparator的实现类
                return Integer.compare(x,y);
            };
            System.out.println(com.compare(1, 520));
        }

  • 语法格式五: 有多个参数并且有返回值,只有一条语句(return 和大括号都可以省略)
  • Comparator<Integer> com = (x, y) -> {
        return Integer.compare(x,y);
    };
    上面的写法等价于
    Comparator<Integer> com = (x,y) ->  Integer.compare(x, y);

  • 语法格式六: lambda表达式的参数列表数据类型可以不写,jvm自动推断(推荐不写)
  • Comparator<Integer> com = (Integer x,Integer y) ->  Integer.compare(x, y);
    等价于
    Comparator<Integer> com = (x,y) ->  Integer.compare(x, y);

    总结:

    • 左右遇一括号省‘->’左边参数列表中若只有一个参数,那么小括号可以省略,’->’右边如果只有一条语句,那么大括号可以省略
    • 左侧推断类型省‘->’左边参数的参数类型可以省略
    • 右侧一条return省如果Lambda表达式具有返回值,并且只有一条语句,那么可以省略’return’关键字

    Lambda表达式既然这么好用,那么是不是什么时候都可以应用呢?

    不是的,Lambda表达式必须要有函数式接口的支持,即接口中必须只有一个抽象方法

    那么问题来了,难道每次使用Lambda表达式都需要自己写一个函数式接口?

    当然不是了,java8现在内置了四大基本的函数式接口,而且还有好多函数式接口,所以没有想象的那么麻烦,下面就开始介绍java8内置的四大函数式接口

    1.Consumer 消费型接口(有一个参数,但是无返回值) void accept(T t);

    @Test
    public void test7() {
        happy(20000, (money) -> System.out.println("我今天花了"+money+"元"));
    }
    /**
     * @Description happy的作用就是想参数传递给 Consumer
     * @Author xw
     * @Date 10:54 2020/2/15
     * @Param [money, consumer]
     * @return void
     **/
    public void happy(double money,Consumer<Double> consumer) {
        consumer.accept(money);
    }

    不写happy方法可以直接这样写

        Consumer<Double> consumer = (x) ->{
            System.out.println("我今天花了"+x+"元");
        };
        consumer.accept(2000d);

    2.Supplier 供给型接口(无参数,但是有返回值) T get();

    @Test
    public void test8() {
        //获得5个0-100的随机数
        List<Integer> numList = getRandomNum(5, () -> (int)(Math.random()*100));
        numList.forEach(System.out::println);
    }
    
    /**
     * @Description 获得num个sup.get()得到的结果
     * @Author xw
     * @Date 11:05 2020/2/15
     * @Param [num, sup]
     * @return java.util.List<java.lang.Integer>
     **/
    public List<Integer> getRandomNum(int num, Supplier<Integer> sup){
        List<Integer> list = new ArrayList<>();
        for (int i = 0; i < num; i++) {
            list.add(sup.get());
        }
        return list;
    }

    3.Function 函数型接口(有一个参数,有返回值)R apply(T t);

    @Test
    public void test9() {
        String result = strHandler("hello ", (str) -> {
            return str+= "Lambda";
        });
        System.out.println(result);
    }
    
    /**
     * @Description  将str传递给函数型接口
     * @Author xw
     * @Date 11:10 2020/2/15
     * @Param [str 前缀, fun]
     * @return java.lang.String
     **/
    public String strHandler(String str, Function<String, String> fun) {
        return fun.apply(str);
    }

    4.Predicate 断言型接口(有一个参数,返回值为波尔类型) boolean test(T t);

    @Test
    public void Test10() {
        List<String> list = Arrays.asList("Hello","world","my","name","is","moti");
        List<String> result = filterStr(list, (str) -> {
            //判断字符串是否含有o
            return str.contains("o");
        });
        result.forEach(System.out::println);
    }
    
    /**
     * @Description 根据 断言型接口提供的条件,筛选集合
     * @Author xw
     * @Date 11:14 2020/2/15
     * @Param [list, pre]
     * @return java.util.List<java.lang.String>
     **/
    public List<String> filterStr(List<String> list, Predicate<String> pre){
        List<String> resultList = new ArrayList<>();
        for (String string : list) {
            if(pre.test(string)) {
                resultList.add(string);
            }
        }
        return resultList;
    }

    java8之后的接口可以这么写

    @FunctionalInterface
    interface myInterface{
        //只有一个没实现的方法,这个接口就叫做函数式接口
        void fun1();
        //默认实现
        default int fun2(int a,int b){
            return a+b;
        }
        //静态方法
        static int fun3(int a,int b){
            return a*b;
        }
    } 

    Java8 还有好多关于以上接口的子接口,有兴趣的可以自己去查查

    最后修改日期:2020-07-13

    作者

    留言

    撰写回覆或留言

    发布留言必须填写的电子邮件地址不会公开。