文章目录
1. lambda表达式
1.1 概述
简单说来,lambda表达式实际上可以理解为一段代码,一段定义了但是却可以按需执行的代码。
1.2 可能好的方面
第一、lambda表达式的功能特性可以帮助java语言做到函数式编程,便于抽象和重构代码。
第二、lambda表达式可以被定义为变量在代码中像传递普通变量一样进行传递,按照实际需要进行一次或者多次执行。
第三、与函数式接口联合使用的时候,使用lambda表达式可以简化代码,代码写起来更加简洁。
1.3 可能要注意
第一、lambda表达式不同于一般的代码形式,一般的代码是写了后,如果代码走到了,里面的代码就会执行,而lambda表达式中的逻辑要被执行的话,还需要额外的一个调用动作。
第二、使用lambda表达式的时候,要注意在lambda表达式中访问不同作用域下的变量的值的安全性,同时异常的处理以及日志记录等要注意。
第三、使用lambda表达式因为简洁,所以有的时候使用过多会带来高度的抽象,可能会导致代码反而不易理解。比如 lambda表达式的参数和返回值的类型都是可以自动推导出来的。当然入参可以加注解让代码清晰点。但是还有各种泛型场景,这样看起来就不是那么明确清晰。
2. 函数式接口
2.1 概述
满足以下2个条件就可以认为是函数式接口:
条件1:是一个接口(interface);
条件2:该接口中抽象方法只有一个。
2.2 可能好的方面
第一、函数式接口的对象,可以通过lambda表达式进行创建,而不用复杂的实现接口的类或者冗长的匿名类。
第二、jdk中自带的函数式接口丰富在java.util.function下很多,使用很方便。
第三、通过lambda表达式和函数式接口的综合使用,便于针对代码具备一定规律行为的抽象,提升代码的层次感。
2.3 可能要注意
第一、如果一个interface中有好几个方法,它有可能是函数式接口,只要它的方法中只有一个未实现的方法即可。例如:
package lambda;
public interface MultiMethodFunctionInterface {
String getDisplayName();
public default String getName() {
return "---";
}
public static void doSth()
{
System.out.println("I am doing something.");
}
}
第二、函数式接口为了明确,我们可以在自定义的函数式接口定义处加上对应的@functionalinterface注解
第三、函数式接口中的抽象方法的参数,尽量控制在3个以内,参数太多的使用起来容易引起理解的复杂性。如果参数就是比较多的话,建议使用类似POJO类的形式把参数进行合理的类定义,以此减少参数的个数。
3. lambda表达式调用形式
3.1 方法引用或构造方法引用
2种形式:
形式1:e -> String.valueOf(e);
形式2: String::valueOf
其中双冒号::的操作符会有几种常见形式:
对象::对象的示例方法
类::类的静态方法
类::new
this::方法
super::方法
3.2 lambda表达式中作用域的问题
lambda表达式是一段代码,这段代码会包括3个部分,
第一,自己独立的代码,
第二,方法的参数,
第三,该lambda表达式所能访问的自由的变量。
关于最后一点,要特别重视,容易在多并发的场景引起问题。因此有个重要的的约束,虽然编译器会有一定的控制,但是注意不能完全检查的出来的,lambda表达式中被引用的自由的变量的值在lambda表达式中是不能被修改的,或者说编码者应该确保被引用的变量可以认为是自动带了final的修饰,然后即使这样还是有些很隐晦的编译器检查不出来,比如List的变量,在lambda表达式中改它里面的元素也是多线程不安全的。
因此,对于lambda表达式在多线程的场景下,为了线程安全,尽量避免在lambda表达式中调用类的成员变量,类的静态变量等。