Flussi Java Null-Safe dalle raccolte

1. Panoramica

In questo tutorial, vedremo come creare flussi null-safe da raccolte Java.

Per cominciare, per comprendere appieno questo materiale è necessaria una certa familiarità con i riferimenti ai metodi di Java 8, le espressioni Lambda, gli optional e l'API Stream.

Se non hai familiarità con uno di questi argomenti, dai un'occhiata prima ai nostri articoli precedenti: Nuove funzionalità in Java 8, Guida a Java 8 opzionale e Introduzione a Java 8 Streams.

2. Dipendenza da Maven

Prima di iniziare, c'è una dipendenza da Maven di cui avremo bisogno per determinati scenari:

 org.apache.commons commons-collections4 4.2 

La libreria commons-collections4 può essere scaricata da Maven Central.

3. Creazione di flussi da raccolte

L'approccio di base alla creazione di un flusso da qualsiasi tipo di raccolta consiste nel chiamare i metodi stream () o parallelStream () sulla raccolta a seconda del tipo di flusso richiesto:

Collection collection = Arrays.asList("a", "b", "c"); Stream streamOfCollection = collection.stream(); 

La nostra raccolta molto probabilmente avrà una fonte esterna ad un certo punto, probabilmente ci ritroveremo con un metodo simile a quello qui sotto durante la creazione di flussi dalle raccolte:

public Stream collectionAsStream(Collection collection) { return collection.stream(); } 

Ciò può causare alcuni problemi. Quando la raccolta fornita punta a un riferimento null , il codice genererà un'eccezione NullPointerException in fase di esecuzione.

La sezione seguente spiega come possiamo proteggerci da questo.

4. Rendere i flussi di raccolta creati nulli

4.1. Aggiungere controlli per prevenire Null dereferenziazioni

Per evitare eccezioni indesiderate di puntatori nulli , possiamo scegliere di aggiungere controlli per impedire riferimenti nulli durante la creazione di flussi dalle raccolte:

Stream collectionAsStream(Collection collection) { return collection == null ? Stream.empty() : collection.stream(); } 

Questo metodo, tuttavia, presenta un paio di problemi.

In primo luogo, il controllo nullo ostacola la logica aziendale che riduce la leggibilità complessiva del programma.

In secondo luogo, l'uso di null per rappresentare l'assenza di un valore è considerato un approccio sbagliato dopo Java SE 8: esiste un modo migliore per modellare l'assenza e la presenza di un valore.

È importante tenere presente che una raccolta vuota non è la stessa di una raccolta nulla . Mentre il primo indica che la nostra query non ha risultati o elementi da mostrare, il secondo suggerisce che si è appena verificato un tipo di errore durante il processo.

4.2. Usa il metodo emptyIfNull dalla libreria CollectionUtils

Possiamo scegliere di utilizzare la libreria CollectionUtils di Apache Commons per assicurarci che il nostro flusso sia nullo . Questa libreria fornisce un metodo emptyIfNull che restituisce una raccolta vuota immutabile data una raccolta nulla come argomento, o altrimenti la raccolta stessa:

public Stream collectionAsStream(Collection collection) { return emptyIfNull(collection).stream(); } 

Questa è una strategia molto semplice da adottare. Tuttavia, dipende da una libreria esterna. Se una politica di sviluppo software limita l'uso di tale libreria, questa soluzione viene resa nulla .

4.3. Usa Java 8 opzionale

L' Opzionale di Java SE 8 è un contenitore a valore singolo che contiene un valore oppure no. Dove manca un valore, si dice che il contenitore opzionale è vuoto.

L'utilizzo di Optional può essere probabilmente considerato come la migliore strategia complessiva per creare una raccolta null-safe da un flusso.

Vediamo come possiamo usarlo seguito da una rapida discussione di seguito:

public Stream collectionToStream(Collection collection) { return Optional.ofNullable(collection) .map(Collection::stream) .orElseGet(Stream::empty); } 
  • Optional.ofNullable (raccolta) crea unoggetto facoltativo dalla raccolta passata. Se la raccolta è nulla, viene creato un oggetto opzionale vuoto .
  • map (Collection :: stream) estrae il valore contenutonell'oggetto opzionale come argomento delmetodo map ( Collection.stream () )
  • orElseGet (Stream :: empty) restituisce il valore di fallback nel caso in cui l'oggetto Optional sia vuoto, ovvero la raccolta passata è null .

Di conseguenza, proteggiamo in modo proattivo il nostro codice da eccezioni indesiderate di puntatori nulli .

4.4. Usa Stream OfNullable di Java 9

Esaminando il nostro precedente esempio ternario nella sezione 4.1. e considerando la possibilità che alcuni elementi possano essere null al posto della Collection , abbiamo a nostra disposizione il metodo ofNullable nella classe Stream .

Possiamo trasformare il campione sopra in:

Stream collectionAsStream(Collection collection) { return collection.stream().flatMap(s -> Stream.ofNullable(s)); }

5. conclusione

In questo articolo, abbiamo rivisitato brevemente come creare uno stream da una data raccolta. Abbiamo quindi proceduto all'esplorazione delle tre strategie chiave per assicurarci che lo stream creato fosse null-safe quando creato da una raccolta.

Infine, abbiamo sottolineato la debolezza dell'utilizzo di ciascuna strategia, ove pertinente.

Come al solito, il codice sorgente completo che accompagna l'articolo è disponibile su GitHub.