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

问题描述:

我的同事和我有一个错误,这是由于我们的假设,一个空的流调用allMatch()将返回false为什么Stream.allMatch()对于空流返回true?

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

当然,假设和不读文档是我们的错。但是我不明白的是为什么空流的默认allMatch()行为返回true。这是什么原因?像anyMatch()(其相反地返回错误)一样,该操作以离开单子并且可能在if声明中使用的命令方式使用。考虑到这些事实,是否有任何理由将allMatch()默认为true在空的流上对大多数用途来说是可取的?

+3

这有点奇怪。我们希望如果'allMatch'返回true,那么'anyMatch'也应该如此。另外,对于空白的情况,'allMatch(...)== noneMatch(...)'也是很奇怪的。 – Radiodef

+4

维基百科说这是一个惯例:http://en.wikipedia.org/wiki/Universal_quantification#The_empty_set – Alex

+0

只是简单的说一下语法:而不是将谓词写成'i - > i.isValid()',你可以写'Foo :: isValid'(其中'Foo'是你正在流式传输的任何类,当然) – MattPutnam

这就是所谓的vacuous truth。所有空集合的成员都能满足你的条件;毕竟,你能指出一个不是吗?同样,anyMatch返回false,因为您无法找到符合条件的集合元素。这对很多人来说都是令人困惑的,但事实证明,它是定义空集“any”和“all”最有用和最一致的方法。

+0

Geez,我讨厌布尔逻辑。我想我知道你在说什么。没有消极是积极的,但没有积极的消极态度。 – tmn

+8

@ThomasN。以同样的方式,一组空数字的乘积为'1',而一组空数字的总和为'0'。它们是乘法/加法的中立元素。在布尔值的情况下,你有'True和x = x'和'False或x = x',因此如果你将'and'和'or'概括为序列(这就是全部和任意)对于空壳,即它们各自的中性元素,用“真”和“假”来表示。 – Bakuriu

+7

@ThomasN。 'anyMatch'测试是否存在正数,'allMatch'测试是否存在负数。 – immibis

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

如果allMatch返回false为空列表会怎么样?

我简单的逻辑会失败:

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

我需要记住与!myList.empty() && !myList.allMatch()更换检查。

简而言之,allMatch返回true对于一个空列表来说不仅逻辑上合理,它还处于快乐的执行路径上,需要更少的检查。

+0

你可能是指'if(!allMatch)' – assylias

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

如果流为空,则量化被认为是真实满足并且总是为真。 Oracle Docs: Stream operations and pipelines

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

在纯数学中,真实的真实陈述本身通常并不感兴趣,但它们经常作为数学归纳证明的基本情况出现。Wikipedia: Vacuous Truth

这里是另一种方式来思考一下这个

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