2015-03-24 10 views
5

Ich möchte verschachtelte Listen mit java8 streams iterieren und einige Ergebnisse der Listen bei der ersten Übereinstimmung extrahieren. Leider muss ich auch einen Wert vom übergeordneten Inhalt erhalten, wenn ein untergeordnetes Element dem Filter entspricht.Wie werden geschachtelte For-Schleifen, die sich auf Elternelemente beziehen, mit Java-8-Streams iteriert?

Wie könnte ich das tun?

// Java7

Result result = new Result(); 

//find first match and pupulate the result object. 
for (FirstNode first : response.getFirstNodes()) { 
    for (SndNode snd : first.getSndNodes()) { 
     if (snd.isValid()) { 
      result.setKey(first.getKey()); 
      result.setContent(snd.getContent()); 
      return; 
     } 
    } 
} 

// java8

response.getFirstNodes().stream() 
     .flatMap(first -> first.getSndNodes()) 
     .filter(snd -> snd.isValid()) 
     .findFirst() 
     .ifPresent(???); //cannot access snd.getContent() here 
+1

mögliche Duplikate von [Java 8 - Streams Verschachtelte ForEach mit unterschiedlicher Sammlung] (http://stackoverflow.com/questions/25357043/java-8-streams-nested-foreach-with-different-collection) –

Antwort

10

gefunden werden Wenn Sie beide Werte brauchen und wollen flatMap (je nach Bedarf, wenn Sie einen Kurzschlussbetrieb wie findFirst ausführen möchten) verwenden, Sie beide Werte abbilden müssen ein Objekt halten

Um nur Standardklassen zu verwenden, verwende ich einen Map.Entry als Paar-Typ, während ein echter Paar-Typ prägnanter aussehen könnte.

In diesem speziellen Anwendungsfall können Sie die Filteroperation mit dem inneren Strom

response.getFirstNodes().stream() 
    .flatMap(first->first.getSndNodes().stream() 
    .filter(snd->snd.isValid()) 
    .map(snd->new AbstractMap.SimpleImmutableEntry<>(first, snd))) 
    .findFirst().ifPresent(e-> { 
    result.setKey(e.getKey().getKey()); 
    result.setContent(e.getValue().getContent()); 
    }); 

bewegen, die die ordentliche Wirkung hat, die nur für den einen passenden Eintrag, eine Map.Entry Instanz (na ja, erstellt werden sollte als the current implementation is not as lazy as it should aber selbst dann wird es immer noch weniger Objekte als bei der ersten Variante erstellen).

+0

Danke für die Erklärung. Wenn ich auf deinen Code schaue, denke ich, dass es immer noch besser ist, sich an den java7 fashioned iteration style zu halten, für den Fall, dass auf multiple/parent Elemente zugegriffen werden muss. – membersound

+2

Ja, die guten alten 'for' Loops sind nicht veraltet. Vielleicht eröffnet eine zukünftige Java-Version mit Sprachunterstützung für Paare/Tupel die Möglichkeit für eine bessere Stream-Lösung ... – Holger

-1

es so sein sollte:

Edit: Danke Holger für den Hinweis auf, dass der Code nicht an der Haltestelle erste gültige FirstNode

response.getFirstNodes().stream() 
    .filter(it -> {it.getSndNodes().stream().filter(SndNode::isValid).findFirst(); return true;}) 
    .findFirst() 
    .ifPresent(first -> first.getSndNodes().stream().filter(SndNode::isValid).findFirst().ifPresent(snd -> { 
    result.setKey(first.getKey()); 
    result.setContent(snd.getContent()); 
    })); 

Ein Test kann here

+2

Dies doesn ' t mach nichts nützliches. Der ursprüngliche Code der Frage hieß 'result.setKey (first.getKey()); result.setContent (snd.getContent()); 'und die Verarbeitung nachfolgender Elemente gestoppt. Dein Code tut das nicht. – Holger

+0

Ich habe gezeigt, wie man auf 'sn.getContent()' innerhalb 'ifPresent()' zugreifen kann, habe jetzt den Code geändert – vsnyc

+0

@Holger kann ich die -1 abfragen, ich habe getestet, dass mein Code funktioniert und was die op beabsichtigt – vsnyc

Verwandte Themen