Wechseln Sie mit Java 8-Foreach-Schleife im Stream zum nächsten Element

Lesezeit: 4 Minuten

Benutzer-Avatar
Viktor M.

Ich habe ein Problem mit dem Stream von Java 8 foreach, der versucht, zum nächsten Element in der Schleife zu wechseln. Ich kann den Befehl nicht wie setzen continue;nur return; funktioniert, aber Sie verlassen die Schleife in diesem Fall. Ich muss zum nächsten Element in der Schleife übergehen. Wie kann ich das machen?

Beispiel (funktioniert nicht):

try(Stream<String> lines = Files.lines(path, StandardCharsets.ISO_8859_1)){
            filteredLines = lines.filter(...).foreach(line -> {
           ...
           if(...)
              continue; // this command doesn't working here
    });
}

Beispiel (funktioniert):

try(Stream<String> lines = Files.lines(path, StandardCharsets.ISO_8859_1)){
    filteredLines = lines.filter(...).collect(Collectors.toList());
}

for(String filteredLine : filteredLines){
   ...
   if(...)
      continue; // it's working!
}

  • Ich muss zum nächsten Element in der Schleife übergehen.

    – Viktor M.

    18. September 2015 um 14:54 Uhr

  • Sein Punkt ist, mit dem Code, den Sie gezeigt haben, das nicht zu haben continue würde trotzdem ohne funktionale Änderungen zum nächsten Punkt übergehen.

    – DoppeltDoppelt

    18. September 2015 um 14:55 Uhr


  • Wenn das Ziel darin besteht, die Ausführung von Zeilen zu vermeiden, die nach dem Aufruf zum Fortfahren kommen und die Sie uns nicht zeigen, fügen Sie einfach alle diese Zeilen in ein ein else Block. Wenn nichts danach kommt continuedann den if-Block und den Continue löschen: Sie sind nutzlos.

    – JB Nizet

    18. September 2015 um 15:02 Uhr


Benutzer-Avatar
Stan

Verwenden return; wird gut funktionieren. Es wird nicht verhindern, dass die vollständige Schleife abgeschlossen wird. Es wird nur die Ausführung der aktuellen Iteration von stoppen forEach Schleife.

Probieren Sie das folgende kleine Programm aus:

public static void main(String[] args) {
    ArrayList<String> stringList = new ArrayList<>();
    stringList.add("a");
    stringList.add("b");
    stringList.add("c");

    stringList.stream().forEach(str -> {
        if (str.equals("b")) return; // only skips this iteration.

        System.out.println(str);
    });
}

Ausgabe:

a
c

Beachten Sie, wie die return; wird für die ausgeführt b Iteration, aber c druckt auf der folgenden Iteration ganz gut.

Warum funktioniert das?

Der Grund, warum das Verhalten zunächst unintuitiv erscheint, liegt darin, dass wir daran gewöhnt sind return Anweisung, die die Ausführung der gesamten Methode unterbricht. In diesem Fall erwarten wir also die main Methodenausführung als Ganzes angehalten werden.

Was jedoch verstanden werden muss, ist, dass ein Lambda-Ausdruck, wie zum Beispiel:

str -> {
    if (str.equals("b")) return;

    System.out.println(str);
}

… muss wirklich als eigene “Methode” betrachtet werden, völlig getrennt von der main Methode, obwohl es sich bequem darin befindet. Also wirklich, die return -Anweisung hält nur die Ausführung des Lambda-Ausdrucks an.

Die zweite Sache, die verstanden werden muss, ist Folgendes:

stringList.stream().forEach()

… ist wirklich nur eine normale Schleife unter der Decke, die den Lambda-Ausdruck für jede Iteration ausführt.

Unter Berücksichtigung dieser 2 Punkte kann der obige Code auf die folgende äquivalente Weise umgeschrieben werden (nur für Bildungszwecke):

public static void main(String[] args) {
    ArrayList<String> stringList = new ArrayList<>();
    stringList.add("a");
    stringList.add("b");
    stringList.add("c");

    for(String s : stringList) {
        lambdaExpressionEquivalent(s);
    }
}

private static void lambdaExpressionEquivalent(String str) {
    if (str.equals("b")) {
        return;
    }

    System.out.println(str);
}

Mit diesem „weniger magischen“ Code-Äquivalent wird der Umfang der return Aussage wird deutlicher.

Eine andere Lösung: Gehen Sie durch einen Filter mit Ihren invertierten Bedingungen: Beispiel:

if(subscribtion.isOnce() && subscribtion.isCalled()){
                continue;
}

kann ersetzt werden durch

.filter(s -> !(s.isOnce() && s.isCalled()))

Der einfachste Ansatz scheint die Verwendung von “return;” zu sein. obwohl.

Das Lambda, zu dem Sie übergehen forEach() wird für jedes aus dem Stream empfangene Element ausgewertet. Die Iteration selbst ist innerhalb des Lambda-Bereichs nicht sichtbar, also können Sie das nicht continue es als ob forEach() waren ein C-Präprozessor-Makro. Stattdessen können Sie die restlichen Anweisungen darin bedingt überspringen.

Sie können eine einfache verwenden if Anweisung statt fortzusetzen. Anstelle der Art und Weise, wie Sie Ihren Code haben, können Sie Folgendes versuchen:

try(Stream<String> lines = Files.lines(path, StandardCharsets.ISO_8859_1)){
            filteredLines = lines.filter(...).foreach(line -> {
           ...
           if(!...) {
              // Code you want to run
           }
           // Once the code runs, it will continue anyway
    });
}

Das Prädikat in der if-Anweisung ist genau das Gegenteil des Prädikats in Ihrer if(pred) continue; Anweisung, also einfach verwenden ! (logisch nicht).

1352910cookie-checkWechseln Sie mit Java 8-Foreach-Schleife im Stream zum nächsten Element

This website is using cookies to improve the user-friendliness. You agree by using the website further.

Privacy policy