2016-04-06 8 views
2

Ich versuche, eine Liste mit anderen Streams zuzuordnen.Java8 streams map - prüfen, ob alle Kartenoperationen erfolgreich waren?

Einige Elemente der ursprünglichen Liste können nicht zugeordnet werden. Das heißt, die Zuordnungsfunktion ist möglicherweise nicht in der Lage, einen geeigneten neuen Wert zu finden.

Ich möchte wissen, wenn eine der Zuordnungen fehlgeschlagen ist. Idealerweise würde ich auch gerne die Verarbeitung stoppen, sobald ein Fehler passiert ist.

Was ich momentan tue, ist:

  • Die Funktionszuordnung gibt null, wenn kein zugeordneter Wert ist
  • I filter() zu entfernen nulls aus dem Strom
  • I collect() und dann
  • I Vergleichen Sie die Größe des Ergebnisses mit der Größe der ursprünglichen Liste.

Zum Beispiel:

List<String> func(List<String> old, Map<String, String> oldToNew) 
{ 
    List<String> holger = old.stream() 
          .map(oldToNew::get) 
          .filter(Objects::nonNull) 
          .collect(Collectors.toList); 

    if (holger.size() < old.size()) { 
     // ... appropriate error handling code ... 
    } 
    else { 
     return holger; 
    } 
} 

Dies ist nicht sehr elegant. Auch wird alles verarbeitet, auch wenn das Ganze scheitern sollte.

Vorschläge für eine bessere Vorgehensweise? Oder vielleicht sollte ich Streams zusammen abschrecken und gute alte Loops verwenden?

+1

Warum werfen Sie keine unchecked Ausnahme von 'oldToNew :: get', wenn das Ergebnis null ist, und fangen Sie es außerhalb? – Tunaki

+0

@Tunaki Danke, es ist eine Option. Ich weiß nicht, ob das entweder Eleganz oder Leistung verbessern würde (da Ausnahmen angeblich teuer sind). – daphshez

+0

Benenne deine Variable nicht "neu". Das wird nicht funktionieren ... Und was ist ein Rückgabetyp von 'void Liste ' soll bedeuten? – Holger

Antwort

0

Sie könnten Ihre Filter Objects::requireNonNull ändern und eine Nullpointer außerhalb des Stromes

+3

Catching 'NullPointerException' ist nie eine gute Idee. Ich würde das nicht empfehlen. – Tunaki

1

Es gibt keine beste Lösung zu fangen, weil das auf dem Anwendungsfall stark abhängt. Z.B. Wenn erwartet wird, dass Nachschlagefehler unwahrscheinlich sind oder die Fehlerbehandlung impliziert, dass ohnehin eine Ausnahme ausgelöst wird, ist das Auslösen einer Ausnahme bei der ersten fehlgeschlagenen Suche in der Zuordnungsfunktion möglicherweise eine gute Wahl. Dann muss sich kein Folgecode um die Fehlerbedingungen kümmern.

Ein andere Art des Umgangs es sein könnte:

List<String> func(List<String> old, Map<String, String> oldToNew) { 
    Map<Boolean,List<String>> map=old.stream() 
     .map(oldToNew::get) 
     .collect(Collectors.partitioningBy(Objects::nonNull)); 
    List<String> failed=map.get(false); 
    if(!failed.isEmpty()) 
     throw new IllegalStateException(failed.size()+" lookups failed"); 
    return map.get(true); 
} 

Dieser noch in Betracht gezogen werden kann für den erfolgreichen Fall optimiert, da es eine meist sinnlos Liste enthält null Werte für die Fehler sammelt. Aber es hat den Sinn, die Anzahl der Fehler zu erkennen (im Gegensatz zur Verwendung einer Wurfkartenfunktion).

Wenn eine detaillierte Fehleranalyse eine hohe Priorität hat, können Sie eine Lösung wie diese verwenden:

List<String> func(List<String> old, Map<String, String> oldToNew) { 
    Map<Boolean,List<String>> map=old.stream() 
     .map(s -> new AbstractMap.SimpleImmutableEntry<>(s, oldToNew.get(s))) 
     .collect(Collectors.partitioningBy(e -> e.getValue()!=null, 
      Collectors.mapping(e -> Optional.ofNullable(e.getValue()).orElse(e.getKey()), 
       Collectors.toList()))); 
    List<String> failed=map.get(false); 
    if(!failed.isEmpty()) 
     throw new IllegalStateException("The following key(s) failed: "+failed); 
    return map.get(true); 
} 

Es sammelt zwei sinnvolle Listen, die ausgefallenen Schlüssel für gescheiterte Lookups und eine Liste der erfolgreich kartiert Werte enthält. Beachten Sie, dass beide Listen zurückgegeben werden können.

Verwandte Themen