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?
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()
.
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 uneOptional
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.
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
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
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.
Temps 1:25:00
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.