3.4 使用函数式接口
Java API中已有的函数式接口:Comparable、Runnable和Callable。
如3.2.2 函数描述符所示,Java8在java.time.function
定义了一些常用的函数式接口。
3.4.1 Predicate
T -> boolean
// jdk8
@FunctionalInterface
public interface Predicate<T> {
boolean test(T t);
}
静态泛型方法——列表过滤
public static <T> List<T> filter(List<T> list, Predicate<T> p) {
List<T> result = new ArrayList<>();
for (T ele : list) {
if (p.test(ele)) {
result.add(ele);
}
}
return result;
}
List<String> listOfStrings = Lists.newArrayList("", "123", "abc");
Predicate<String> nonEmptyStringPredicate = (String s) -> !s.isEmpty();
filter(listOfStrings, nonEmptyStringPredicate); // [123, abc]
3.4.2 Consumer
T -> void
// jdk8
@FunctionalInterface
public interface Consumer<T> {
void accept(T t);
}
静态泛型方法——列表循环执行
public static <T> void forEach(List<T> list, Consumer<T> c) {
for (T ele : list) {
c.accept(ele);
}
}
// 1 2 3 4 5
forEach(Lists.newArrayList(1, 2, 3, 4, 5), (Integer i) -> System.out.print(i + "\t"));
3.4.3 Function
T -> R
// jdk8
@FunctionalInterface
public interface Function<T, R> {
R apply(T t);
}
静态泛型方法——列表对象映射
public static <T, R> List<R> map(List<T> list, Function<T, R> f) {
List<R> result = new ArrayList<>();
for (T ele : list) {
result.add(f.apply(ele));
}
return result;
}
// [7, 2, 6]
List<Integer> result = map(Lists.newArrayList("lambdas", "in", "action"), (String s) -> s.length());
基本类型函数式接口
由于Java泛型只能绑定引用类型,不能作用于基本类型。
为提高性能和减少内存使用,如3.2.2 函数描述符所示,Java8在java.time.function
提供了基本类型函数式接口。
// jdk8
@FunctionalInterface
public interface IntPredicate {
boolean test(int value);
}
Predicate<Integer> evenIntegers = (Integer i) -> i % 2 == 0;
// true,装箱
evenIntegers.test(1000);
// true,无装箱
IntPredicate evenInts = (int i) -> i % 2 == 0;
evenInts.test(1000);
若标准函数式接口,无法满足诉求,可按照函数描述符形如(T, U)-> R
进行思考及设计。
测验3.4:函数式接口
对于下列函数描述符(即Lambda表达式的签名),你会使用哪些函数式接口?
在表3-2中可以找到大部分答案。
作为进一步练习,请构造一个可以利用这些函数式接口的有效Lambda表达式:
T -> R
,Function<T, R>(int, int) -> int
,IntBinaryOperatorT -> void
,Consumer<T>() -> T
,Supplier<T> 或者 Callable<T>(需要处理抛出的异常)(T, U) -> R
,BiFunction<T, U, R>
在java.time.function
中所有的函数式接口都不允许抛出受检异常,因此若需处理抛出异常的Lambda表达式
-
定义新的函数式接口,声明受检异常。例如示例3.3;
@FunctionalInterface public interface BufferedReaderProcessor { String process(BufferedReader br) throws IOException; } BufferedReaderProcessor p = (BufferedReader br) -> br.readLine();
-
try-catch显式捕获处理异常;
Function<BufferedReader, String> bufferedReaderFunction = (BufferedReader br) -> { try { return br.readLine(); } catch (IOException e) { throw new RuntimeException(e); } };