web-dev-qa-db-fra.com

Court-circuit de flux Java 8

En lisant un peu sur Java 8, je suis arrivé à this post de blog expliquant un peu à propos des flux et de leur réduction, et quand il serait possible de court-circuiter la réduction. En bas, il est écrit:

Notez que dans le cas de findFirst ou findAny, nous avons uniquement besoin de la première valeur qui correspond au prédicat (bien que findAny ne renvoie pas la première). Cependant, si le flux n’a pas de classement, nous nous attendons à ce que findFirst se comporte comme findAny. Les opérations allMatch, noneMatch et anyMatch peuvent ne pas court-circuiter le flux, car il peut être nécessaire d'évaluer toutes les valeurs pour déterminer si l'opérateur est true ou false. Ainsi, un flux infini utilisant ceux-ci ne peut pas se terminer.

Je comprends que findFirst ou findAny peut court-circuiter la réduction, car dès que vous trouvez un élément, vous n'avez plus besoin de traiter.

Mais pourquoi cela ne serait-il pas possible pour allMatch, noneMatch et anyMatch? Pour allMatch, si vous en trouvez un qui ne correspond pas au prédicat, vous pouvez arrêter le traitement. Idem pour aucun. Et anyMatch surtout n’a pas de sens pour moi, car il est à peu près égal à findAny (à l’exception de ce qui est renvoyé)?

Dire que ces trois ne peuvent pas court-circuiter, car il faudra peut-être évaluer toutes les valeurs, pourrait aussi être dit pour findFirst/Any.

Y a-t-il une différence fondamentale qui me manque? Est-ce que je ne comprends pas vraiment ce qui se passe?

17
Koekje

Il y a une différence subtile, car la famille anyMatch utilise un prédicat, contrairement à la famille findAny. Techniquement, findAny() ressemble à anyMatch(x -> true) et anyMatch(pred) à filter(pred).findAny(). Nous avons donc un autre problème. Considérons que nous avons un flux infini simple:

Stream<Integer> s = Stream.generate(() -> 1);

Il est donc vrai que l'application de findAny() à un tel flux sera toujours court-circuitée et se terminera lors de l'application de anyMatch(pred) dépend du prédicat. Cependant, filtrons notre flux infini:

Stream<Integer> s = Stream.generate(() -> 1).filter(x -> x < 0);

Le flux résultant est-il également infini? C'est une question délicate. En réalité, il ne contient aucun élément, mais pour le déterminer (par exemple, en utilisant .iterator().hasNext()), nous devons vérifier le nombre infini d'éléments de flux sous-jacents afin que cette opération ne se termine jamais. J'appellerais aussi un tel flux un infini. Cependant, l'utilisation de ce flux anyMatch et findAny ne se terminera jamais:

Stream.generate(() -> 1).filter(x -> x < 0).anyMatch(x -> true);
Stream.generate(() -> 1).filter(x -> x < 0).findAny();

Donc, il n'est pas garanti que findAny() se termine non plus, cela dépend des opérations de flux intermédiaires précédentes.

Pour conclure, je dirais que ce post sur le blog est très trompeur. À mon avis, le comportement du flux infini est mieux expliqué dans JavaDoc officiel.

18
Tagir Valeev

Réponse mise à jour

Je dirais que l'article de blog est faux lorsqu'il dit "findFirst ou findAny, nous n'avons besoin que de la première valeur qui correspond au prédicat".

Dans le javadoc pour allMatch (Predicate) , anyMatch (Predicate) , noneMatch (Predicate) , findAny () , et findFirst () :

Ceci est une opération de terminal en court-circuit.

Toutefois, notez que findFirst et findAny ne possède pas Predicate. Ainsi, ils peuvent tous les deux revenir immédiatement après avoir vu la première/n'importe quelle valeur. Les 3 autres sont conditionnels et peuvent boucler indéfiniment si la condition ne se déclenche jamais.

5
Andreas

Selon la documentation de flux d'Oracle: https://docs.Oracle.com/javase/8/docs/api/Java/util/stream/package-summary.html#StreamOps

Une opération de terminal est en court-circuit si, lorsqu'elle est présentée avec une entrée infinie, elle peut se terminer en temps fini. Une opération de court-circuit dans le pipeline est une condition nécessaire, mais non suffisante, pour que le traitement d'un flux infini se termine normalement en un temps fini.

Les cinq fonctions ont la ligne:

Ceci est une opération de terminal en court-circuit.

Dans la description de la fonction.

2
WillShackleford

Lorsque le javadoc indique "ne peut pas court-circuiter", il indique simplement qu'il ne s'agit pas d'un court-circuit et, en fonction des valeurs, le flux complet peut être traité.

findFirst et findAny, en revanche, sont garantis de court-circuit car ils n'ont jamais besoin de traiter le reste du flux une fois qu'ils sont satisfaits.

1
Trevor Freeman

anyMatch, noneMatch et allMatch renvoient des valeurs booléennes, de sorte qu'ils doivent peut-être tout vérifier pour prouver la logique.

findFirst et findAny se soucient simplement de trouver le premier possible et de le restituer.

Edition: pour un ensemble de données donné, il est garanti que les méthodes de correspondance renvoient toujours la même valeur, mais les méthodes de recherche ne le sont pas car leur ordre peut varier et avoir une incidence sur la valeur renvoyée.

Le court-circuit décrit décrit les méthodes de recherche manquant de cohérence pour un ensemble de données donné.

0
Jaeger Kor