webentwicklung-frage-antwort-db.com.de

So erstellen Sie eine Java 8 Stream-Karte kontinuierlich mit Nullprüfung

Ich habe diesen Code

Coverage mainCoverage = illus.getLifes().stream()
    .filter(Life::isIsmain)
    .findFirst()
    .orElseThrow(() -> new ServiceInvalidAgurmentGeneraliException(env.getProperty("MSG_002")))
    .getCoverages()  
    .stream() // <==may cause null here if list coverage is null
    .filter(Coverage::isMainplan)
    .findFirst()
    .orElseThrow(() -> new ServiceInvalidAgurmentGeneraliException(env.getProperty("MSG_002")));

das ist total gut, aber ich denke, es ist ein bisschen chaotisch und deckt nicht den ganzen null pointer exception ab (siehe Kommentar).

Ich versuche, diesen Code in umzuwandeln

Coverage mainCoverage1 = illus.getLifes().stream()
    .filter(Life::isIsmain)
    .map(Life::getCoverages)
    .filter(Coverage::isMainplan) //<== cannot filter from list coverage to one main coverage
    ...

Nachdem ich das Leben der Berichterstattung zugeordnet habe, scheint es keine Liste mehr zu sein. Die Frage ist also, wie ich den ersten Abschnitt in null safe umwandeln und vielleicht kürzen kann?

8
Dang Nguyen

Life::getCoverages gibt eine Sammlung zurück, daher funktioniert der Filter Coverage::isMainplan nicht. Stattdessen sollten Sie flatMap die nach .map(Life::getCoverages) zurückgegebenen Sequenzen verwenden und dann die filter-Operation auf Coverage anwenden:

Coverage mainCoverage = 
          illus.getLifes()
               .stream()
               .filter(Life::isIsmain)               
               .map(Life::getCoverages)
               //.filter(Objects::nonNull) uncomment if there can be null lists
               .flatMap(Collection::stream) // <--- collapse the nested sequences
               //.filter(Objects::nonNull) // uncomment if there can be null Coverage
               .filter(Coverage::isMainplan)
               .findFirst().orElse(...);

Ich habe ein paar Dinge zu Ihrem Code hinzugefügt:

  1. Ich habe .filter(Objects::nonNull) after .map(Life::getCoverages) hinzugefügt, das Sie unkommentieren können, wenn die zurückgegebenen Elemente möglicherweise null sind.
  2. Ich habe .flatMap(Collection::stream) hinzugefügt, das einen Stream zurückgibt, der aus den Ergebnissen des Ersetzens jedes Elements dieses Streams durch den Inhalt eines zugeordneten Streams besteht, der durch Anwenden der bereitgestellten Zuordnungsfunktion auf jedes Element erzeugt wird. 
  3. Ich habe ein weiteres .filter(Objects::nonNull) hinzugefügt, das Sie auskommentieren können, wenn die nach flatMap zurückgegebenen Elemente möglicherweise null sind.
  4. Wir befinden uns dann in einem Stadium, in dem wir .filter(Coverage::isMainplan) anwenden können und schließlich das erste Objekt abrufen, das die Kriterien erfüllt, über findFirst. Falls keines vorhanden ist, geben Sie einen Standardwert über orElse an.

Ich würde empfehlen, sich die folgenden Blogs anzusehen, um sich mit der flatMap-Methode vertraut zu machen:

4
Aomine

Fügen Sie in filter eine Bedingung hinzu. Wenn die Liste nicht null ist und i.isIsmain dann nur filtern, können Sie public static boolean isNull(Object obj) oder public static boolean nonNull(Object obj) verwenden

Coverage mainCoverage = illus.getLifes().stream()
.filter(i->i.isIsmain && Objects.nonNull(i.getCoverages()))
.findFirst()
.orElseThrow(() -> new ServiceInvalidAgurmentGeneraliException(env.getProperty("MSG_002")))
.getCoverages()  
.stream() // <==may cause null here if list coverage is null
.filter(Coverage::isMainplan)
.findFirst()
.orElseThrow(() -> new ServiceInvalidAgurmentGeneraliException(env.getProperty("MSG_002")));
3
Deadpool

Im ersten Teil Ihres Codes können Sie eine filter(e -> e != null) eingeben, um sich zu vergewissern, dass die List null ist, um keine NPE zu werfen:

Coverage mainCoverage = illus.getLifes().stream()
         .filter(Life::isIsmain)
         .findFirst()
         .orElseThrow(() -> new ServiceInvalidAgurmentGeneraliException(env.getProperty("MSG_002")))
         .getCoverages()  
         .filter(e -> e != null) //<=== Filter out all null values
         .stream()
         .filter(Coverage::isMainplan)
         .findFirst()
         .orElseThrow(() -> new ServiceInvalidAgurmentGeneraliException(env.getProperty("MSG_002"))

Das Problem mit Ihrem zweiten Code-Snippet ist, dass ich davon ausgehe, dass Life::getCoverages eine Collection zurückgibt, keine einzelnen Coverage-Objekte. Daher können Sie Coverage::isMainplan nicht aufrufen

2
GBlodgett

Das Beispiel, das Sie gegeben haben, und die Antworten, die hier dafür gegeben wurden, brechen einige Prinzipien der sauberen funktionalen Stilcodierung.

Erstens sollten Sie Terminalaktionen nicht mischen und Streams in derselben Code-Kette/-Pipeline erneut erstellen. Wie in Ihrem Beispiel stream (). FindFirst (). OrElseThrow (..). Stream (). OtherActions. Es ist wirklich keine gute Übung und fehleranfällig. Im Idealfall sollte eine Kette von Java Stream-API-Aufrufen mit einem einzelnen Stream funktionieren. Auf diese Weise ist es einfacher, Ihren Code nachzuvollziehen und zu begründen.

Zweitens haben Sie erwähnt, dass dieses Bit den Nullzeiger exkl. Treffen könnte:

.getCoverages()  
.stream() // <==may cause null here if list coverage is null

wenn getCoverages () eine Auflistung zurückgeben soll, sollte es niemals null zurückgeben, sondern immer eine leere Auflistung.

Teilen Sie Ihren Code in separate logische Teile und geben Sie ihm einige aussagekräftige Namen:

Coverage mainCoverage = illus.getLifes().stream()
    .filter(Life::isIsmain)
    .findFirst()
    .orElseThrow(() -> new ServiceInvalidAgurmentGeneraliException(env.getProperty("MSG_002")));

Coverage mainplan = mainCoverage.getCoverages().stream()
    .filter(Coverage::isMainplan)
    .findFirst()
    .orElseThrow(() -> new ServiceInvalidAgurmentGeneraliException(env.getProperty("MSG_002")));

Es sieht viel besser aus als Ihr Ausgangspunkt. Ich hoffe das hilft.

1
mwdev

Sie können versuchen, den resultierenden Collection<Coverage> in einen Optional<Collection<Coverage>> zu kapseln, damit Sie in einer null safe - Weise kartieren können.

final Supplier<ServiceInvalidAgurmentGeneraliException> customExceptionThrower = () -> new ServiceInvalidAgurmentGeneraliException(env.getProperty("MSG_002"));

final Collection<Coverage> firstMainLifeCoverages = illus.getLifes().stream()
    .filter(Life::isIsmain)
    .findFirst()
    .orElseThrow(customExceptionThrower)
    .getCoverages();

Optional.ofNullable(firstMainLifeCoverages)
    .map(Collection::stream)
    .orElseThrow(customExceptionThrower)
    .filter(Coverage::isMainplan)
    .findFirst()
    .orElseThrow(customExceptionThrower);
0
HPH