Pourquoi ne Stream.allMatch() renvoie true pour un vide stream?
Mon collègue et j'ai eu un bug qui était dû à notre hypothèse selon laquelle un vide de flux d'appel allMatch()
serait de retour false
.
if (myItems.allMatch(i -> i.isValid()) {
//do something
}
Bien sûr, il est une sorte de notre faute de prise en charge et de ne pas lire de la documentation. Mais ce que je ne comprends pas, c'est pourquoi la valeur par défaut allMatch()
comportement pour un vide de flux retours true
. Quel a été le raisonnement pour cela? Comme le anyMatch()
(qui contrairement renvoie false), cette opération est utilisée de manière impérative qui s'écarte de la monade et probablement utilisé dans un if
déclaration. Compte tenu de ces faits, est-il une raison pourquoi avoir allMatch()
par défaut pour true
sur un vide stream être souhaitable pour la majorité des usages?
- C'est un peu bizarre. Nous nous attendons à ce que si
allMatch
retourne true alors devraitanyMatch
. En outre, pour la vides cas,allMatch(...) == noneMatch(...)
qui est aussi bizarre. - Wikipédia dit que c'est la convention: en.wikipedia.org/wiki/Universal_quantification#The_empty_set
- Juste un petit aparté sur la syntaxe: au lieu d'écrire votre prédicat
i -> i.isValid()
, vous pouvez écrireFoo::isValid
(oùFoo
est quelle classe vous êtes en streaming, bien sûr) - "Cette opération est utilisée de manière impérative qui s'écarte de la monade" - je doute que ces facteurs dans toute décision.
Vous devez vous connecter pour publier un commentaire.
Ceci est connu comme vides de sens, de vérité. Tous les membres d'un regroupement vide satisfaire votre condition; après tout, pouvez-vous point à un autre qui ne l'est pas? De même,
anyMatch
renvoie la valeur false, parce que vous ne pouvez pas trouver un élément de votre collection qui ne correspond pas à l'état. Ceci est source de confusion pour beaucoup de gens, mais il s'avère être le plus utile et de manière cohérente pour définir "tout" et "tous" pour vide ensembles.1
tandis que la somme d'un ensemble vide de nombres est0
. Ils sont les éléments neutres pour la multiplication ou l'addition. Dans le cas de booléens-vous queTrue and x = x
etFalse or x = x
donc si vous généralisezand
etor
de séquences (c'est ce queall
etany
sont), vous vous retrouvez avecTrue
etFalse
pour le caisson vide, c'est à dire qu'ils respectifs éléments neutres.allMatch
tests pour l'absence de négatifs.Quand je l'appelle
list.allMatch
(ou de ses analogues dans d'autres langues), je veux détecter si tous les éléments delist
ne correspond pas aux prédicat. Si il n'y aucun élément, aucun pourrait ne pas correspondre. Mon suivant la logique de choisir des articles et s'attendent à avoir égalé le prédicat. Si la liste est vide, je vais prendre aucun des éléments et de la logique sera toujours le son.Que si
allMatch
retournéfalse
pour une liste vide?Mon simple logique serait un échec:
Je vais avoir besoin de vous rappeler de remplacer le chèque avec
!myList.empty() && !myList.allMatch()
.En bref,
allMatch
retourtrue
pour une liste vide n'est pas seulement logiquement son, il se trouve aussi sur la bonne chemin d'exécution, nécessitant moins de contrôles.if (!allMatch)
Voici une autre façon de penser à ce sujet:
allMatch()
est à&&
cesum()
est à+
Envisager la suite logique des énoncés:
Ce sens, car
sum()
est juste une généralisation de+
. Cependant, qu'advient-il lorsque vous supprimez un élément de plus?Nous pouvons voir qu'il est logique de définir
IntStream.of().sum()
, ou la somme d'une séquence vide de nombres, d'une manière particulière. Cela nous donne l'identité "élément" de la sommation, ou la valeur qui s'ajoute à quelque chose, n'a pas d'effet (0
).Nous pouvons appliquer la même logique à
Boolean
algèbre.De manière plus générale:
Si
stream = Stream.of()
ensuite, cette règle doit s'appliquer. On peut utiliser l'identité "élément" de && de résoudre ce problème.true && thing == thing
, doncStream.of().allMatch(it -> it) == true
.Il ressemble à la base, c'est l'induction mathématique. Pour l'informatique, une application de ce qui pourrait être une base de cas d'un algorithme récursif.
La clé ici est qu'il est "vacuously satisfaits" qui, par nature, est quelque peu trompeur. Wikipedia a une bonne discussion à ce sujet.