简体   繁体   English

分层过滤使用 Java Stream API

[英]Layered filtering using Java Stream API

I have some imperative Java conditional code that I want to refactor to use Streams.我有一些命令式 Java 条件代码,我想重构以使用 Streams。

Specifically, I have this map that I want to filter into a List based on specific filter criteria.具体来说,我有这个 map,我想根据特定的过滤条件过滤到一个列表中。

private  Map<Integer,Thing> thingMap = new HashMap<Integer,Thing>();
// populate thingMap

And here's the code that uses it:这是使用它的代码:

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);
        }
    }
}

I refactored that to the following.我将其重构为以下内容。 But what's missing is I want the location to be checked only if the category filter passes.但是缺少的是我希望在类别过滤器通过时才检查位置。 Also, I suspect there's a better way to do this:另外,我怀疑有更好的方法来做到这一点:

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());
    

What would be the idiomatic approach to retaining the layered conditional checks using Streams?使用 Streams 保留分层条件检查的惯用方法是什么?

Operations chained after a filter will only be executed for elements accepted by the predicate.filter之后链接的操作只会对谓词接受的元素执行。 So there is no need to worry about that.所以没有必要担心这一点。

You could also join the conditions into a single filter step, just like you could join the nested if statements into a single if , by combining the conditions using && .您还可以将条件加入单个filter步骤,就像您可以将嵌套的if语句加入单个if一样,通过使用&&组合条件。 The result is the same.结果是一样的。

But note that the loop uses the condition location == null , referring to the variable declared outside the code snippet you have posted, not thing.getLocation() == null .但请注意,循环使用条件location == null ,指的是在您发布的代码片段之外声明的变量,而不是thing.getLocation() == null

Besides that, you made other unnecessary changes compared to the loop.除此之外,与循环相比,您还进行了其他不必要的更改。 The loop iterates over the values() view of the map whereas you used entrySet() for the Stream instead, introducing the need to call getValue() on a Map.Entry four times.该循环遍历 map 的values()视图,而您将entrySet()用于 Stream,从而需要在Map.Entry上调用getValue()四次。

A straight-forward translation of the loop logic is much simpler:循环逻辑的直接翻译要简单得多:

List<Thing> things = thingMap.values().stream()
    .filter(thing -> thing.getCategory().equals(category))
    .filter(thing -> location == null || thing.getLocation().equals(location))
    .collect(Collectors.toList());

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM