【问题标题】:Use Streams to return Boolean if all the List values in a Map are empty/not-empty如果 Map 中的所有 List 值为空/非空,则使用 Streams 返回布尔值
【发布时间】:2016-05-18 20:52:20
【问题描述】:

鉴于Map 将字符串映射到List,有没有办法使用Java Streams 返回一个布尔值,其中TRUE 表示一个或多个列表有元素?如果地图中的所有列表都是空的,则返回 FALSE。

Map< String , List<String> > map = …

使用 Streams 可以替代这种常规代码吗?

// See if any diffs were found. Loop through the Map, look at each List of diffs to see if non-empty.
boolean anyElementsInAnyList = false;
for (List<String> list : map.values () ) {
    if (!list.isEmpty()) {
        anyElementsInAnyList = true;
        break;
    }
}

请注意,我们可以在第一次发现后退出检查。无需检查所有地图值(所有列表)。如果为了提高效率,Stream 可以执行相同的 stop-work-on-first-finding(“短路”操作),那就太好了。

【问题讨论】:

  • 你的意思是这个 java-stream 吗? oracle.com/technetwork/articles/java/…
  • 有什么理由在循环中使用Boolean 而不是boolean
  • @Holger Boolean 优于 `boolean,因为我是一个面向对象的人。而且因为在做进一步的工作时,例如在 UI 框架中表示值,如 Vaadin,我可能需要对象而不是原语。
  • 当您编写 Boolean 而不是 boolean 时,代码不会变得更加面向对象。它只是打开了一个新的错误源,因为 Boolean 引用可以是 null 并且 == 运算符不会按照您的意图执行。除此之外,这段代码仍然是相同的命令式循环。顺便问一下,是什么让你现在回答这个四年前的问题?

标签: java java-stream


【解决方案1】:

Stream::allMatch

在 Java 8 中,您可以检查并非所有列表都是空的。

 boolean anyNonEmpty = !map.values().stream().allMatch(List::isEmpty);

注意Stream::allMatchshort-circuiting terminal operation。所以流是高效的,不会运行超过需要的时间。

【讨论】:

  • 有趣的是看到 answer by rgettman 中的代码相反,使用 allMatchanyMatch。在我看来,这种方法不能利用“短路”操作。所以它不如 rgettman 的效率高,它会短路。
  • @BasilBourque allMatch 方法也是短路的。
  • @Basil Bourque:不要按方法名,按the documentation:“这是一个短路终端操作。
【解决方案2】:

使用the anyMatch method 来查找流的任何元素是否与Predicate 匹配。在这里,您的谓词是条目的值(列表)不为空。

boolean anyNonEmpty = map.entrySet()
    .stream()
    .anyMatch(entry -> !entry.getValue().isEmpty());

【讨论】:

  • @hotkey 你应该刚刚评论说我可以用values 替换entrySet 并在谓词中直接转到!list.isEmpty
  • 好的,谢谢!医生说这个方法是short-circuiting terminal operation。所以这个Stream应该有一些不检查Map中所有值的效率。显然,根据this Question,即使并行(多线程)工作,我们也能获得这种好处。
  • @rgettman:您可以将 entrySet 替换为 values 并在谓词中直接转到 !list.isEmpty ;-)。顺便说一句,即使问题的代码已经使用values()
【解决方案3】:
int size = Map.entrySet().stream()
                           .map(entry -> entry.getValue())
                           .flatMap(list -> list.stream())
                           .size();
if(size==0)
  return Boolean.False;
else
  return Boolean.True;

此代码很简单,可能对您的工作有所帮助。

【讨论】:

  • 投反对票?请留下您的评论和您的投票。这是一个可靠的答案,具有教育意义,具有有趣的替代方法。不是最适合这个问题的场景,但可能对其他场景略有不同的读者非常有用。
  • 我没有投反对票,但有一些明显的事情要批评。首先,使用Map(容易与那个名字的类型混淆)而不是正确的变量名map,那么,流过entrySet()只是为了映射到下一个值是没有意义的步骤,特别是因为问题已经暗示了values() 的存在,您可以首先流式传输。此外,Stream 中没有 size() 方法,即使它存在,这也是资源的浪费,因为计算所有元素通常不会短路。更不用说return size==0;...
猜你喜欢
  • 2014-02-07
  • 2019-12-23
  • 2012-12-06
  • 2020-08-09
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-04-29
相关资源
最近更新 更多