方法引用的几种类型:
| 方法引用类型 | 例子 | 等效λ表达式 | code |
|---|---|---|---|
| Static | Integer::parseInt | str -> Integer.parseInt(str) | AnonymousAndLambda.java |
| Bound | Instant.now()::isAfter | Instant then =Instant.now(); t ->then.isAfter(t) | AnonymousAndLambda.java |
| Unbound | String::toLowerCase | str ->str.toLowerCase() | AnonymousAndLambda.java |
| Class Constructor | TreeMap<K,V>::new | () -> new TreeMap<K,V> | AnonymousAndLambda.java |
| Array Constructor | int[]::new | len -> new int[len] | AnonymousAndLambda.java |
如果方法引用更短、更清晰,则使用它们;如果没有,仍然使用 lambda 表达式;
java.util.function 中有 43 个接口。需要记住其中 6 个基本接口,在需要时派生出其他接口:
| 接口 | 签名 | eg | 说明 |
|---|---|---|---|
| UnaryOperator | T apply(T t) | String::toLowerCase | 返回类型与入参类型相同 |
| BinaryOperator | T apply(T t1, T t2) | BigInteger::add | 返回类型与入参类型相同,但是有两个入参 |
| Predicate | boolean test(T t) | Collection::isEmpty | 接受一个参数T,返回boolean类型 |
| Function<T,R> | R apply(T t) | Arrays::asList | 接受参数T,返回R |
| Supplier | T get() | Instant::now | 不接受参数,返回T |
| Consumer | void accept(T t) | System.out::println | 接受参数T, 不返回结果 |
6个基本接口每个会有3中变体,用于操作基本类型 int、long 和 double。 它们的名称是通过在基本接口前面加上基本类型前缀而派生出来的。
例如:一个接受 int 的 Predicate 就是一个 IntPredicate,一个接受两个 long 值并返回一个 long 的二元操作符就是一个 LongBinaryOperator。除了由返回类型参数化的函数变量外,这些变量类型都不是参数化的。例如,LongFunction<int[]> 使用 long 并返回一个 int[]。
Function接口还有9个额外变体,以供结果类型为基本数据类型时使用。如果源类型和结果类型都是基本数据类型,则使用带有 SrcToResult 的前缀函数,例如 LongToIntFunction(六个变体)。如果源是一个基本数据类型,而结果是一个对象引用,则使用带前缀 ToObj 的 Function 接口,例如 DoubleToObjFunction(三个变体)。
大多数标准函数式接口的存在只是为了提供对基本类型的支持。不要尝试使用带有包装类的基本函数式接口,而不是使用基本类型函数式接口。在批量操作中使用装箱原语的性能后果可能是致命的。
- 在没有显式类型的情况下,lambda 表达式参数的谨慎命名对于流管道的可读性至关重要
- 在流管道中使用 helper 方法比在迭代代码中更重要,因为管道缺少显式类型信息和命名的临时变量
- Java 不支持基本字符流
"Hello world!".chars().forEach(System.out::print);
// 打印 721011081081113211911111410810033
// 这是因为 "Hello world!".chars() 返回的流元素不是 char 值,而是 int 值,因此调用了 print 的 int 重载
适合使用流的场景:
- 元素序列的一致变换
- 过滤元素序列
- 使用单个操作组合元素序列(例如添加它们、连接它们或计算它们的最小值)
- 将元素序列累积到一个集合中,可能是按某个公共属性对它们进行分组
- 在元素序列中搜索满足某些条件的元素
使用中间操作 flatMap
- forEach 操作应该只用于报告流计算的结果,而不是执行计算
- 静态导入 Collectors 的所有成员是习惯用法,也是明智的,因为这使流管道更具可读性