Mój kolega i ja mieliśmy błąd, który wynikał z naszego założenia, że wywołanie pustego strumienia allMatch()
powróci false
.
if (myItems.allMatch(i -> i.isValid()) {
//do something
}
Oczywiście to trochę nasza wina, że przyjmujemy i nie czytamy dokumentacji. Ale nie rozumiem, dlaczego allMatch()
powraca domyślne zachowanie pustego strumienia true
. Jaki był tego powód? Podobnie jak anyMatch()
(które odwrotnie zwraca false), operacja ta jest używana w sposób imperatywny, który odchodzi od monady i prawdopodobnie jest używany w if
instrukcji. Biorąc pod uwagę te fakty, czy jest jakikolwiek powód, dla którego allMatch()
domyślne ustawienie true
pustego strumienia byłoby pożądane w większości zastosowań?
allMatch
zwraca prawdę, to powinnoanyMatch
. Dodatkowo dla pustej obudowy,allMatch(...) == noneMatch(...)
co też jest dziwne.i -> i.isValid()
, możesz pisaćFoo::isValid
(Foo
oczywiście gdzie jest klasa, którą przesyłasz strumieniowo)Odpowiedzi:
Jest to znane jako pusta prawda . Wszyscy członkowie pustej kolekcji spełniają twój warunek; w końcu czy możesz wskazać taki, który tego nie robi?
Podobnie
anyMatch
zwracafalse
, ponieważ nie możesz znaleźć elementu swojej kolekcji, który nie spełnia warunku. Dla wielu osób jest to mylące, ale okazuje się, że jest to najbardziej użyteczny i spójny sposób definiowania „dowolnych” i „wszystkich” dla pustych zestawów.źródło
1
podczas gdy suma pustego zbioru liczb wynosi0
. Są neutralnymi elementami do mnożenia / dodawania. W przypadku booleanów masz toTrue and x = x
iFalse or x = x
dlatego jeśli uogólniaszand
ior
na sekwencje (to jest toall
iany
są), kończysz zTrue
iFalse
dla pustego przypadku, tj. Odpowiadają one elementom neutralnym.anyMatch
testy na brak pozytywów,allMatch
testy na brak negatywów.Oto inny sposób myślenia o tym:
allMatch()
jest do&&
tego, cosum()
jest+
Rozważ następujące logiczne stwierdzenia:
IntStream.of(1, 2).sum() + 3 == IntStream.of(1, 2, 3).sum() IntStream.of(1).sum() + 2 == IntStream.of(1, 2).sum()
Ma to sens, ponieważ
sum()
jest to tylko uogólnienie+
. Co się jednak stanie, gdy usuniesz jeszcze jeden element?IntStream.of().sum() + 1 == IntStream.of(1).sum()
Widzimy, że sensowne jest zdefiniowanie
IntStream.of().sum()
, czyli suma pustego ciągu liczb, w określony sposób. Daje nam to „element tożsamości” sumowania, czyli wartość, która po dodaniu do czegoś nie ma żadnego efektu (0
).Możemy zastosować tę samą logikę do
Boolean
algebry.Stream.of(true, true).allMatch(it -> it) == Stream.of(true).allMatch(it -> it) && true
Bardziej ogólnie:
Jeśli
stream = Stream.of()
wtedy ta zasada nadal musi obowiązywać. Aby rozwiązać ten problem, możemy użyć „elementu tożsamości” funkcji &&.true && thing == thing
więcStream.of().allMatch(it -> it) == true
.źródło
Kiedy dzwonię
list.allMatch
(lub jego odpowiedniki w innych językach), chcę wykryć, czy jakiekolwiek elementylist
nie są zgodne z predykatem. Jeśli nie ma żadnych elementów, żaden może nie pasować. Moja następująca logika polegałaby na wybieraniu elementów i oczekiwaniu, że pasują do predykatu. W przypadku pustej listy nie wybiorę żadnych elementów, a logika będzie nadal działać.A co, jeśli
allMatch
wróciszfalse
z powodu pustej listy?Moja prosta logika zawiodłaby:
if (!myList.allMatch(predicate)) { throw new InvalidDataException("Some of the items failed to match!"); } for (Item item : myList) { ... }
Muszę pamiętać, żeby wymienić czek na
!myList.empty() && !myList.allMatch()
.Krótko mówiąc,
allMatch
powróttrue
do pustej listy jest nie tylko logicznie uzasadniony, ale leży również na szczęśliwej ścieżce wykonania, wymagającej mniejszej liczby kontroli.źródło
if (!allMatch)
Wygląda na to, że podstawą tego jest indukcja matematyczna. W przypadku informatyki zastosowanie tego mogłoby być przypadkiem bazowym algorytmu rekurencyjnego.
Kluczowe jest tutaj to, że jest on „bezmyślnie zadowolony”, co z natury jest nieco mylące. Wikipedia ma o tym porządną dyskusję.
źródło
Chociaż na to pytanie udzielono już poprawnej odpowiedzi, pomnożyć, chcę wprowadzić bardziej matematyczne podejście.
W tym celu chcę potraktować strumień jako zbiór (w sensie matematycznym). Następnie
odpowiada while
odpowiada .
To, że druga część jest fałszywa, jest dość oczywiste, ponieważ w pustym zestawie nie ma elementów. Pierwsza jest nieco bardziej skomplikowana. Możesz zaakceptować to jako prawdę z definicji lub spojrzeć na inne odpowiedzi z kilku powodów, dla których tak powinno być.
Przykładem ilustrującym tę różnicę są twierdzenia typu „Wszyscy ludzie żyjący na Marsie mają 3 nogi” (prawda) i „Na Marsie żyje człowiek z 3 nogami” (fałsz)
źródło