转载

java lambda 容易掉进的2个坑

java lambda 容易掉进的2个坑 戳蓝字「TopCoder 」关注我们哦!

java lambda 容易掉进的2个坑

JDK8通过引入Lambda,小伙伴们不用再写大量的匿名内部类。事实上,还有更多由于函数式编程本身特性带来的提升。比如:代码的可读性会更好、高阶函数引入了函数组合的概念。此外,因为Lambda的引入,集合操作也得到了极大的改善。比如,引入stream API,把map、reduce、filter这样的基本函数式编程的概念与Java集合结合起来。在大多数情况下,处理集合时,Java程序员可以告别for、while、if这些语句。随之而来的是,map、reduce、filter等操作都可以并行化,在一些条件下,可以提升性能。

但是如果lambda的使用姿势不对,会造成意向不到的问题。下面就总结几个常见的Java lambda坑(不正确的使用姿势)~

Collectors.toMap报Duplicate key异常

首先看下以下代码:

// 将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时就会报异常了,所以,在开发中如果不能保证 lambdaCollectors.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);

findFirst空指针异常

首先看下如下代码:

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) 的逻辑。

原文  http://mp.weixin.qq.com/s?__biz=MzIwNTI2ODY5OA==&mid=2649938626&idx=3&sn=15c1348a402d503981c842c5964d8b26
正文到此结束
Loading...