Lambda表达式

行为参数化传递代码

  1. 我们有一个Apple类,他有两个属性重量(weight),颜色(color)。现在希望我们获取一组苹果中颜色为绿色的方法我们一般是这么写的

public static List<Apple> filterGreenApples(List<Apple> inventory){
   List<Apple> result = new ArrayList<>();
   for(Apple apple: inventory){
       if("green".equals(apple.getColor())){
           result.add(apple);
      }
  }
   return result;
}
  1. 现在我们要改变需求,想获得红色的苹果。最简单的方法是更改if语句的条件,但如果筛选其他颜色的这种方法就无法应对。我们可以增加一个颜色参数。

public static List<Apple> filterApplesByColor(List<Apple> inventory, String color){
   List<Apple> result = new ArrayList<>();
   for(Apple apple: inventory){
       if(apple.getColor().equals(color)){
           result.add(apple);
      }
  }
   return result;
}  
  1. 那如果现在要根据重量筛选苹果呢,一般要么重载方法,要么修改原来的方法

public static List<Apple> filterApplesByWeight(List<Apple> inventory, int weight){
  List<Apple> result = new ArrayList<>();
  for(Apple apple: inventory){
     if(apple.getWeight() > weight){
        result.add(apple);
    }
  }
  return result;
}
  1. 不论那一种都不能很好的应对变化的需求。可以利用行文参数化(面向接口编程)来应对更多的变化.ApplePredicate相当于一个标准,任何if语句内的行为判断都放在该接口的实现类中,利用多态进行方法调用。

interface ApplePredicate{
  public boolean test(Apple a);
}

static class AppleWeightPredicate implements ApplePredicate{
  public boolean test(Apple apple){
     return apple.getWeight() > 150;
  }
}
static class AppleColorPredicate implements ApplePredicate{
  public boolean test(Apple apple){
     return "green".equals(apple.getColor());
  }
}
public static List<Apple> filter(List<Apple> inventory, ApplePredicate p){
  List<Apple> result = new ArrayList<>();
  for(Apple apple : inventory){
     if(p.test(apple)){
        result.add(apple);
    }
  }
  return result;
}  
  1. 这种方式有一个缺点,当你要扩充功能的时候就不得不为他编写实现类,当你有很多可能存在功能就要实现多个比较麻烦可以使用匿名类。随用随建

List<Apple> redApples2 = filter(inventory, new ApplePredicate() {
  public boolean test(Apple a){
     return a.getColor().equals("red");
  }
});
  1. 尝试使用lambda重写

List<Apple> redApples3 = filter(inventory, a -> a.getColor().equals("red"));

lambda表达式

什么是lambda表达式

lambda表达式实际上是一个语法糖,可以理解为一个匿名函数。由编译器帮你翻译成常规代码

构成

(Appler a) ->  a.getColor().equals("red")
  • 参数列表: (Apper a)

  • 箭头: ->

  • lambda主体 :{a.getColor().equals("red")}

基本语法

  • (parameters)-> expression/statement

  • (parameters)->{statements;}

  • 参数

  • parameters: 参数, 可以指定或不指定参数类型, 当只有一个参数时可以不要圆括号

  • expression:函数返回值,直接返回该值,无需大括号

  • statements:函数体,当使用大括号时需要指明表达式返回的值

应用范围

参数为函数式接口的方法上都可以使用lambda表达式。(函数式接口:只定义了一个抽象方法的接口)

常见的函数式接口

  1. Predicate(谓语):T -> boolean

@FunctionalInterface
public interface Predicate<T> {
   boolean test(T t);
}

重点:因为泛型只能接受引用类型,所以当一个基础类型传递给函数接口变量式会进行自动装箱,这种自动装箱是要消耗更多的内存。因此提供了针对输入参数类型的函数式接口:IntConsumer,DoublePreDicate

  1. Consumer(消费者): T -> void

@FunctionalInterface
public interface Consumer<T> {
   void accept(T t);
}
  1. Function<T,R>: T ->R

@FunctionalInterface
public interface Function<T, R> {
   R apply(T t);
}
  1. Supplier(提供者): ()->T

@FunctionalInterface
public interface Supplier<T> {
   T get();
}
  1. UnaryOperator:T->T

@FunctionalInterface
public interface UnaryOperator<T> extends Function<T, T> {
   static <T> UnaryOperator<T> identity() {
       return t -> t;
  }
}
  1. BinaryOperator:(T,T) ->T

@FunctionalInterface
public interface BinaryOperator<T> extends BiFunction<T,T,T> {
   public static <T> BinaryOperator<T> minBy(Comparator<? super T> comparator) {
       Objects.requireNonNull(comparator);
       return (a, b) -> comparator.compare(a, b) <= 0 ? a : b;
  }
  1. BiConsumer<T,U>: (T,U)->void,BiPredicate<L,R>:(L,R)->boolean,BiFunction<T,U,R>:(T,U)->R

方法引用

  1. 指向静态方法的引用

    ()->Intger.parseInt();
    (Integer::parseInt)
  2. 指向任意对象实例的方法引用(对象本身是参数)

    (String s)->s.length();
    (String::length)
  3. 指向现有对象实例的方法引用(调用外部本身已经存在的对象的方法)

    Experss exp;
    (args)->exp.instanceMethod(args);
    (exp::instanceMethod)

构造器引用

Supplier<Apple> supplier = () -> new Apple();//空参构造
Supplier<Apple> supplier = Apple::new;

Function<Integer, BigDecimal> function = x -> new BigDecimal(x);//1参构造
Function<Integer, BigDecimal> function = BigDecimal::new;

//2参构造可以用BiFuncation<T,U,R>,在更多可以自己创建函数接口

复合

  1. 比较器复合(comparator)

    • reversed();获取的结果逆序

    • thenComparing():设置第二个比较条件

List<User> users = Arrays.asList(new User(1, 2), new User(2, 3), new User(2, 1), new User(3, 3));
users.sort(Comparator.comparing(User::getAge).thenComparing(User::getHeight).reversed());
System.out.println(users);
  1. 谓词复合(predicate)

    • and

      • Predicate<List<Apple>> predicate =List::isEmpty;
        Predicate<List<Apple>> and = predicate.and(list -> list.size() != 0);//添加一个新的比较条件,同时满足才为true
    • or 与上述类似,二者满足其一即可

    • negate

      • Predicate<List<Apple>> predicate =List::isEmpty; //判断list是否为空
        Predicate<List<Apple>> negate = predicate.negate();//结果取反

         

    • 不同于其他的比较运算,谓词复合的判断是根据顺序来的,也就是说 A.or(B).and(C) 执行顺序为(A or B )and C

  2. 函数复合(funtion)

    • andthen():f1.andthen(f2),先执行f1后执行f2

    • compose():f1.compose(f2),先执行f2后执行f1

posted @ 2021-10-02 17:47  blackRx  阅读(112)  评论(0编辑  收藏  举报
© 2021 GitHub, Inc.