函数式接口

函数式接口

Java 原本作为纯粹的面向对象的语言,需要对 Lambda 表达式特性进行支持,其实是基于了一种特殊的函数式接口。换言之,()->{} 这样的语法本质上还是继承并且实现了一个接口。FI 的定义其实很简单:任何接口,如果只包含唯一一个抽象方法,那么它就是一个 FI。为了让编译器帮助我们确保一个接口满足 FI 的要求(也就是说有且仅有一个抽象方法),Java8 提供了 @FunctionalInterface 注解。举个简单的例子,Runnable 接口就是一个 FI,下面是它的源代码:

@FunctionalInterface
public interface Runnable {
  public abstract void run();
}

我们不能使用以下类型的方法来声明一个功能接口:默认方法、静态方法、继承自 Object 类的方法。一个函数式接口可以重新声明 Object 类中的方法。而这个方法不算是抽象方法。因此我们可以声明另一个 lambda 表达式使用的方法。

package java.util;
@FunctionalInterface

public interface  Comparator<T> {
   // An abstract method  declared in the functional interface
   int compare(T  o1,   T  o2);

   // Re-declaration of the equals() method in the Object class
   boolean equals(Object  obj);

   ...
}

Builtin Functional Interface | 函数式接口

Consumer

Consumer 接口表示一个接受单一输入参数并不返回结果的操作。

Consumer<String> c = (x) -> System.out.println(x.toLowerCase());
c.accept("Java2s.com");

public class Main {
    public static void main(String[] args) {
      int x = 99;

      Consumer<Integer> myConsumer = (y) ->
      {
          System.out.println("x = " + x); // Statement A
          System.out.println("y = " + y);
      };

      myConsumer.accept(x);
    }
}

public class Main {
   public static void main(String[] args) {
      List<Student> students = Arrays.asList(
            new Student("John", 3),
            new Student("Mark", 4)
      );

      acceptAllEmployee(students, e -> System.out.println(e.name));
      acceptAllEmployee(students, e -> {
         e.gpa *= 1.5;
      });
      acceptAllEmployee(students, e -> System.out.println(e.name + ": " + e.gpa));
   }

   public static void acceptAllEmployee(List<Student> student, Consumer<Student> printer) {
      for (Student e : student) {
         printer.accept(e);
      }
   }

}
class Student {
  public String name;
  public double gpa;

  Student(String name, double g) {
    this.name = name;
    this.gpa = g;
  }
}

DoubleConsumer 功能接口表示一个接受单个双值参数并不返回结果的操作。这是 Consumer 对 double 的原始类型特化。

DoubleConsumer d = (x) -> System.out.println(x*x);
d.accept(0.23);

BiConsumer 表示一个接受两个输入参数并不返回结果的操作。

BiConsumer<String, String> biConsumer = (x, y) -> {
  System.out.println(x);
  System.out.println(y);
};

biConsumer.accept("java2s.com", " tutorials");

BiConsumer andThen 返回一个组成的 BiConsumer,它依次执行这个操作,然后是 after 操作。

biConsumer.andThen(biConsumer).accept("java2s.com", " tutorial");

Comparators

Comparator 接口在早期的 Java 版本中非常著名。Java 8 为这个接口添加了不同的默认方法。

Comparator<Person> comparator = (p1, p2) -> p1.firstName.compareTo(p2.firstName);

Person p1 = new Person("John", "Doe");
Person p2 = new Person("Alice", "Wonderland");

comparator.compare(p1, p2);             // > 0
comparator.reversed().compare(p1, p2);  // < 0

Function

BiFunction 表示一个接受两个参数并产生一个结果的函数。这是 Function 的二元特化。

BiFunction<String, String,String> bi = (x, y) -> {
      return x + y;
    };

System.out.println(bi.apply("java2s.com", " tutorial"));

// BiFunction 作为参数
public class Main {
  public static void main(String[] args) {
    Calculator calculator = new Calculator();
    String result = calculator.calc((a, b) -> ": " + (a * b),3,  5);

    System.out.println(result);

  }
}

class Calculator {
  public String calc(BiFunction<Integer, Integer, String> bi, Integer i1, Integer i2) {
      return bi.apply(i1, i2);
  }
}

// 传入 Stream 中
List<Integer> _numbers = Arrays.asList(1, 2, 3, 4, 5, 6, 7, 8, 9, 10);

