为什么Stream.allMatch()对于空stream返回true?

我的同事和我有一个错误是由于我们的假设,一个空的stream调用allMatch()将返回false

 if (myItems.allMatch(i -> i.isValid()) { //do something } 

当然,假设和不读文档是我们的错。 但是我不明白为什么空stream的默认allMatch()行为返回true 。 这是什么原因? 和anyMatch() (相反地返回false)一样,这个操作是以一种命令的方式来使用的,它离开monad,可能用在if语句中。 考虑到这些事实,是否有任何理由为什么allMatch()默认为true空stream是可取的大多数用途?

这被称为空洞的真相 。 所有空集合的成员满足您的条件; 毕竟,你能指出一个不是吗? 同样, anyMatch返回false,因为您找不到符合条件的集合元素。 这让很多人感到困惑,但事实certificate,这是定义空集“任意”和“全部”的最有用和最一致的方法。

当我调用list.allMatch (或其他语言的list.allMatch语言)时,我想检测list任何项目是否与谓词不匹配。 如果没有项目,则可能无法匹配。 我的下面的逻辑会select项目,并期望他们已经匹配的谓词。 对于一个空的列表,我会select任何项目,逻辑将仍然是健全的。

如果allMatch为空列表返回false

我直截了当的逻辑会失败:

  if (!myList.allMatch(predicate)) { throw new InvalidDataException("Some of the items failed to match!"); } for (Item item : myList) { ... } 

我需要记住用!myList.empty() && !myList.allMatch()replace检查。

简而言之, allMatch对于一个空列表返回true不仅在逻辑上是合理的,而且还在于快乐的执行path,所以需要更less的检查。

看起来它的基础是math归纳。 对于计算机科学来说,这可能是一个recursionalgorithm的基本情况。

如果这个stream是空的,则量化被认为是真实的满足,并且总是如此。 Oracle Docs:stream操作和pipe道

这里的关键在于它“天真地满意”,这本质上有点误导。 维基百科有一个体面的讨论。

在纯粹的math中,真实的真实陈述本身通常并不感兴趣,但是它们经常作为math归纳certificate的基本情况而出现。 维基百科:真实的真相

这是另一种思考方式:

allMatch()是&&什么sum()是+

考虑下面的逻辑陈述:

 IntStream.of(1, 2).sum() + 3 == IntStream.of(1, 2, 3).sum() IntStream.of(1).sum() + 2 == IntStream.of(1, 2).sum() 

这是有道理的,因为sum()只是+的泛化。 但是,当你移除一个元素时会发生什么?

 IntStream.of().sum() + 1 == IntStream.of(1).sum() 

我们可以看到,以特定的方式定义IntStream.of().sum()或者一个空的数字序列之和是有意义的。 这给我们提供了总和的“身份要素”,或者当添加到某个东西时没有效果(0)的价值。

我们可以将相同的逻辑应用于布尔代数。

 Stream.of(true, true).allMatch(it -> it) == Stream.of(true).allMatch(it -> it) && true 

更一般地说:

 stream.concat(Stream.of(thing)).allMatch(it -> it) == stream.allMatch(it -> it) && thing 

如果stream = Stream.of()那么这个规则仍然需要应用。 我们可以用&&的“身份元素”来解决这个问题。 true && thing == thing ,所以Stream.of().allMatch(it -> it) == true