我有需要的情况
map
一个对象,如果映射函数抛出异常,则将其映射到null
。filter
对象null
的映射流,如果为null,则抛出Exception,否则收集到List。我将如何实现?
list.stream().map(ob-> {
try {
// cannot throw only catch
return function(ob);
} catch (Exception e) {
log.error(e);
return null;
}
}).filter(Objects::isNull).findFirst().orElseThrow(Exception::new);
现在我的问题是我应该如何将上述lambda调整/重构为throw new Exception()
上的null
或其他collect(Collectors.toList())
。
答案 0 :(得分:6)
如果您打算报告该异常(这是个好主意),则永远不要一开始将其映射到null
。由于某些功能接口不允许引发已检查的异常,因此您应将其重新包装在未检查的异常中:
try {
List<Object> result = list.stream().map(ob-> {
try {
// cannot throw checked exception types
return function(ob);
} catch(Exception e) {
throw new CompletionException(e);
}
}).collect(Collectors.toList());
} catch(CompletionException ex) {
throw (Exception)ex.getCause();
}
关键是,这将引发原始异常,其中包含所有信息,而不是通过new Exception()
创建一个新实例,而该实例根本不包含有关原因的信息。
请注意,在某些情况下,已经有专用的异常类型,例如UncheckedIOException
来包装IOException
。在其他情况下,声明您自己的未经检查的异常类型可能更简洁,以确保不会与应用程序其他组件抛出的其他异常混淆。
答案 1 :(得分:3)
如果映射包含null
键的非空集合,则可以按谓词进行分区并引发异常:
Map<Boolean, List<String>> resultMap = list.stream().map(ob-> {
try {
return function(ob);
} catch (Exception e) {
return null;
}
}).collect(Collectors.partitioningBy(Objects::isNull));
if(!resultMap.get(Boolean.TRUE).isEmpty()) {
throw new Exception();
}
return resultMap.get(Boolean.FALSE);
Collectors.partitioningBy(Objects::isNull)
将返回一个Map<Boolean, List<T>>
,其中true
将被映射到一个列表,其中所有元素都与谓词(Objects::isNull
)相匹配,而false
与那些没有。
如果true
集合不为空,则可以引发该异常。
答案 2 :(得分:3)
嗯,可以在lambda内使用try-catch
子句,但是不建议这样做,因为lambda的长度应尽可能短。
将映射器分隔为新方法,然后在lambda中调用它。
private static final <T, R> R tryMapOrElseNull(T t) {
try {
return function(t);
} catch (Exception e) {
this.log.error(e);
return null;
}
}
然后将该方法用作Stream::map
方法中的方法引用。首先,收集新映射的元素,然后只需检查null
。
newList = list.stream().map(MyClass::safeMap).collect(Collectors.toList());
if (newList.contains(null)) {
throw new Exception();
}
答案 3 :(得分:3)
如果检测到不需要迭代下一个元素,我将抛出异常并立即离开流处理。如果无助,为什么还要继续执行逻辑?
因此,在这种情况下,我不会使用内置的map()
,也不会流式传输。
我认为通过引入一种简单的映射方法,可以使事情变得易于阅读:
try{
return map(list);
}
catch (Exception e) {
throw new AnyExceptionYouWant(e);
}
// helper method
List<Bar> map (List<Foo> list) throws Exception{
List<Bar>> bars = new ArrayList<>();
for (Foo foo : list){
bars.add(function(foo));
}
return bars;
}
如果您想使用可读且易于维护的流,则可能不应在function()
中引发任何异常。例如,您可以返回Optional
的列表,因此处理流中的空情况很简单。
答案 4 :(得分:1)
我分两步执行此操作,首先收集到列表:
List<T> result = list.stream().map(ob -> {
try {
// cannot throw only catch, since lambda expression
return function(ob);
} catch (Exception e) {
log.error(e);
return null;
}
}).collect(toList());
其中T
是要映射到的元素的类型。
然后检查是否为空:
if(result.contains(null)) {/* throw exeception... */}
else { /* do something else */}