01 函数式接口

1.1 什么是函数式接口

函数式接口(Functional Interface)就是一个有且仅有一个抽象方法,但是可以有多个非抽象方法的接口。

函数式接口可以被隐式转换为 Lambda 表达式。

Lambda 是一个匿名函数,返回一个实现了接口的对象。方法引用实际上也可认为是 Lambda 表达式(简化版)。

1.2 自定义函数式接口

如果要实现自己的函数式接口,步骤很简单。

首先,定义一个接口,并声明一个抽象方法。然后给接口添加注解 @FunctionalInterface,该接口即为函数式接口:

@FunctionalInterface
interface Converter<T, R> {
    R convert(T from);
}

使用同样也很简单,创建一个 Lambda 表达式(要实现的方法)并赋值给该接口的一个变量,然后直接调用定义的那个抽象方法:

// 创建一个函数:字符串转整型
Converter<String, Integer> converter = (from) -> Ingeter.valueOf(from);
converter.convert("123") // 123

02 Java(8)提供的函数式接口

2.1 Converter<T, R>,如上

2.2 Predicate

作用:断言,判断是与非。

调用方式:predicate.test(OBJ)

示例:

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

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

2.3 Function<T, R>

作用:接口一个参数,返回一个结果,可以链式调用。

调用方式:function.apply(OBJ)

示例:

Function<String, Integer> toInteger = Integer::valueOf;
// 链式
Function<String, String> backToString = toInteger.andThen(String::valueOf);

backToString.apply("123");     // "123"

2.4 Supplier

作用:和 Function 一样返回一个结果,但不接收参数。

调用方式:supplier.get()

示例:

Supplier<Person> personSupplier = Person::new;
personSupplier.get();   // new Person

2.5 Consumer

作用:接收一个参数,但不返回(顾名思义),仅执行操作。

调用方式:consumer.accept(OBJ)

示例:

Consumer<Person> greeter = (p) -> System.out.println("Hello, " + p.firstName);
greeter.accept(new Person("Luke", "Skywalker")); // 输出:Hello, Luke

2.6 Comparator(since 1.2)

作用:接收两个参数,对比它们的大小(0),支持链式。

调用方式:comparator.compare(o1, o2)

示例:

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

2.7 Optional(非函数式接口)

作用:用于防止空指针异常等。

调用方式:optional.get() optional.orElse(如果为空则返回这个值)

示例:

// Optional.ofNullable(xx)
Optional<String> optional = Optional.of("bam");

optional.isPresent();           // true
optional.get();                 // "bam"
optional.orElse("fallback");    // "bam"

optional.ifPresent((s) -> System.out.println(s.charAt(0)));     // "b"

03 示例

3.1 实现 f1.SetVal(f2.getVal())

实现一个功能如:把 f2 的 val 赋值给 f1 的 val。

首先,用到了两个方法,需要用链式调用,并且

  • getVal 需要一个参数一个返回值,用 Function<V, R>
  • setVal 不需要返回值,用 Consumer<T>

可以定义如下,Function 接收一个参数 v,返回一个 Consumer,而 Consumer 接收一个参数 o,执行指定动作。

Function<T, Consumer<T>> valSetter = v -> o -> {
    v.setVal(o.getVal());
};

具体使用如下:

// valSetter.apply(f1) == consumer
//   此时 consumer == (o) -> { f1.setVal(o.getVal()); }
// consumer.accept(f2) => 执行上面的 consumer,即f2 代入 o,得到想要的执行结果
valSetter.apply(f1).accept(f2);
  • apply:先执行 Function 的方法,然后将结果作为参数给下个调用
  • accept:由于不需要返回值,就用 Consumer 来接收处理

References

[1] winterbe. Java 8 Tutorial[DB/OL]. https://winterbe.com/posts/2014/03/16/java-8-tutorial/ .