Function<Integer, Integer> lambda = value -> value * 2;
List<Integer> doubled = _numbers.stream()
        .map(lambda)
        .collect(java.util.stream.Collectors.toList());

System.out.println(doubled);

// 传入方法引用
public class Main {

   public static void main(String[] args) {
     List<Double> numbers = Arrays.asList(1D, 25D, 100D);
     System.out.println(transformNumbers(numbers, Math::sqrt));
   }

   private static List<String> transformNumbers(List<Double> numbers, Function<Double, Double> fx) {
     List<String> appliedNumbers = new ArrayList<>();
     for (Double n : numbers) {
        appliedNumbers.add(String.valueOf(fx.apply(n)));
     }
     return appliedNumbers;
  }
}

DoubleFunction 表示一个接受双值参数并产生结果的函数。这是 Function 的双耗基元特化。

DoubleFunction<String> df = (d) -> d +" is now a string";
System.out.println(df.apply(0.5));

Predicate

Predicate 是一个布尔类型的函数,该函数只有一个输入参数。Predicate 接口包含了多种默认方法,用于处理复杂的逻辑动词(and, or,negate)

Predicate<String> predicate = (s) -> s.length() > 0;

predicate.test("foo");              // true
predicate.negate().test("foo");     // false

Predicate<Boolean> nonNull = Objects::nonNull;
Predicate<Boolean> isNull = Objects::isNull;

Predicate<String> isEmpty = String::isEmpty;
Predicate<String> isNotEmpty = isEmpty.negate();

BiPredicate 表示一个谓词,它是两个参数的布尔值函数。

BiPredicate<Integer, Integer> bi = (x, y) -> x > y;
System.out.println(bi.test(2, 3));

public class Main {

  public static void main(String[] args) {
    boolean result = compare((a, b) -> a / 2 == b, 10, 5);

    System.out.println("Compare result: " + result);

  }
  public static boolean compare(BiPredicate<Integer, Integer> bi, Integer i1, Integer i2) {
    return bi.test(i1, i2);
  }

}

Operator

BinaryOperator 表示对两个相同类型的操作数的操作,产生相同类型的结果。

BinaryOperator<Integer> adder = (n1, n2) -> n1 + n2;
System.out.println(adder.apply(3, 4));

DoubleBinaryOperator 表示对两个双值操作数的操作,并产生一个双值的结果。

DoubleBinaryOperator d = (x,y) -> x*y;
System.out.println(d.applyAsDouble(0.23, 0.45));

Supplier

Supplier 代表着结果的提供者。

Supplier<String> i  = ()-> "java2s.com";
System.out.println(i.get());

下面的代码显示了如何传递 Supplier 作为参数。

public class Main {
    public static SunPower produce(Supplier<SunPower> supp) {
        return supp.get();
    }
    public static void main(String[] args) {
        SunPower power = new SunPower();

        SunPower p1 = produce(() -> power);
        SunPower p2 = produce(() -> power);

        System.out.println("Check the same object? " + Objects.equals(p1, p2));
    }
}

class SunPower {

  public SunPower() {
      System.out.println("Sun Power initialized..");
  }
}

下面的代码显示了如何使用构造函数作为 Supplier 的方法引用。

public class Main {
  public static void main(String[] args) {
    System.out.println(maker(Employee::new));
  }

  private static Employee maker(Supplier<Employee> fx) {
    return fx.get();
  }
}

class Employee {
  @Override
  public String toString() {
    return "A EMPLOYEE";
  }
}

下面的代码显示了如何通过方法引用将用户定义的函数分配给 Supplier。

public class Main {
  public static void main(String[] args) {
    Supplier<Student> studentGenerator = Main::employeeMaker;

    for (int i = 0; i < 10; i++) {
      System.out.println("#" + i + ": " + studentGenerator.get());
    }
  }

  public static Student employeeMaker() {
    return new Student("A",2);
  }

}

class Student {
  public String name;
  public double gpa;

  Student(String name, double g) {
    this.name = name;
    this.gpa = g;
  }

  @Override
  public String toString() {
    return name + ": " + gpa;
  }
}

BooleanSupplier 表示布尔值结果的供应商。

BooleanSupplier bs = () -> true;
System.out.println(bs.getAsBoolean());

int x = 0, y= 1;
bs = () -> x > y;
System.out.println(bs.getAsBoolean());
上一页
下一页