【问题标题】:Checking if a list is empty in java 8在java 8中检查列表是否为空
【发布时间】:2023-03-28 23:56:02
【问题描述】:

我是 Java8 的新手。我已经实现了列表和过滤器。我在我的代码中做了一个空检查。对于如何检查同一代码 sn-p 中的列表是否不为空,我将不胜感激。如果列表不为空,则代码应继续进行断言。

    list.stream().filter(listElement -> listElement != null).
    forEach((listElement) -> Assert.assertEquals(
        ValueType.CANDY,
        listElement.getCandyType()));

【问题讨论】:

    标签: filter java-8 java-stream empty-list


    【解决方案1】:

    你在问一个过时的问题。 Streams 处理源的所有元素,因此,如果没有元素,则不会执行任何操作。因此,您无需检查列表是否为空。

    不过,您可以简化代码:

    list.stream().filter(Objects::nonNull)
        .map(listElement -> listElement.getCandyType())
        .forEach(candyType -> Assert.assertEquals(ValueType.CANDY, candyType));
    

    或

    Assert.assertTrue(list.stream().filter(Objects::nonNull)
                          .map(listElement -> listElement.getCandyType())
                          .allMatch(Predicate.isEqual(ValueType.CANDY));
    

    allMatch 遵循此检查所需的规则。如果没有元素,则没有矛盾的元素,因此 all match。请注意,listElement -> listElement.getCandyType() 也可以替换为 ClassName::getCandyType 形式的方法引用;因为不知道正确的类名,所以这里没有做。

    两种变体之间没有性能差异。 allMatch 遇到第一个不匹配的元素会立即返回,assertEquals 会抛出第一个不匹配的元素。在第二种情况下,堆栈跟踪不会显示流 API 实现的工件。

    当您为生产代码而不是单元测试提供检查并允许关闭这些检查时,第二个是首选,例如 Java 语言 assert 功能,例如

    assert list.stream().filter(Objects::nonNull)
               .map(listElement -> listElement.getCandyType())
               .allMatch(Predicate.isEqual(ValueType.CANDY));
    

    因为这种形式保证在关闭断言时不会产生开销,而第一个变体具有带有forEach 操作的assert 语句仍可能导致迭代所有元素并执行中间步骤管道。

    【讨论】:

    • 您的方法的缺点是,在失败的情况下,原始代码将显示一个实际的不匹配值,例如“预期的 CANDY 但为:SHMANDY”,而您的代码只会说断言失败。
    • @Tagir Valeev:我的第一个变体仍然是这样。尽管这些信息是否真的有帮助还有待商榷。也许索引会更有帮助,也许 other 不匹配的项目,如果有的话……通常,导致错误状态的历史是您需要的,但这是任何变体都无法提供的东西。
    • 谢谢。我选择了你的答案。它非常清晰,我的代码也得到了改进。
    【解决方案2】:

    选择的答案很棒,只是一个小建议,用Optional.ofNullable 的newly introduced to Java8 Optional class 处理空大小写:

      Optional.ofNullable(list)
                .orElseGet(Collections::emptyList)
                .stream().filter(Objects::nonNull)
                .map(listElement -> listElement.getCandyType())
                .forEach(candyType -> Assert.assertEquals(ValueType.CANDY, candyType)););
    

    【讨论】:

      【解决方案3】:

      查看isEmpty 方法

      if (list.isEmpty()) { ... }
      

      这是文档:https://docs.oracle.com/javase/7/docs/api/java/util/List.html#isEmpty()

      【讨论】:

      • 谢谢,但我想知道如何在 Java8 流中检查它的语法
      • 如果列表为空,那么断言无论如何都不会发生,因为它不会有任何元素可以循环
      【解决方案4】:

      断言列表为空与断言列表的任何特定元素具有某种形式(即getCandyType() == ValueType.CANDY)是不同的。试图将这两个想法联系在一起并不是正确的做事方式。

      您需要做的是在forEach 之前或之后添加第二个断言

      assertThat(list.isEmpty(), not(equalTo(Boolean.FALSE)))
      

      ... 或类似的东西。

      关于空列表的主要观点之一是它们可以像处理包含元素的列表一样处理。这就是存在Optional class 和Null pattern 之类的东西的原因。因此,如果您真的关心列表是否为空,您真的应该 将其设为一个单独的、不同的断言。

      【讨论】:

      • 如果这些实用方法如其名称所暗示的那样,not(equalTo(Boolean.FALSE)) 是一种相当模糊的说法 true...
      • @Holger,我猜他们也能够自动格式化错误消息(类似于“它不等于 FALSE”)。尽管这里绝对没有必要如此冗长。
      • @Holger 你是对的,最好的断言可能会使用 hamcrest IsEmptyCollection.empty() matcher - assertThat(list, not(empty()))。
      猜你喜欢
      • 2012-12-18
      • 2022-08-18
      • 1970-01-01
      • 2021-05-30
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2017-06-11
      • 1970-01-01
      相关资源
      最近更新 更多