创建并使用 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);

image.png

  • 如果可以吧条件直接传递给方法入参
// 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);
}

image.png

  • 在定义中只有一个方法声明的 Java 接口现在被注释为函数接口,@FunctionalInterface这个注释只是为了帮助您; 拥有它并不会使接口具有功能性
    image.png

总结

  • 函数接口是任何一个接口,它只有一个抽象方法。
  • 由于默认方法具有实现,所以它们不是抽象的,因此函数接口可以有任意数量的实现。
  • 如果接口声明了一个抽象方法,并且具有java.lang.Object方法之一的签名,那么它就不会计算函数接口方法计数。
  • 当函数接口继承与另一个方法等价但不相同时,该接口有效。
  • 空接口不被视为功能接口。
  • 即使省略@functioninterface注释,功能接口也是有效的。
  • 函数接口是lambda表达式的基础。

这个家伙很懒,啥也没有留下😋