web-dev-qa-db-fra.com

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

Je suis un peu confus entre Stream#findAny() et Stream#findFirst() de l'API Stream en 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 conjointement avec le filtre.

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

51
Mandeep Rajpal

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

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

Retourne un Optional<T> décrivant un certain é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 choisir n'importe quel élément du flux. Ceci permet une performance maximale dans les opérations parallèles;

while Stream.findFirst() retournera un Optional<T> décrivant strictement le premier élément du flux. La classe Stream n'a pas de méthode .findOne(), alors je suppose que vous vouliez dire .findFirst().

59
Konstantin Yovkov

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

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

Retourne une Optional décrivant un élément du flux, ou une Optional vide si le flux est vide.

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

Le comportement de cette opération est explicitement non déterministe; _ {il est libre de choisir n'importe quel élément du flux} _. Cela permet une performance maximale dans les opérations parallèles; le coût est que plusieurs invocations sur la même source peuvent ne pas renvoyer le même résultat. (Si un résultat stable est souhaité, utilisez plutôt findFirst().)

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

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

33
Tunaki

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
3
Amir

en mode parallèle, la findAny ne garantit pas l'ordre, mais la findFirst le fait.

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

1
jiahut

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

Référence

Temps 1:25:00

0
emon

Je vais juste dire que méfiez-vous de findFirst() et findAny() lors de l'utilisation.

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

Supposons que nous ayons la coutume list composée de l'ISBN et du nom du livre. 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 identique 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é. Imaginez un scénario dans lequel 5 livres sont nommés "Référence Java" mais ont des numéros ISBN différents et findFirst() livre par nom aura 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 s'ils sont triés sur BookByName.

Article détaillé: 

0
Common Man