web-dev-qa-db-fra.com

Retourne de lambda pourEach () dans java

J'essaie de changer certaines boucles for-each en méthodes lambda forEach()- pour découvrir les possibilités des expressions lambda. La suite semble être possible:

ArrayList<Player> playersOfTeam = new ArrayList<Player>();      
for (Player player : players) {
    if (player.getTeam().equals(teamName)) {
        playersOfTeam.add(player);
    }
}

Avec lambda forEach()

players.forEach(player->{if (player.getTeam().equals(teamName)) {playersOfTeam.add(player);}});

Mais le suivant ne fonctionne pas:

for (Player player : players) {
    if (player.getName().contains(name)) {
        return player;
    }
}

avec lambda

players.forEach(player->{if (player.getName().contains(name)) {return player;}});

Y a-t-il un problème dans la syntaxe de la dernière ligne ou est-il impossible de renvoyer depuis la méthode forEach()?

72
samutamm

La return il retourne à partir de l'expression lambda plutôt que de la méthode contenant. Au lieu de forEach vous devez filter le flux:

players.stream().filter(player -> player.getName().contains(name))
       .findFirst().orElse(null);

Ici, filter limite le flux aux éléments correspondant au prédicat, et findFirst renvoie alors un Optional avec la première entrée correspondante.

Cela semble moins efficace que l'approche par boucle, mais en fait, findFirst() peut court-circuiter - il ne génère pas l'intégralité du flux filtré et n'en extrait ensuite un élément, mais il filtre uniquement le nombre d'éléments doit pour trouver le premier correspondant. Vous pouvez également utiliser findAny() au lieu de findFirst() si vous ne vous souciez pas nécessairement d'obtenir le joueur premier correspondant du flux (commandé), mais simplement tout élément correspondant. Cela permet une meilleure efficacité en cas de parallélisme.

97
Ian Roberts

Je vous suggère d’essayer d’abord de comprendre Java 8 dans son ensemble, le plus important dans votre cas ce seront les flux, les lambdas et les références de méthodes.

Vous devriez ne jamais convertir le code existant en code Java 8 sur une base ligne par ligne, vous devez extraire les entités et les convertir .

Ce que j'ai identifié dans votre premier cas est le suivant:

  • Vous souhaitez ajouter des éléments d'une structure d'entrée à une liste de sortie s'ils correspondent à un prédicat.

Voyons comment nous faisons cela, nous pouvons le faire avec ce qui suit:

List<Player> playersOfTeam = players.stream()
    .filter(player -> player.getTeam().equals(teamName))
    .collect(Collectors.toList());

Ce que vous faites ici est:

  1. Transformez votre structure d’entrée en un flux (je suppose ici qu’il est de type Collection<Player>, vous avez maintenant un Stream<Player>.
  2. Filtrez tous les éléments indésirables avec un Predicate<Player>, en mappant chaque joueur sur le booléen true si vous souhaitez le conserver.
  3. Rassembler les éléments résultants dans une liste, via un Collector, nous pouvons utiliser ici l'un des collecteurs de bibliothèque standard, qui est Collectors.toList().

Cela intègre également deux autres points:

  1. Code contre interfaces, donc code contre List<E> sur ArrayList<E>.
  2. Utilisez l’inférence diamant pour le paramètre type dans new ArrayList<>(), vous utilisez Java 8 après tout.

Passons maintenant à votre deuxième point:

Vous voulez encore une fois convertir quelque chose d'héritage Java en Java 8 sans regarder l'image plus grande. @ IanRoberts a déjà répondu à cette partie, bien que je pense que vous devez faire players.stream().filter(...)... au-dessus de ce qu'il a suggéré.

11
skiwi

Si vous voulez renvoyer une valeur booléenne, vous pouvez utiliser quelque chose comme ceci (beaucoup plus rapidement que filter):

players.stream().anyMatch(player -> player.getName().contains(name));
4
Sriram

C'est ce qui m'a aidé:

List<RepositoryFile> fileList = response.getRepositoryFileList();
RepositoryFile file1 = fileList.stream().filter(f -> f.getName().contains("my-file.txt")).findFirst().orElse(null);

Extrait de Java 8 Recherche d'un élément spécifique dans la liste avec Lambda

4
user5495300