对Lambda的理解

一、前言

从毕业起,接触lambda也有了4个多月了,期间也写过不少lambda表达式,今天就来梳理一下我对lambda理解的过程。


二、我不要你觉得,我要我觉得

网上讲的lambda概念太过生涩,不易理解,下面我谈谈自己的想法。

java中最简单的语法,莫过于将一个值赋给某个变量,例如

int a=1;

而java8中的lambda,就是将一段代码赋给某个变量,例如

ablock=public void dosomethings(String s){
            System.out.println(s);
       }

但是这样的写法略显笨拙,我们可以一步一步精简代码。

这样的🦁就是一个lambda表达式,可以使得代码变得很简洁。

lambda表达式,即(可省略类型,也可省略参数的参数列表)->{ 代码块 }


三、我全都要

我们来看更多的lambda例子

(1)强就强在lambda能替换匿名内部类

        Runnable r = new Runnable() {
            @Override
            public void run() {
                System.out.println("thread run");
            }
        }

        Runnable r = () -> {
            System.out.println("thread run");
        };

从这里可以看出,lambda是有类型的,它的类型为等号左边接口的类型。

当lambda表达式内部的语句只有一行时,可以省略{},但不建议这样做。

编译器之所以能大胆推断出这条语句System.out.println("thread run")实际上是run方法的内部语句,是因为Runnable接口只有run这一个抽象方法。我们注意到,Runnable接口被@FunctionalInterface注解修饰,该注解限制该接口只能有一个抽象方法,该接口就会被赋予新的名词,函数接口。

在工作中,我们也可以给某一个接口添加@FunctionalInterface注解,代表该接口为函数接口,是为lambda所服务的。如果再添加一个抽象方法,就会和此注解冲突,从而编译失败。

(2)哪里有list,哪里就有lambda

        //遍历输出集合
        List<Integer> list=Arrays.asList(1,2,3,4,5);
        list.forEach(x->System.out.print(x));
        //当然也可使用方法引用
        list.forEach(System.out::print);

        //取出所有大于1的元素,并形成新的集合
        List<Integer> collect = list.stream().filter(x -> x > 1).collect(Collectors.toList());
        
        //获取学生的所有年龄集合
        List<Integer> ageList=Arrays.asList(new Student("tom",20),new Student("jack",22))
                .stream().map(Student::getAge).collect(Collectors.toList());

forEach:对集合的迭代。但在大多数情况下,遍历效率:迭代器与for-each循环>带有索引的for循环>lambda中的forEach。但是lambda可以在多个CPU核上同时处理集合,在大数据量并行计算下,lambda的效率就体现出来了。

stream():将集合转化为流,这里的流不是io流。只有转化为流后,才可以进行接下来的map、filter、collect操作等,但流只能被消费一次。

map():将一种形式的流转化为另一种形式的流,这里常常配合方法引用,例如将List<Student>形式的流转化为List<Integer>形式的流。

collect():按照某种方法将流形成具体的集合。

lambda对集合的操作还有很多,需要大家自己去探索。


四、Stream常用的操作