Stream.allMatch ()가 빈 스트림에 대해 true를 반환하는 이유는 무엇입니까?


84

제 동료와 저는 빈 스트림 호출 allMatch()이 반환 될 것이라는 가정으로 인해 버그가 발생했습니다 false.

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

물론 문서를 읽지 않고 가정하는 것은 우리의 잘못입니다. 그러나 내가 이해하지 못하는 allMatch()것은 빈 스트림에 대한 기본 동작이 true. 그 이유는 무엇입니까? anyMatch()(반대로 false를 반환하는) 와 마찬가지로이 작업은 모나드를 떠나 if명령문 에서 사용되는 명령형 방식으로 사용됩니다 . 이러한 사실을 고려할 때 대부분의 경우 빈 스트림에서 allMatch()기본값을 true사용하는 것이 바람직한 이유 가 있습니까?


4
좀 이상합니다. allMatchtrue를 반환하면 그렇게해야한다고 예상 할 수 anyMatch있습니다. 또한 빈 케이스의 경우 allMatch(...) == noneMatch(...)도 이상합니다.
Radiodef는


구문에 대한 간단한 설명 : 술어를로 작성하는 대신 다음과 같이 작성할 i -> i.isValid()수 있습니다 Foo::isValid( Foo물론 스트리밍하는 클래스는 어디에 있든)
MattPutnam

2
"이 작업은 모나드를 떠나는 명령적인 방식으로 사용됩니다."-나는 이것이 어떤 결정에 영향을 미치는지 의심 스럽다.
user253751

답변:


115

이것은 공허한 진실로 알려져 있습니다 . 빈 컬렉션의 모든 구성원이 조건을 충족합니다. 결국 그렇지 않은 것을 가리킬 수 있습니까?

마찬가지로, 조건과 일치하는 컬렉션 요소를 찾을 수 없기 때문에를 anyMatch반환 false합니다. 이것은 많은 사람들에게 혼란 스럽지만 빈 세트에 대해 "any"및 "all"을 정의하는 가장 유용하고 일관된 방법으로 밝혀졌습니다.


3
이런, 난 부울 논리가 싫어. 당신이 무슨 말을하는지 알 것 같아요. 부정적인 것이 없다는 것은 긍정적이지만 긍정적 인 것이없는 것은 부정적인 것이 아닙니다.
tmn

13
@ThomasN. 같은 방식으로 빈 숫자 집합의 곱은이고 빈 숫자 집합의 1합은입니다 0. 곱셈 / 덧셈의 중립 요소입니다. 부울의 경우 귀하는 다음이 True and x = xFalse or x = x따라서 당신이 일반화 경우 andor시퀀스에 (의 어떤 것을 all하고 any있다) 당신이 결국 True하고 False비어있는 경우에, 즉 그들이 각각의 중립적 인 요소.
Bakuriu

9
@ThomasN. anyMatch양성 부재에 allMatch대한 테스트 , 음성 부재에 대한 테스트.
user253751

3
이렇게하면 De Morgan의 법칙과 같은 멋진 작업을 수행 할 수 있습니다. stream.allMatch (predicate)는! stream.anyMatch (predicate.negate ())와 동일합니다. 마찬가지로! stream.allMatch (predicate.negate ())는 stream.anyMatch (predicate)와 동일합니다.
Hans

1
@PatrickBard : "할 수있는 사람을 가리킬 수 있습니까?"라고 말할 수 있으며 이는 완전히 유효 하지만 컬렉션의 모든 구성원이 조건을 충족하지 못한다는 의미입니다. 컬렉션의 모든 멤버가 조건을 충족하고 컬렉션의 모든 멤버가 조건을 충족하지 못합니다. 이는 "컬렉션의 모든 구성원이 조건을 충족하는 것은 거짓입니다"와는 다른 설명입니다. 내가 말했듯이 혼란 스럽습니다.
user2357112 모니카 지원

10

이에 대해 생각하는 또 다른 방법이 있습니다.

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()이 규칙을 적용해야합니다. 이 문제를 해결하기 위해 &&의 "identity element"를 사용할 수 있습니다. true && thing == thing, 그래서 Stream.of().allMatch(it -> it) == true.


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하는 것은 논리적으로 건전 할뿐만 아니라 실행의 행복한 경로에 있으며 확인이 더 적게 필요합니다.


당신은 아마 의미했습니다if (!allMatch)
assylias

3

그것의 기초가 수학적 귀납처럼 보입니다. 컴퓨터 과학의 경우이를 적용하는 것이 재귀 알고리즘의 기본 사례가 될 수 있습니다.

스트림이 비어 있으면 정량화가 막연하게 충족되었다고하며 항상 참입니다. Oracle Docs : 스트림 작업 및 파이프 라인

여기서 핵심은 본질적으로 다소 오해의 소지가있는 "진공 적으로 만족"한다는 것입니다. Wikipedia에는 ​​그것에 대해 적절한 토론이 있습니다.

순수 수학에서 막연하게 참된 진술은 일반적으로 그 자체로 흥미롭지는 않지만 수학적 귀납법에 의한 증명의 기본 사례로 자주 발생합니다. Wikipedia : 공허한 진실


1

이 질문에 이미 정확한 곱셈에 대한 답변이 있었지만 더 수학적 접근 방식을 도입하고 싶습니다.

이를 위해 스트림을 (수학적 의미에서) 세트로 간주하고 싶습니다. 그때

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

여기에 이미지 설명 입력while에 해당

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

에 해당합니다 여기에 이미지 설명 입력.

두 번째 부분이 거짓이라는 것은 빈 집합에 요소가 없기 때문에 매우 분명합니다. 첫 번째는 좀 더 까다 롭습니다. 정의에 따라 사실이라고 받아들이거나 그 이유 중 일부에 대해 다른 답변을 살펴볼 수 있습니다.

이 차이를 설명하는 예로는 "화성에 사는 모든 인간은 다리가 3 개 있습니다"(참) 및 "화성에 다리가 3 개있는 인간이 살고 있습니다"(거짓)와 같은 명제를들 수 있습니다.

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.