lambda

函数式接口

函数式接口是只定义了一个方法的接口,可以被lambda 匿名函数表达: 函数式接口的抽象方法签名被称为函数描述符

  1. public interface Comparator<T> { ←---- java.util.Comparator
  2. int compare(T o1, T o2);
  3. }
  4. public interface Runnable { ←---- java.lang.Runnable
  5. void run();
  6. }
  7. public interface ActionListener extends EventListener { ←---- java.awt.event.ActionListener
  8. void actionPerformed(ActionEvent e);
  9. }
  10. public interface Callable<V> { ←---- java.util.concurrent.Callable
  11. V call() throws Exception;
  12. }
  13. public interface PrivilegedAction<T> { ←---- java.security.PrivilegedAction
  14. T run();
  15. }

@FunctionalInterface
这个标注用于表示该接口会设计成一个函数式接口,因此对文档来说非常有用。此外,如果你用 @FunctionalInterface 定义了一个接口,而它不是函数式接口的话,编译器将返回一个提示原因的错误。例如,错误消息可能是 “Multiple non-overriding abstract methods found in interface Foo”,表明存在多个抽象方法。请注意,@FunctionalInterface 不是必需的,但对于为此设计的接口而言,使用它是比较好的做法。它就像是 @Override 标注表示方法被重写了。

函数式接口类型

predicate

java.util.function.Predicate 接口定义了一个名叫 test 的抽象方法,它接受泛型 T 对象,并返回一个 boolean

  1. @FunctionalInterface
  2. public interface Predicate<T> {
  3. boolean test(T t);
  4. }
  5. public <T> List<T> filter(List<T> list, Predicate<T> p) {
  6. List<T> results = new ArrayList<>();
  7. for(T t: list) {
  8. if(p.test(t)) {
  9. results.add(t);
  10. }
  11. }
  12. return results;
  13. }
  14. Predicate<String> nonEmptyStringPredicate = (String s) -> !s.isEmpty();
  15. List<String> nonEmpty = filter(listOfStrings, nonEmptyStringPredicate);

Consumer

java.util.function.Consumer 接口定义了一个名叫 accept 的抽象方法,它接受泛型 T 的对象,没有返回( void )。你如果需要访问类型 T 的对象,并对其执行某些操作,就可以使用这个接口。

  1. @FunctionalInterface
  2. public interface Consumer<T>{
  3. void accept(T t);
  4. }
  5. public <T> void forEach(List<T> list, Consumer<T> c){
  6. for(T i: list){
  7. c.accept(i);
  8. }
  9. }
  10. forEach(
  11. Arrays.asList(1,2,3,4,5),
  12. (Integer i) -> System.out.println(i) ←---- Lambda Consumeraccept方法的实现
  13. );

Function

java.util.function.Function 接口定义了一个叫作 apply 的抽象方法,它接受泛型 T 的对象,并返回一个泛型 R 的对象。如果你需要定义一个 Lambda ,将输入对象的信息映射到输出,就可以使用这个接口

  1. @FunctionalInterface
  2. public interface Function<T, R> {
  3. R apply(T t);
  4. }
  5. public <T, R> List<R> map(List<T> list, Function<T, R> f) {
  6. List<R> result = new ArrayList<>();
  7. for(T t: list) {
  8. result.add(f.apply(t));
  9. }
  10. return result;
  11. }
  12. // [7, 2, 6]
  13. List<Integer> l = map(
  14. Arrays.asList(" Lambda s", "in", "action"),
  15. (String s) -> s.length() ←---- Lambda Function接口的apply方法的实现
  16. );

注: Java 类型要么是引用类型(比如 Byte、Integer、Object、 List ),要么是基本类型(比如 int 、double、byte、char)。但是泛型(比如 Consumer 中的 T )只能绑定到引用类型。这是由泛型内部的实现方式造成的 [①]

常用的函数式接口

截屏2022-06-11 下午6.44.33.png
截屏2022-06-11 下午10.24.13.png

类型检查

java 会自动检查lambda 的上下文从而判断lambda 应该继承哪一个函数式接口

类型判断

  1. Comparator<Apple> c =
  2. (Apple a1, Apple a2) -> a1.getWeight().compareTo(a2.getWeight()); ←---- 没有类型推断
  3. Comparator<Apple> c =
  4. (a1, a2) -> a1.getWeight().compareTo(a2.getWeight()); ←---- 有类型推断