函数式接口
Java 8 引入了 java.util.function
包。它包含一组接口,这些接口是 Lambda 表达式和方法引用的目标类型。 每个接口只包含一个抽象方法
,称为函数式方法
。
在编写接口时,可以使用 @FunctionalInterface
注解强制执行此“函数式方法”模式(可选)
java 8 允许我们将函数赋值给接口
高阶函数
import java.util.function.*;
interface
FuncSS extends Function<String, String> {} // [1]
public class ProduceFunction {
static FuncSS produce() {
return s -> s.toLowerCase(); // [2]
}
public static void main(String[] args) {
FuncSS f = produce();
System.out.println(f.apply("YELLING"));
}
}
输出:
yelling
import java.util.function.*;
class I {
@Override
public String toString() { return "I"; }
}
class O {
@Override
public String toString() { return "O"; }
}
public class TransformFunction {
static Function<I,O> transform(Function<I,O> in) {
return in.andThen(o -> {
System.out.println(o);
return o;
});
}
public static void main(String[] args) {
Function<I,O> f2 = transform(i -> {
System.out.println(i);
return new O();
});
O o = f2.apply(new I());
}
}
输出:
I
O
被 Lambda 表达式引用的局部变量必须是 final
或者是等同 final
效果的。
IntSupplier makeFun(int x) {
int i = 0;
// x++ 和 i++ 都会报错:
return () -> x++ + i++;
}
这样是可以的:等同 final
效果的。
public class Closure1 {
int i;
IntSupplier makeFun(int x) {
return () -> x + i++;
}
}
如果 x
和 i
的值在方法中的其他位置发生改变(但不在返回的函数内部),则编译器仍将视其为错误。
import java.util.function.*;
public class Closure5 {
IntSupplier makeFun(int x) {
int i = 0;
i++;
x++;
return () -> x + i;
}
}
可以改成:
import java.util.function.*;
public class Closure6 {
IntSupplier makeFun(int x) {
int i = 0;
i++;
x++;
final int iFinal = i;
final int xFinal = x;
return () -> xFinal + iFinal;
}
}
import java.util.*;
import java.util.function.*;
public class Closure8 {
Supplier<List<Integer>> makeFun() {
final List<Integer> ai = new ArrayList<>();
ai.add(1);
return () -> ai;
}
public static void main(String[] args) {
Closure8 c7 = new Closure8();
List<Integer>
l1 = c7.makeFun().get(),
l2 = c7.makeFun().get();
System.out.println(l1);
System.out.println(l2);
l1.add(42);
l2.add(96);
System.out.println(l1);
System.out.println(l2);
}
}
final ai 不会重新复制,每个闭包都有自己独立的 ArrayList
,它们之间互不干扰。
输出:
[1]
[1]
[1, 42]
[1, 96]
public class Closure9 {
Supplier<List<Integer>> makeFun() {
List<Integer> ai = new ArrayList<>();
ai = new ArrayList<>(); // 无法编译
return () -> ai;
}
}
重新赋值编译不通过
柯里化和部分求值
- 将一个多参数的函数,转换为一系列单参数函数。
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