web-dev-qa-db-fra.com

Trouver le premier élément par prédicat

Je viens de commencer à jouer avec Java 8 lambdas et j'essaie d'implémenter certaines des choses auxquelles je suis habitué dans des langages fonctionnels.

Par exemple, la plupart des langages fonctionnels ont une sorte de fonction de recherche qui agit sur des séquences ou des listes qui renvoie le premier élément pour lequel le prédicat est true. La seule façon dont je peux voir cela dans Java 8 est la suivante:

lst.stream()
    .filter(x -> x > 5)
    .findFirst()

Cependant, cela me semble inefficace, car le filtre parcourra toute la liste, du moins à ma compréhension (ce qui pourrait être faux). Y a-t-il un meilleur moyen?

458
siki

Non, le filtre n'analyse pas l'intégralité du flux. C'est une opération intermédiaire qui renvoie un flux paresseux (en fait, toutes les opérations intermédiaires renvoient un flux paresseux). Pour vous convaincre, vous pouvez simplement faire le test suivant:

List<Integer> list = Arrays.asList(1, 10, 3, 7, 5);
int a = list.stream()
            .peek(num -> System.out.println("will filter " + num))
            .filter(x -> x > 5)
            .findFirst()
            .get();
System.out.println(a);

Quelles sorties:

will filter 1
will filter 10
10

Vous voyez que seuls les deux premiers éléments du flux sont réellement traités.

Donc, vous pouvez aller avec votre approche qui est parfaitement bien.

651
Alexis C.

Cependant, cela me semble inefficace, car le filtre va scanner toute la liste

Non, il ne le fera pas - il se "cassera" dès que le premier élément satisfaisant le prédicat sera trouvé. Vous pouvez en savoir plus sur la paresse dans le paquet de flux javadoc , en particulier (l'emphase mienne):

De nombreuses opérations de flux, telles que le filtrage, le mappage ou la suppression des doublons, peuvent être implémentées paresseusement, ouvrant ainsi des perspectives d'optimisation. Par exemple, "trouver la première chaîne avec trois voyelles consécutives" n'a pas besoin d'examiner toutes les chaînes d'entrée. Les opérations de flux sont divisées en opérations intermédiaires (production de flux) et opérations terminales (production de valeurs ou d'effets secondaires). Les opérations intermédiaires sont toujours paresseuses.

100
wha'eve'
return dataSource.getParkingLots().stream().filter(parkingLot -> Objects.equals(parkingLot.getId(), id)).findFirst().orElse(null);

Je devais filtrer un seul objet d'une liste d'objets. Donc j'ai utilisé ça, j'espère que ça aide.

30
CodeShadow

En plus de la réponse de Alexis C , utilisez ceci si vous utilisez une liste de tableaux dans laquelle vous ne savez pas si l'élément que vous recherchez existe.

Integer a = list.stream()
                .peek(num -> System.out.println("will filter " + num))
                .filter(x -> x > 5)
                .findFirst()
                .orElse(null);

Ensuite, vous pourriez simplement vérifier si un est null.

13
Ifesinachi Bryan

Si vous recherchez une valeur de retour booléenne, nous pouvons le faire mieux en ajoutant un contrôle nul:

return dataSource.getParkingLots().stream().filter(parkingLot -> Objects.equals(parkingLot.getId(), id)).findFirst().orElse(null) != null;
0
shreedhar bhat