Différence entre findAny () et findFirst () dans Java 8

90

Je suis peu confus entre Stream#findAny()et Stream#findFirst()de l' StreamAPI dans Java 8.

Ce que j'ai compris, c'est que les deux renverront le premier élément correspondant du flux, par exemple, lorsqu'ils sont utilisés en conjonction avec le filtre?

Alors, pourquoi deux méthodes pour la même tâche? Est-ce que je manque quelque chose?

Mandeep Rajpal
la source

Réponses:

92

Ce que j'ai compris, c'est que les deux renverront le premier élément correspondant du flux, par exemple, lorsqu'ils sont utilisés en conjonction avec le filtre?

Ce n'est pas vrai. Selon le javadoc, Stream#findAny():

Renvoie un élément Optional<T>décrivant un élément du flux, ou un vide Optional<T>si le flux est vide. Le comportement de cette opération est explicitement non déterministe; il est libre de sélectionner n'importe quel élément du flux. Cela permet des performances maximales dans les opérations parallèles;

while Stream.findFirst()retournera une Optional<T>description strictement du premier élément du flux. La Streamclasse n'a pas de .findOne()méthode, donc je suppose que vous vouliez dire .findFirst().

Konstantin Yovkov
la source
Je ne comprends toujours pas, donc ce que vous dites est que même après l' filterapplication d'un, findAnypeut renvoyer n'importe quel élément, y compris celui qui ne correspond pas au filtre appliqué?
Koray Tugay
@KorayTugay - Non, après le filtre, quels que soient les éléments restants présents, findAnypeuvent renvoyer n'importe quel élément de celui-ci de manière (en quelque sorte) aléatoire, en particulier dans les opérations de flux parallèles
KrishPrabakar
46

Non, les deux ne renverront pas le premier élément du Stream.

De Stream.findAny()(c'est moi qui souligne):

Renvoie un élémentOptional décrivant un élément du flux, ou un vide Optionalsi le flux est vide.

Il s'agit d'une opération de borne de court-circuit.

Le comportement de cette opération est explicitement non déterministe; il est libre de sélectionner n'importe quel élément du flux . Cela permet des performances maximales dans les opérations parallèles; le coût est que plusieurs appels sur la même source peuvent ne pas renvoyer le même résultat. (Si un résultat stable est souhaité, utilisez à la findFirst()place.)

Donc, pour le dire plus simplement, il peut ou non choisir le premier élément du Stream.

Avec l'implémentation spécifique d'Oracle actuelle, je pense qu'elle renverra le premier élément d'un pipeline non parallèle. Cependant, dans un pipeline parallèle, ce ne sera pas toujours (exécuter par exemple System.out.println(IntStream.range(0, 100).parallel().findAny());, il est retourné OptionalInt[50]lorsque je l'ai exécuté). Quoi qu'il en soit, vous ne devez pas vous y fier.

Tunaki
la source
16

findFirst renvoie les premiers éléments du flux mais findAny est libre de sélectionner n'importe quel élément du flux.

List<String> lst1 = Arrays.asList("Jhonny", "David", "Jack", "Duke", "Jill","Dany","Julia","Jenish","Divya");
List<String> lst2 = Arrays.asList("Jhonny", "David", "Jack", "Duke", "Jill","Dany","Julia","Jenish","Divya");

Optional<String> findFirst = lst1.parallelStream().filter(s -> s.startsWith("D")).findFirst();
Optional<String> fidnAny = lst2.parallelStream().filter(s -> s.startsWith("J")).findAny();

System.out.println(findFirst.get()); //Always print David
System.out.println(fidnAny.get()); //Print Jack/Jill/Julia :behavior of this operation is explicitly nondeterministic
Amir
la source
1

en mode parallèle, l' findAnyordre ne garantit pas, mais le findFirstfait.

J'ai écrit un extrait de code pour montrer la différence, visitez-le

Jiahut
la source
1

Dans le flux findFirst et findAny retournent le premier élément et n'exécutent pas le reste mais dans parallelStream, il n'est pas passible de dire l'ordre et parallelStream exécute le reste de la collection.

Référence

Heure 1:25:00

emon
la source
1

Je dirai simplement que méfiez-vous de findFirst()Et findAny()lors de l'utilisation.

À partir de leur Javadoc ( ici et ici ), les deux méthodes renvoient un élément arbitraire du flux - à moins que le flux n'ait un ordre de rencontre , auquel cas findFirst()renvoie le premier élément tandis que findAny()retournera n'importe quel élément.

Supposons que nous ayons un listISBN et un nom de LIVRE personnalisés. Pour un scénario, regardez cet exemple:

public class Solution {
   private Integer ISBN;
   private String BookName;

public Solution(int i, String string) {
    ISBN =i;
    BookName = string;
}
//getters and setters
}

public static void main(String[] args) {
        List<Solution> Library = Arrays.asList(new Solution(12,"Java in Action"),new Solution(13,"Java 8"),new Solution(15,"Java 8 Features"),new Solution(16,"Java in Action"));
 System.out.println(Library.stream()
        .map(p->p.getBookName())
        .sorted(Comparator.reverseOrder())
        .findFirst());
    }

Sortie :Optional[Java in Action]

Il peut y avoir des scénarios où le nom du livre est le même mais les numéros ISBN sont différents, dans ce cas le tri et la recherche du livre peuvent être très similaires findAny()et donneront un résultat erroné. Pensez à un scénario où 5 livres sont nommés «Java Reference» mais ont des numéros ISBN différents et un findFirst()livre par nom donnera le même résultat que findAny().

Pensez à un scénario où:

 ISBN    Name Of book
+-----+------------------+
| 100 | Java-8 in Action |
+-----+------------------+
| 101 | Java-8 in Action |
+-----+------------------+
| 102 | Java-8 in Action |
+-----+------------------+
| 103 | Java-8 in Action |
+-----+------------------+
| 104 | Java-8 in Action |
+-----+------------------+

ici findFirst () et findAny () donneront le même résultat même si triés sur BookByName.

Article détaillé:

Vishwa Ratna
la source
-1

Quand Streamn'est pas ordonné, findFirst()et findAny()sont les mêmes. Mais quand Streamest commandé, ce findAny()sera mieux.

logbasex
la source
Ceci est une erreur. Aucune de ces méthodes n'est «meilleure», car leurs comportements et cas d'utilisation sont complètement différents. Aussi, qu'entendez-vous par un Streamêtre «ordonné»? Il est toujours ordonné (les opérations sont exécutées Streamdans le même ordre à chaque fois qu'il n'est pas parallélisé), mais peut-être pas triés par l'utilisateur.
Jezor