通常来说,将带有单个抽象方法的接口作为函数类型,他们的实例称为函数对象,表示函数或者要采取的动作,之前创建的方式主要通过匿名类。java8中有些接口的只有单个抽象方法,这些接口被称为函数接口,java8中允许利用Lambda表达式创建这些接口的实例,例如下面的代码:
Collections.sort(words, (s1, s2)->Integer.compare(s1.length(), s2.length());
上面的代码中省去了接口的参数编译器可以通过上下文的语义推断出Lambda的,所以通常不用添加参数的类型,在使用lambda表达式的时候需要注意,如果方法使用泛型,一定要带上对应的类型,不要使用原生泛型,否则编译器无法进行类型推导,必须在Lambda中手工指定类型。例如上述代码片段中的变量words声明为原生类型List,而不是泛型化参数List
首先写出之前的版本:
public enum Operation {
PLUS("+") {
public double apply(double x, double y) { return x + y; }
},
MINUS("-") {
public double apply(double x, double y) { return x - y; }
},
TIMES("*") {
public double apply(double x, double y) { return x * y; }
},
DIVIDE("/") {
public double apply(double x, double y) { return x / y; }
};
private final String symbol;
Operation(String symbol) { this.symbol = symbol; }
@Override public String toString() { return symbol; }
public abstract double apply(double x, double y);
}
Lambda表达式也可以在枚举类型中使用
import item38.Operation;
import java.util.function.DoubleBinaryOperator;
public enum OperationLambda {
PLUS("+", (x, y)->x + y),
MINUS("-", (x, y)-> x - y),
TIMES("*", (x, y)->x * y),
DIVIDE("/", (x, y)-> x / y);
private final String symbol;
private final DoubleBinaryOperator op;
OperationLambda(String symbol, DoubleBinaryOperator op){
this.symbol = symbol;
this.op = op;
}
@Override
public String toString(){
return symbol;
}
public double apply(double x, double y){
return op.applyAsDouble(x, y);
}
}
用lambda表达式实现这个Operation非常简洁。
lambda表达式也有一些缺点:
- Lambda没有名称和文档,最好lambda表达式应在1~3行之间,超出这个限制不应该使用Lambda。
- Lambda接口只能有一个抽象函数,如果有多个抽象函数的抽象类就不能使用Lambda了
- Lambda中this指针指向的是外围类实例,而匿名类是指向匿名类本身的。
- Lambda无法可靠地序列化和反序列化。
总结:从java8开始,Lambda表达式就成了小函数对象的最佳方式,不要使用匿名类除非创建的接口是非函数接口类型的实例。