函数式接口
函数式接口
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());