wake-up-neo.com

Wie kann man einen Java 8-Stream am besten aus einem Objekt erstellen, das keine Objekte aufnehmen kann?

Was ist die beste/idiomatische Art, eine Nullprüfung durchzuführen, bevor ein Stream abgerufen wird?

Ich habe eine Methode, die eine List empfängt, die null sein kann. Ich kann also nicht einfach .stream() für den übergebenen Wert aufrufen. Gibt es einen statischen Helfer, der einen leeren Stream liefert, wenn der Wert null ist?

23
checketts

Ich stimme zu Stuart Marks , dass list == null ? Stream.empty() : list.stream() der beste Weg ist, dies zu tun (siehe seine Antwort ), oder zumindest der beste Weg, dies vor Java 9 zu tun (siehe Bearbeiten unten), aber ich ' Überlassen Sie diese Antwort, um die Verwendung der optionalen API zu demonstrieren.

<T> Stream<T> getStream(List<T> list) {
    return Optional.ofNullable(list).map(List::stream).orElseGet(Stream::empty);
}

Edit: Java 9 fügte die statische Methode Stream.<T>ofNullable(T) hinzu, die den leeren Stream mit einem null-Argument zurückgibt, andernfalls ein Stream mit dem Argument als einziges Element. Wenn das Argument eine Sammlung ist, können wir flatMap in einen Stream umwandeln.

<T> Stream<T> fromNullableCollection(Collection<? extends T> collection) {
    return Stream.ofNullable(collection).flatMap(Collection::stream);
}

Die von Stuart Marks diskutierte optionale API wird dadurch nicht missbraucht. Im Gegensatz zur Lösung für ternäre Operatoren besteht keine Möglichkeit für eine Ausnahme mit einem Nullzeiger (als ob Sie nicht darauf geachtet hätten und die Reihenfolge der Operanden falsch dargestellt hätten). Dank der Signatur von flatMap funktioniert es auch mit einem Platzhalter mit oberer Begrenzung, ohne dass SuppressWarnings("unchecked") benötigt wird, sodass Sie einen Stream<T> aus einer Sammlung von Elementen eines beliebigen Untertyps von T erhalten können.

35
gdejohn

In den anderen Antworten wird die Instanz Optional erstellt und streng innerhalb derselben Anweisung verwendet. Die Optional-Klasse ist in erster Linie nützlich für die Kommunikation mit dem Aufrufer über das Vorhandensein oder Fehlen eines Rückgabewerts, der mit dem tatsächlichen Wert, falls vorhanden, verbunden ist. Die Verwendung innerhalb einer einzigen Methode scheint unnötig.

Lassen Sie mich folgende prosaische Technik vorschlagen:

static <T> Stream<T> nullableListToStream(List<T> list) {
    return list == null ? Stream.empty() : list.stream();
}

Ich denke, der ternäre Betreiber ist heutzutage ein bisschen deklassiert, aber ich denke, dass dies die einfachste und effizienteste Lösung ist.

Wenn ich dies für real schreiben würde (dh für eine echte Bibliothek, nicht nur Beispielcode für Stack Overflow), würde ich Platzhalterzeichen einfügen, damit der Stream-Rückgabetyp vom List-Typ abweichen kann. Oh, und es kann eine Collection sein, da dort die stream()-Methode definiert ist:

@SuppressWarnings("unchecked")
static <T> Stream<T> nullableCollectionToStream(Collection<? extends T> coll) {
    return coll == null ? Stream.empty() : (Stream<T>)coll.stream();
}

(Die Unterdrückung der Warnung ist aufgrund der Umwandlung von Stream<? extends T> in Stream<T> erforderlich, was sicher ist, aber der Compiler weiß das nicht.)

12
Stuart Marks

Das Beste, was ich mir vorstellen kann, ist die Verwendung einer Optional mit der orElseGet-Methode.

return Optional.ofNullable(userList)
                .orElseGet(Collections::emptyList)
                .stream()
                .map(user -> user.getName())
                .collect(toList());

Aktualisiert mit @ Mishas Vorschlag, Collections::emptyList über ArrayList::new zu verwenden

12
checketts

Apache Commons-Collections4:

CollectionUtils.emptyIfNull(list).stream()
5
piotrek

Persönlich halte ich null für veraltet und verwende optional (wo auch immer möglich) trotz des (winzigen) Leistungsaufwandes. Also benutze ich die Schnittstelle von Stuart Marks mit einer Implementierung, die auf gdejohn basiert, d. H.

@SuppressWarnings("unchecked")
static <T> Stream<T> nullableCollectionToStream(Collection<? extends T> coll)
{
    return (Stream<T>) Optional.ofNullable(coll)
                           .map(Collection::stream)
                           .orElseGet(Stream::empty);
}
0