【问题标题】:Java stream - apply two filters and collect to two collections in one iteration [duplicate]Java流-在一次迭代中应用两个过滤器并收集到两个集合[重复]
【发布时间】:2019-06-03 16:00:58
【问题描述】:

我有一个要迭代的地图,我想用两个条件检查 entryset 的值;如果满足条件1,我将它分组到一个集合中,findFirst() 并获取Optional<>,如果不满足,则使用另一个条件过滤并收集到另一个集合,执行相同操作。

我在一次迭代中使用了for 循环。现在,如果我只想用 Java 8 流迭代一次,有可能吗?

我已经尝试过stream().filter(cond1).map(Map.Entry::getValue).findFirst()(迭代两次)。

我还检查了groupingBy()partitionBy(),但我还没有看到这种可能性。


方法一的例子:

for (Map.Entry<String, Response> entry: responses.entrySet()) {
    String key = entry.getKey();
    Response value = entry.getValue();
    if (key.equals("foo") && !value.equals("bar")) {
        res1 = value;
    } else if (key.equals("some other key")) {
        res2 = value;
    }
}

Response finalResponse = res1 != null ? res1 : res2;

方法2示例:

Optional<Response> res1 = Optional.empty();
Response res2;

res1 = responses.entrySet().stream()
        .filter(entry -> entry.getKey().equals("foo") && 
                !entry.getValue().equals("bar"))
        .map(Map.Entry::getValue)
        .findFirst();
res2 = responses.entrySet().stream()
        .filter(entry -> entry.getKey().equals("some other key"))
        .map(Map.Entry::getValue)
        .findFirst().orElse(null);

Response finalResponse = res1.orElse(res2);

【问题讨论】:

  • if 或者 else .. 可能使用partitioningBy
  • 哈哈好吧,在这里尝试加深我对Java Stream的理解..
  • @Naman: paritioningBy?它在这里有什么用处?能给个代码吗?我试过了,但是太笨拙了。
  • @Nikolas 我最初认为问题读取条件为 if/else,这就是分区有用的地方。但在当前情况下,条件是独立的,因此使用partitioningBy 没有多大意义。尽管就为什么必须遍历此处设置的条目而言,这个问题并不是很清楚。 containsKeyget 可以提供足够的信息恕我直言。
  • Response 的实例永远不能等于字符串"bar"

标签: java dictionary java-8 java-stream


【解决方案1】:

如果您的条件仅基于键和值上的.equals(),就像您在问题中显示的那样,您可以使用map.get() 和一个简单的if 语句:

Response result = responses.get("foo");
if (result == null || result.equals(bar))
    result = responses.get("some other key");

所以没有必要使用其他任何东西。

或者按照 Holger 的建议,您也可以使用 map.getOrDefault()

Response result = responses.getOrDefault("foo", bar); 
if(result.equals(bar))
    result = responses.get("some other key");

【讨论】:

  • 或者,您可以使用Response result = responses.getOrDefault("foo", bar); if(result.equals(bar)) result = responses.get("some other key");
  • @Holger 是的,这是一个很好的选择。感谢您提出这个建议。
【解决方案2】:

这可能是您使用Optional 所需要的:

Response response = Optional
        .ofNullable(responses.get("foo"))              // find the "foo" Response
        .filter(value -> !"bar".equals(value)) // except if is null or "bar"
        .orElse(responses.get("other"));    // then find the "other" response (then null)

一些见解:

  1. 有代码:

    if (key.equals("foo") && !value.equals("bar")) {
        res1 = value;
    } else if (key.equals("some other key")) {
        res2 = value;
    }
    

    在循环内部不必要地在每次迭代中检查这两个条件,尽管每个键可能只出现一次。如果设置了res1res2,请考虑使用break

  2. 不是赢家。请注意,entry.getKey().equals("foo") 应缩短为 map.get("foo"),如果密钥不存在,则返回 null。这就是为什么我将这种行为与 Optional 一起使用。

【讨论】:

  • ofNullable(responses.get("foo")) 表示缺少密钥 foo
  • 是的,你是对的 :)
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2020-03-25
  • 2020-12-24
  • 1970-01-01
相关资源
最近更新 更多