戳蓝字「TopCoder 」关注我们哦!
JDK8通过引入Lambda,小伙伴们不用再写大量的匿名内部类。事实上,还有更多由于函数式编程本身特性带来的提升。比如:代码的可读性会更好、高阶函数引入了函数组合的概念。此外,因为Lambda的引入,集合操作也得到了极大的改善。比如,引入stream API,把map、reduce、filter这样的基本函数式编程的概念与Java集合结合起来。在大多数情况下,处理集合时,Java程序员可以告别for、while、if这些语句。随之而来的是,map、reduce、filter等操作都可以并行化,在一些条件下,可以提升性能。
但是如果lambda的使用姿势不对,会造成意向不到的问题。下面就总结几个常见的Java lambda坑(不正确的使用姿势)~
首先看下以下代码:
// 将list转换成map接口
List<String> list = Arrays.asList("a", "b", "c", "a");
Map<String, String> map = list.stream().collect(Collectors.toMap(k -> k, v -> v));
System.out.println(map);
直接执行代码会报异常:
Exception in thread "main" java.lang.IllegalStateException: Duplicate key a
at java.util.stream.Collectors.lambda$throwingMerger$0(Collectors.java:133)
at java.util.HashMap.merge(HashMap.java:1254)
at java.util.stream.Collectors.lambda$toMap$58(Collectors.java:1320)
at java.util.stream.ReduceOps$3ReducingSink.accept(ReduceOps.java:169)
at java.util.Spliterators$ArraySpliterator.forEachRemaining(Spliterators.java:948)
at java.util.stream.AbstractPipeline.copyInto(AbstractPipeline.java:481)
at java.util.stream.AbstractPipeline.wrapAndCopyInto(AbstractPipeline.java:471)
at java.util.stream.ReduceOps$ReduceOp.evaluateSequential(ReduceOps.java:708)
at java.util.stream.AbstractPipeline.evaluate(AbstractPipeline.java:234)
at java.util.stream.ReferencePipeline.collect(ReferencePipeline.java:499)
这是为什么呢?因为默认情况下,也就是 Collectors.toMap(k -> k, v -> v)
未指定 BinaryOperator<U> mergeFunction
时,使用的 mergeFunction
为:
(u,v) -> { throw new IllegalStateException(String.format("Duplicate key %s", u)); };
这样在出现重复key时就会报异常了,所以,在开发中如果不能保证 lambda
的 Collectors.toMap
元素不重复,那么就需要自定义 mergeFunction
,可以将示例代码更改如下就可以了。
List<String> list = Arrays.asList("a", "b", "c", "a");
// v1表示old value,v2表示current value
Map<String, String> map = list.stream().collect(Collectors.toMap(k -> k, v -> v, (v1, v2) -> v1));
System.out.println(map);
首先看下如下代码:
List<String> list = Arrays.asList("a", "b", "c");
String value = list.stream().map(o -> o.equals("a") ? null : o)
.findFirst().orElse(null);
System.out.println(value);
以上代码执行会报空指针,异常信息如下:
Exception in thread "main" java.lang.NullPointerException
at java.util.Objects.requireNonNull(Objects.java:203)
at java.util.Optional.<init>(Optional.java:96)
at java.util.Optional.of(Optional.java:108)
at java.util.stream.FindOps$FindSink$OfRef.get(FindOps.java:193)
at java.util.stream.FindOps$FindSink$OfRef.get(FindOps.java:190)
at java.util.stream.FindOps$FindOp.evaluateSequential(FindOps.java:152)
at java.util.stream.AbstractPipeline.evaluate(AbstractPipeline.java:234)
at java.util.stream.ReferencePipeline.findFirst(ReferencePipeline.java:464)
因为 findFirst
使用的是 Optional.of
,而 Optional.of
要求元素必须非null,所以会报空指针,上述代码很容易看出来,如果 findFirst
前置逻辑较复杂,可能会疏忽元素可能为null情况,因为最好在执行findFirst前加上一个 filter(Objects::nonNull)
的逻辑。