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

时间:2015-05-13 18:53:39

标签: java lambda java-8 java-stream

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

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

当然,假设而不是阅读文档是我们的错。但我不明白为什么空流的默认allMatch()行为返回true。这是什么原因?与anyMatch()(相反地返回false)一样,此操作以强制方式使用,离开monad并可能在if语句中使用。考虑到这些事实,对于大多数用途,是否有理由在空流上allMatch()默认为true

6 个答案:

答案 0 :(得分:88)

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

答案 1 :(得分:6)

当我调用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不仅在逻辑上合理,而且还在于快乐的执行路径,需要更少的检查。

答案 2 :(得分: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()

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

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

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

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

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(),则仍需要应用此规则。我们可以使用&&amp ;;的“身份元素”。解决这个问题。 true && thing == thingStream.of().allMatch(it -> it) == true

答案 3 :(得分:3)

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

  

如果流是空的,则称量化是真空满足并且始终为真。 Oracle Docs: Stream operations and pipelines

这里的关键是它真的很满意"这本质上有点误导。维基百科对此进行了不错的讨论。

  

在纯粹的数学中,空洞的真实陈述本身并不普遍,但它们经常作为数学归纳证明的基本案例出现。 Wikipedia: Vacuous Truth

答案 4 :(得分:1)

虽然这个问题已经被多次正确回答,但我想引入一种更数学的方法。

为此,我想将流视为一个Set(在数学意义上)。然后

emptyStream.allMatch(x-> p(x))

对应于enter image description here

emtpyStream.anyMatch(x -> p(x))

对应于enter image description here

第二部分为假是很明显的,因为空集中没有元素。第一个比较棘手。您可以按照定义接受它为真,也可以出于某些原因考虑其他答案。

一个示例来说明这种差异,例如“所有人类在火星上生活的人都有3条腿”(true)和“有人类在火星上生活的人有3条腿”(false)这样的命题

答案 5 :(得分:0)

在某些情况下,解决方法并不美观。

示例:验证是否所有请求都已发送(但某些类型的请求列表可以为空)

public boolean isAllRequestsSent(String type){

        //empty request List
        var count = requestsList.stream().filter(Request::type).count();
        
        if(count <= 0) {
            return false;
        }
    
        return requestsList.stream().filter(Request::type).allMatch(RequestData::isSent);
        }