A lambda expression is a block of code that you can pass around so it can be executed later.
比如 comparator 或者多线程中的 task,他们仅仅是一小段代码,一个方法足矣,但却因为 Java 的面向对象特征,不得不把一个方法塞进一个类中,并且使用的时候还得实例出来
参数、箭头、内容 () -> {}
。参数就像方法的参数那样,内容就像函数体那样
- 内容如果只有一条语句,可以直接写语句不加
{}
- 如果参数可被推断,则参数列表中的类型可以不指明 (这涉及到原理,可以往后看)
- 如果 buff 拉满了,既可被推断,又只有一个参数,那不加
()
- 如果内容过长,需要自己写
return
。大多数时间,一个表达式返回值是会被推断的
只在 functional interface 中只用 lambda
在 Java 中,lambda 就只在这种情况下使用吧
就算赋值给
Object
也是不允许的
Processing Lambda Expressions
使用 lambda 就是在需要一块过会再执行的代码,以及用在函数接口处
除了 Comparator
之外,还有一些常用的:Predicate
, Runnable
, Callable
Method References
有时候 lambda 的内容就是调用了一个方法,那这种情况可以用 method references 来处理 (也就是说,当发生仅仅就是调用一个方法的时候,那就考虑转化一下,练多了就会了)
和 lambda expression 的本质一样,都不是 Object,仅仅是编译器处理的一个特例,在面对一个 functional interface 的时候,自动升格为一个对应实例
面对重载的选择
因为函数接口里头只有一个方法签名,会根据这个方法签名的样貌选择合适的方法
Runnable task = System. out:: println;
对于这个样的语句,
Runnable
里头是一个() -> void
,所以选择的就是打印空行的方法
有时候一些简单的操作,API 却提供了对应的方法实现,如此脱裤子放屁的行为其实就是为了用在方法引用上,比如 list.removeIf(Objects::isNull);
方法引用和 lambda 大多数时候是一样的
大部份情况,方法引用是 lambda 的一个特例,只有少数情况,比如对 null 指针的错误使用,方法引用会直接报错,而 lambda 毕竟是个函数,要等到真正被调用的时候才会报错
- object::instanceMethod
- Class::instanceMethod
- Class::staticMethod
- super::instanceMethod
- this::instanceMethod
Constructor References
Variable Scope
closure (闭包),一个函数会记住他被创建时,可见变量的状态
这也是为什么我一开始没考虑到这个问题,因为我直接默认就看的被创建时的状态。有时候 lambda 会在所在函数结束后,才被调用运行 (比如定时器)
因此,考虑被创建的状态,也就是不能重名了,并且重名也许会调用到意想不到的东西,比如 this
不可捕获的情况
书中有简单的提到,可以理解为当 lambda 被创建时,那些可见的变量会被记录在自己的字段中,这一听就知道这个字段不能被修改吧
- lambda 内不能修改。毕竟 lambda 生效的时候,函数可能都已经结束了
- lambda 外不能修改,同理