[英]Correct lambda filter implementation
我有一個需要的案例
map
一個對象,如果映射函數拋出異常,我將其映射為null
。 filter
映射的null
對象流,如果為null則拋出異常,否則收集到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以在null
上throw new Exception()
或者collect(Collectors.toList())
。
如果您打算報告異常(這是一個好主意),您應該首先將它映射為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()
創建一個新實例, new Exception()
根本不包含有關原因的信息。
請注意,對於某些情況,已經有專用的異常類型,例如UncheckedIOException
來包裝IOException
。 在其他情況下,聲明自己的未經檢查的異常類型可能更清晰,以確保它不會與應用程序的其他組件拋出的其他異常混淆。
如果映射包含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
集合不為空,您知道可以引發異常。
好吧,有可能在lambdas中使用try-catch
子句,但不建議這樣做,因為lambdas應盡可能短。
將映射器分隔為新方法,然后在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();
}
如果我檢測到我不需要迭代下一個元素,我會拋出異常並立即離開流處理。 如果它無助,為什么繼續執行邏輯呢?
所以我不會在這種情況下使用內置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
列表,因此處理流中的空案例會很簡單。
我分兩步完成,先收集到一個列表:
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 */}
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.