为什么Stream.allMatch()为空流返回true?

tmn*_*tmn 75 java lambda java-8 java-stream

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

if (myItems.allMatch(i -> i.isValid()) { 
    //do something
}
Run Code Online (Sandbox Code Playgroud)

当然,假设而不是阅读文档是我们的错.但我不明白为什么allMatch()空流的默认行为返回true.这是什么原因?就像anyMatch()(相反地返回false)一样,这个操作以一种离开monad并且可能在if声明中使用的命令性方式使用.考虑到这些事实,是否有任何理由为什么在大多数用途中需要allMatch()默认为true空流?

use*_*ica 99

这被称为空洞真相.空集合的所有成员都满足您的条件; 毕竟,你能指出一个没有的吗?同样,anyMatch返回false,因为您无法找到与该条件匹配的集合元素.这让很多人感到困惑,但事实证明这是为空集定义"any"和"all"的最有用和最一致的方法.

  • @ThomasN.同样地,一组空数字的乘积值为"1",而一组空数字的总和为"0".它们是乘法/加法的中性元素.在布尔值的情况下,你有'True和x = x`和'False或x = x`因此,如果你将`和`和`或`概括为序列(那就是'all`和`any`)你就结束了对于空案例,即"真"和"假",即它们各自的中性元素. (12认同)
  • @ThomasN.`anyMatch`测试没有阳性,`allMatch`测试没有阴性. (7认同)
  • 请注意,通过这种方式,您可以执行诸如De Morgan定律之类的好处:stream.allMatch(谓词)与!stream.anyMatch(predicate.negate())相同.类似地,!stream.allMatch(predicate.negate())与stream.anyMatch(谓词)相同. (3认同)
  • 哎呀,我讨厌布尔逻辑。我想我明白你在说什么。缺少否定是积极的,但没有积极性不是消极的。 (2认同)

900*_*000 6

当我打电话list.allMatch(或其他语言的模拟)时,我想检测是否有任何项目list与谓词不匹配.如果没有项目,则没有项目可能无法匹配.我的以下逻辑将选择项目并期望它们与谓词匹配.对于一个空列表,我将不会选择任何项目,逻辑仍然是合理的.

如果allMatch返回false空列表怎么办?

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

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

我需要记得用支票替换支票!myList.empty() && !myList.allMatch().

简而言之,allMatch返回true空列表不仅在逻辑上是合理的,而且还在于快乐的执行路径,需要更少的检查.


Han*_*ans 6

这是考虑这个的另一种方式:

allMatch()&&什么sum()+

请考虑以下逻辑语句:

IntStream.of(1, 2).sum() + 3 == IntStream.of(1, 2, 3).sum()
IntStream.of(1).sum() + 2 == IntStream.of(1, 2).sum()
Run Code Online (Sandbox Code Playgroud)

这是有道理的,因为sum()它只是一个概括+.但是,当你删除一个元素时会发生什么?

IntStream.of().sum() + 1 == IntStream.of(1).sum()
Run Code Online (Sandbox Code Playgroud)

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

我们可以将相同的逻辑应用于Boolean代数.

Stream.of(true, true).allMatch(it -> it) == Stream.of(true).allMatch(it -> it) && true
Run Code Online (Sandbox Code Playgroud)

更一般地说:

stream.concat(Stream.of(thing)).allMatch(it -> it) == stream.allMatch(it -> it) && thing
Run Code Online (Sandbox Code Playgroud)

如果stream = Stream.of()那么这条规则仍然需要适用.我们可以使用&&的"标识元素"来解决这个问题.true && thing == thing所以Stream.of().allMatch(it -> it) == true.