使用JavaStreamAPI进行分层过滤
我有一些命令式 Java 条件代码,我想对其进行重构以使用 Streams。
具体来说,我有这张地图,我想根据特定的过滤条件过滤到一个列表中。
private Map<Integer,Thing> thingMap = new HashMap<Integer,Thing>();
// populate thingMap
这是使用它的代码:
List<Thing> things = new ArrayList<Thing>();
for (Thing thing : thingMap.values()) {
if (thing.getCategory().equals(category)) {
if (location == null) {
things.add(thing);
} else if (thing.getLocation().equals(location)) {
things.add(thing);
}
}
}
我将其重构为以下内容。但是缺少的是我希望只有在类别过滤器通过时才检查位置。另外,我怀疑有更好的方法来做到这一点:
List<Thing> things = thingMap.entrySet()
.stream()
.filter(t -> t.getValue().getCategory().equals(category))
.filter(t ->
location == null ||
t.getValue().getLocation().equals(location)
)
.map(Map.Entry::getValue)
.collect(Collectors.toList());
使用 Streams 保留分层条件检查的惯用方法是什么?
回答
链接在 a 之后的操作filter只会对谓词接受的元素执行。所以没有必要担心。
您也可以将条件合并为一个filter步骤,就像您可以将嵌套if语句合并为单个 一样if,通过使用 组合条件&&。结果是一样的。
但请注意,循环使用 condition location == null,指的是在您发布的代码片段之外声明的变量,而不是thing.getLocation() == null.
除此之外,与循环相比,您还进行了其他不必要的更改。该循环迭代values(),而你使用的地图视图entrySet()的流代替,引入需要调用getValue()上Map.Entry四次。
循环逻辑的直接转换要简单得多:
List<Thing> things = thingMap.values().stream()
.filter(thing -> thing.getCategory().equals(category))
.filter(thing -> location == null || thing.getLocation().equals(location))
.collect(Collectors.toList());