web-dev-qa-db-fra.com

En Java8, comment définir la valeur globale dans le bloc lambdas foreach?

    public void test(){
       String x;
       List<String> list=Arrays.asList("a","b","c","d");

       list.forEach(n->{
          if(n.equals("d"))
            x="match the value";
       });
    }

1.Comme le code ci-dessus, je veux définir la valeur d'une variable à côté du bloc foreach, cela peut-il fonctionner?

Et pourquoi?

3.Et l'itérateur foreach est en ordre ou en désordre?

4.Je pense que le bloc lamdas foreach est cool et simple pour l'itérateur, mais c'est vraiment une chose compliquée à faire plutôt que le même travail en Java 7 ou avant.

27
MarsYoung

Vous pouvez, bien sûr, "rendre la valeur externe modifiable" via une astuce:

public void test() {
    String[] x = new String[1];
    List<String> list = Arrays.asList("a", "b", "c", "d");

    list.forEach(n -> {
        if (n.equals("d"))
            x[0] = "match the value";
    });
}

Préparez-vous à être battu par le puriste fonctionnel de l'équipe. Cependant, il est beaucoup plus agréable d'utiliser une approche plus fonctionnelle ( similaire à l'approche de Sleiman ):

public void test() {
    List<String> list = Arrays.asList("a", "b", "c", "d");
    String x = list.stream()
                   .filter("d"::equals)
                   .findAny()
                   .map(v -> "match the value")
                   .orElse(null);
}
23
Lukas Eder

En plus des exemples idiomatiques déjà fournis, un autre hack serait d'utiliser AtomicReference, mais je ne le recommanderais que si vous avez besoin de `` forEach '' et préférez quelque chose de plus lisible qu'une variante vraiment fonctionnelle:

public void test(){
    AtomicReference<String> x = new AtomicReference<>();
    List<String> list= Arrays.asList("a", "b", "c", "d");

    list.forEach(n->{
        if(n.equals("d"))
            x.set("match the value");
    });
}
9
Andrii Rubtsov
  1. Non, vous ne pouvez pas le faire. (Bien que vous auriez dû l'essayer vous-même)
  2. Parce que les variables utilisées dans les classes internes anonymes et l'expression lambda doivent être effectively final.
  3. vous pouvez obtenir le même résultat de manière plus concise en utilisant filter et map.

    Optional<String> d = list.stream()
                             .filter(c -> c.equals("d"))
                             .findFirst()
                             .map(c -> "match the value");
    
8
Sleiman Jneidi

Comme cela a déjà été expliqué, vous ne pouvez pas modifier la variable locale de la méthode externe à partir du corps lambda (ainsi qu'à partir du corps de classe anonyme). Mon conseil est de ne pas utiliser de lambdas lorsqu'ils sont complètement inutiles. Votre problème peut être résolu comme ceci:

public void test(){
   String x;
   List<String> list = Arrays.asList("a","b","c","d");
   if(list.contains("d"))
       x = "match the value";
}

En général, les lambdas sont des amis de la programmation fonctionnelle où vous avez rarement des variables mutables (chaque variable n'est affectée qu'une seule fois). Si vous utilisez des lambdas, mais continuez de penser de façon impérative, vous aurez toujours de tels problèmes.

6
Tagir Valeev