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

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/30223079/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-11 09:21:28  来源:igfitidea点击:

Why does Stream.allMatch() return true for an empty stream?

javalambdajava-8java-stream

提问by tmn

My colleague and I had a bug that was due to our assumption that an empty stream calling allMatch()would return false.

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

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

Of course, it is kind of our fault for assuming and not reading documentation. But what I don't understand is why the default allMatch()behavior for an empty stream returns true. What was the reasoning for this? Like the anyMatch()(which contrarily returns false), this operation is used in an imperative way that departs the monad and probably used in an ifstatement. Considering those facts, is there any reason why having allMatch()default to trueon an empty stream be desirable for majority of uses?

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

采纳答案by user2357112 supports Monica

This is known as vacuous truth. All members of an empty collection satisfy your condition; after all, can you point to one that doesn't?

这被称为空洞的真理。一个空集合的所有成员都满足你的条件;毕竟,你能指出一个没有吗?

Similarly, anyMatchreturns false, because you can't find an element of your collection that does match the condition. This is confusing to a lot of people, but it turns out to be the most useful and consistent way to define "any" and "all" for empty sets.

同样,anyMatch返回false,因为您找不到与条件匹配的集合元素。这让很多人感到困惑,但事实证明这是为空集定义“任何”和“所有”的最有用和最一致的方法。

回答by 9000

When I call list.allMatch(or its analogs in other languages), I want to detect if any items in listfail to match the predicate. If there are no items, none might fail to match. My following logic would pick items and expect them to have matched the predicate. For an empty list, I'll pick no items and the logic will still be sound.

当我调用list.allMatch(或其在其他语言中的类似物)时,我想检测是否有任何项目list无法匹配谓词。如果没有项目,则可能没有项目无法匹配。我的以下逻辑会选择项目并期望它们与谓词匹配。对于空列表,我不会选择任何项目,逻辑仍然是合理的。

What if allMatchreturned falsefor an empty list?

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

My straightforward logic would fail:

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

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

I'll need to remember to replace the check with !myList.empty() && !myList.allMatch().

我需要记住用!myList.empty() && !myList.allMatch().

In short, allMatchreturning truefor an empty list is not only logically sound, it also lies on the happy path of execution, requiring fewer checks.

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

回答by Nathan

It looks like the base of it is mathematical induction. For computer science an application of this could be a base case of a recursive algorithm.

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

If the stream is empty, the quantification is said to be vacuously satisfied and is always true. Oracle Docs: Stream operations and pipelines

如果流为空,则称量化为空满足且始终为真。Oracle 文档:流操作和管道

The key here is that it is "vacuously satisfied" which, by nature, is somewhat misleading. Wikipedia has a decent discussion about it.

这里的关键是它是“空虚地满足”,这在本质上有点误导。维基百科对此进行了不错的讨论。

In pure mathematics, vacuously true statements are not generally of interest by themselves, but they frequently arise as the base case of proofs by mathematical induction. Wikipedia: Vacuous Truth

在纯数学中,空洞真命题本身通常并不令人感兴趣,但它们经常作为数学归纳法证明的基本情况出现。维基百科:空洞的真相

回答by Hans

Here's another way to think about this:

这是另一种思考方式:

allMatch()is to &&what sum()is to +

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

Consider the following logical statements:

考虑以下逻辑语句:

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

This makes sense because sum()is just a generalization of +. However, what happens when you remove one more element?

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

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

We can see that it makes sense to define IntStream.of().sum(), or the sum of an empty sequence of numbers, in a particular way. This gives us the "identity element" of summation, or the value that, when added to something, has no effect (0).

我们可以看到IntStream.of().sum()以特定方式定义或空数字序列的总和是有意义的。这为我们提供了求和的“身份元素”,或者说当添加到某物时没有任何效果的值 ( 0)。

We can apply the same logic to Booleanalgebra.

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

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

More generically:

更一般地:

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

If stream = Stream.of()then this rule still needs to apply. We can use the "identity element" of && to solve this. true && thing == thing, so Stream.of().allMatch(it -> it) == true.

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