创建并使用 Lambda 表达式
简化代码
重复或复制粘贴的代码更改的灵活性不强,容易出错。
面向对象方法
Java 是面向对象的,使用一种流行的设计模式——策略来解决这个问题,封装了变化的行为(算法) ,并使所有这些行为可以互换
Java推荐方法是使用一个接口,这样我们就可以为每个算法创建实现
举例
假设我们有一个程序有一个汽车列表,我们需要按照不同条件搜索所有的紧凑型汽车
- 传统方法
List<Car> findCompactCars(List<Car> cars) {
List<Car> compactCars = new ArrayList<Car>();
for(Car car : cars) {
if(car.getType().equals(CarTypes.COMPACT)) {
compactCars.add(car);
}
}
return compactCars;
}
- 策略模式
1.编写一个接口,可以包含不同的搜索条件
interface Searchable {
boolean test(Car car);
}
2.将不同的代码放入该接口的实现中
class CompactCarSearch implements Searchable {
public boolean test(Car car) {
return car.getType().equals(CarTypes.COMPACT);
}
}
class TwentyKCarSearch implements Searchable {
public boolean test(Car car) {
return car.getCostUSD() > 20000;
}
}
3.可以使实际搜索的方法更加通用
List<Car> findCars(List<Car> cars, Searchable s) {
List<Car> searchedCars = new ArrayList<Car>();
for(Car car : cars) {
if(s.test(car)) {
searchedCars.add(car);
}
}
return searchedCars;
}
4.以这种方式调用函数,我们没有重复的代码了
List<Car> compactCars = findCars(cars, new CompactCarSearch());
List<Car> twentyKCars = findCars(cars, new TwentyKCarSearch());
- 再次简化
不再使用两个方法,而是使用两个类和一个接口,把这些实现转换成匿名类
List<Car> compactCars = findCars(cars,new Searchable() {
public boolean test(Car car) {
return car.getType().equals(CarTypes.COMPACT);
}
});
- 继续简化
将类赋给变量
Searchable compactCarSearch = new Searchable() {
public boolean test(Car car) {
return car.getType().equals(CarTypes.COMPACT);
}
};
List<Car> compactCars = findCars(cars, compactCarSearch);
- 如果可以吧条件直接传递给方法入参
// Don't even try, it won't work
List<Car> compactCars = findCars(cars,
car.getType().equals(CarTypes.COMPACT));
Java8新类型值传递
- Java中方法入参传递可以为基本类型的值传递和引用传递
- 如果我们想要将某段代码传递给一个方法,我们必须将它封装在一个对象中(如前面的例子所示)。可以通过使用 lambda 表达式直接传递这段代码
函数式接口
- 函数接口是任何只有一个抽象方法的接口
以缺省方法为例。因为缺省方法有一个实现,所以它们不是抽象的。所以像下面这样的接口被认为是函数式接口
interface A {
default int defaultMethod() {
return 0;
}
void method();
}
interface B {
default int defaultMethod() {
return 0;
}
default int anotherDefaultMethod() {
return 0;
}
void method();
}
- 如果一个接口用 java.lang.Object 的方法之一的签名声明了一个抽象方法。对象时,它不计入函数接口方法计数,因为该接口的任何实现都将具有该方法的实现(因为所有类都是从 java.lang.Object 扩展而来的)
下面的接口认为函数式接口
interface A {
boolean equals(Object o);
int hashCode();
String toString();
void method();
}
- java8还引入了@functionalinterface 注释,当您所注释的接口不是一个有效的函数接口时,该注释会生成一个编译时错误。
// This won't compile
@FunctionalInterface interface A {
void m(int i);
void m(long l);
}
- 在定义中只有一个方法声明的 Java 接口现在被注释为函数接口,@FunctionalInterface这个注释只是为了帮助您; 拥有它并不会使接口具有功能性
总结
- 函数接口是任何一个接口,它只有一个抽象方法。
- 由于默认方法具有实现,所以它们不是抽象的,因此函数接口可以有任意数量的实现。
- 如果接口声明了一个抽象方法,并且具有java.lang.Object方法之一的签名,那么它就不会计算函数接口方法计数。
- 当函数接口继承与另一个方法等价但不相同时,该接口有效。
- 空接口不被视为功能接口。
- 即使省略@functioninterface注释,功能接口也是有效的。
- 函数接口是lambda表达式的基础。
Comments | 0 条评论