总结
用一个接口对象去应用绑定一个类的方法(接口方法和类方法有相同的辨识符)
用 接口.方法(参数…)的方法调用,或者获取返回值
- RecursiveFibonacci.java
public class RecursiveFibonacci {
IntCall fib;
RecursiveFibonacci() {
fib = n -> n == 0 ? 0 :
n == 1 ? 1 :
fib.call(n - 1) + fib.call(n - 2);
}
int fibonacci(int n) { return fib.call(n); }
public static void main(String[] args) {
RecursiveFibonacci rf = new RecursiveFibonacci();
for(int i = 0; i <= 10; i++)
System.out.println(rf.fibonacci(i));
}
}
>输出结果:
0
1
1
2
3
5
8
13
21
34
55
- UnboundMethodReference.java
class X {
String f() { return "X::f()"; }
}
interface MakeString {
String make();
}
interface TransformX {
String transform(X x);
}
public class UnboundMethodReference {
public static void main(String[] args) {
// MakeString ms = X::f; // [1]
TransformX sp = X::f;
X x = new X();
System.out.println(sp.transform(x)); // [2]
System.out.println(x.f()); // 同等效果
}
}
>输出结果:
X::f()
X::f()
- [1],我们尝试把 X 的 f() 方法引用赋值给 MakeString。结果:即使 make() 与 f() 具有相同的签名,编译也会报“invalid method reference”(无效方法引用)错误。 这是因为实际上还有另一个隐藏的参数:我们的老朋友 this。 你不能在没有 X 对象的前提下调用 f()。 因此,X :: f 表示未绑定的方法引用,因为它尚未“绑定”到对象。
要解决这个问题,我们需要一个 X 对象,所以我们的接口实际上需要一个额外的参数的接口,如上例中的 TransformX。 如果将 X :: f 赋值给 TransformX,这在 Java 中是允许的。这次我们需要调整下心里预期——使用未绑定的引用时,函数方法的签名(接口中的单个方法)不再与方法引用的签名完全匹配。 理由是:你需要一个对象来调用方法。 - [2] 的结果有点像脑筋急转弯。 我接受未绑定的引用并对其调用 transform(),将其传递给 X,并以某种方式导致对 x.f() 的调用。 Java 知道它必须采用第一个参数,这实际上就是 this,并在其上调用方法。
- 在编写接口时,可以使用 @FunctionalInterface 注解强制执行此“函数式方法”模式。
- TriFunctionTest.java
@FunctionalInterface
interface TriFunction<T, U, V, R> {
R apply(T t, U u, V v);
}
public class TriFunctionTest {
static int f(int i, long l, double d) {
return 99;
}
public static void main(String[] args) {
TriFunction<Integer, Long, Double, Integer> tf =
TriFunctionTest::f;
System.out.println(tf.apply(1, 1L, 1.0));
// tf = (i, l, d) -> i+l+d; //error
tf = (i, l, d) -> i;
System.out.println(tf.apply(13, 14L, 15.0));
}
}
>输出结果:
99
13
- TransformFunction.java
import java.util.function.*;
class I {
public I() {
System.out.println("Create I");
}
@Override
public String toString() { return "I"; }
}
class O {
public O() {
System.out.println("Create O");
}
@Override
public String toString() { return "O"; }
}
public class TransformFunction {
static Function<I,O> transform(Function<I,O> in) {
System.out.println("2");
return in.andThen(o -> {
System.out.println("Accept a O");
System.out.println(o);
return o;
});
}
public static void main(String[] args) {
System.out.println("1");
Function<I,O> f2 = transform(i -> {
System.out.println("Accept a I");
System.out.println(i);
return new O();
});
System.out.println("3");
O o = f2.apply(new I());
}
}
>输出结果:
1
2
3
Create I
Accept a I
I
Create O
Accept a O
O
- 闭包
- 实际上只要有内部类,就会有闭包(Java 8 只是简化了闭包操作)。在 Java 8 之前,变量 x 和 i 必须被明确声明为 final。在 Java 8 中,内部类的规则放宽,包括等同 final 效果。
- Curry3Args.java
import java.util.function.*;
public class Curry3Args {
public static void main(String[] args) {
Function<String,
Function<String,
Function<String, String>>> sum =
a -> b -> c -> a + b + c;
Function<String,
Function<String, String>> hi =
sum.apply("Hi ");
Function<String, String> ho =
hi.apply("Ho ");
System.out.println(ho.apply("Hup"));
}
}
>输出结果:
Hi Ho Hup