2015-03-20 2 views
5

Ich bin für eine saubere Art und Weise der Suche komplexe logische Bedingungen mit if und else Aussagen zu übersetzen, dass führen zu unterschiedlichen Aktionen, in Lambdas und Bäche.Übersetzen komplexe bedingte Logik in einer Schleife in Bäche und lambda

Angenommen, ich habe diesen Code:

List<OuterData> result = new LinkedList<>(); 

for (Outer outer : getOutersFromSomewhere()) { 
    OuterData outerData = new OuterData(); 

    if (outer.isImportant()) { 
     doImportantAction(outer, outerData); 
    } else if (outer.isTrivial()) { 
     doTrivialAction(outer, outerData); 
    } else { 
     doDefaultAction(outer, outerData); 
    } 

    for (Inner inner : outer.getInners()) { 
     if (inner.mustBeIncluded()) { 
      InnerData innerData = new InnerData(); 

      if (inner.meetsCondition1()) { 
       doAction1(inner, innerData, outer, outerData); 
      } else if (inner.meetsCondition2()) { 
       doAction2(inner, innerData, outer, outerData); 
      } else { 
       doDefaultAction(inner, innerData, outer, outerData); 
      } 
      outerData.add(innerData); 
     } 
    } 
    result.add(outerData); 
} 

return result; 

Diese von echtem Code vereinfacht die ich habe. Ich weiß, dass es optimiert und neu strukturiert werden kann, d. H. Ich könnte das innere for zu einem private-Verfahren bewegen. Ich würde gerne wissen, wie man die if, else if und else Teile zu Streams und Lambda übersetzt.

Ich kann das Skelett dieses Beispiels übersetzen. Ich würde List.stream(), Stream.map(), Stream.filter(), Stream.collect() und Stream.peek() verwenden. Mein Problem ist nur mit bedingten Verzweigungen. Wie kann ich diese Übersetzung machen?

+2

Möglicherweise könnten Sie den Code in Ihrem Beispiel vereinfachen. –

+0

@RaulGuiu OK, ich werde das tun. Danke –

+1

Ich denke, dass Sie ein paar verschiedene Filter mit den if-Bedingungen und eine foreach mit dem Körper des if verwenden könnten. –

Antwort

5

Eine erste offensichtliche Möglichkeit besteht darin, Ihre Elemente zu streamen, sie nach den erforderlichen Kriterien zu filtern und dann die Aktion auf jedes verbleibende Element anzuwenden. Dies macht auch den Code viel sauberer:

List<Outer> outers = getOutersFromSomewhere(); 
outers.stream().filter(Outer::isImportant) 
    .forEach(outer -> doImportantAction(outer, outerDate)); 
outers.stream().filter(Outer::isTrivial) 
    .forEach(outer -> doTrivialAction(outer, outerDate)); 
// default action analog 

Vorsicht: Dies funktioniert nur, wenn die wichtig, die trivial, und die Standardelemente bilden eine Partition. Ansonsten entspricht es nicht Ihrer if-else-Struktur. Aber vielleicht ist das sowieso beabsichtigt ...

Das Hauptproblem bei diesem Ansatz: Es ist nicht sehr gut OOP. Sie fragen die Objekte ab, um eine Entscheidung zu treffen. Aber OOP sollte so viel wie möglich "sagen, nicht fragen".

So ist eine andere Lösung, die eine aufwändige Methode in Ihrer Outer-Klasse zu bieten:

public class Outer { 
    ... 
    public void act(OuterData data, Consumer<Outer> importantAction, 
      Consumer<Outer> trivialAction, Consumer<Outer> defaultAction) { 
     if (isImportant()) 
      importantAction.accept(this, data); 
     else if (isTrivial()) 
      trivialAction.accept(this, data); 
     else 
      defaultAction.accept(this, data); 
    } 
} 

Jetzt haben Sie es so einfach wie diese nennen:

List<Outer> outers = getOutersFromSomewhere(); 
outers.forEach(outer -> outer.act(...)); // place consumers here (lambdas) 

Dies hat einen klaren Vorteil: Wenn Sie jemals muss ein Feature zu Ihrer Outer Klasse hinzufügen - sagen wir isComplex() - Sie müssen nur die Interna dieser einzelnen Klasse ändern (und vielleicht den Compilerfehler in anderen Teilen auflösen). Oder Sie können diese Funktion rückwärtskompatibel hinzufügen.

Die gleichen Regeln können auf die Klasse Inner und die Iteration angewendet werden.

Verwandte Themen