对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对集合的操作还有很多,需要大家自己去探索。