1. Controllo

Penso che potresti già annoiarti di imparare come concatenare i flussi di dati. Vuoi finalmente fare qualcosa con i dati.

La Streamclasse ha tre metodi standard che non costruiscono flussi, ma invece controllano che tipo di dati sono in essi contenuti. Questi metodi sono: anyMatch(), allMatch(), e noneMatch().

boolean anyMatch(rule)metodo

Questo metodo controlla se il flusso ha almeno un elemento che soddisfa la regola passata al metodo. Se esiste un tale elemento, il metodo restituisce true, altrimenti false.

Esempi

Codice Nota
Stream<Integer> stream = Stream.of(1, 2, 3, 4, 5);
boolean result = stream.anyMatch(x -> x > 0);

true
Stream<Integer> stream = Stream.of(1, -2, 3, -4, 5);
boolean result = stream.anyMatch(x -> x > 0);

true
Stream<Integer> stream = Stream.of(1, -2, 3, -4, 5);
boolean result = stream.filter(x -> x < 0).anyMatch(x -> x > 0);

false

Nell'ultimo esempio, prima conserviamo solo gli elementi che sono minori di zero, quindi controlliamo il risultato per vedere se qualcuno degli elementi filtrati è maggiore di zero. Naturalmente, tali elementi non ci sono più.

metodo booleano allMatch(rule).

Questo metodo controlla se tutti gli elementi nel flusso corrispondono alla regola (nota anche come predicato). La regola viene passata come argomento al metodo:

Codice Nota
Stream<Integer> stream = Stream.of(1, 2, 3, 4, 5);
boolean result = stream.allMatch(x -> x > 0);
true
(tutti gli elementi maggiori di zero)
Stream<Integer> stream = Stream.of(1, -2, 3, -4, 5);
boolean result = stream.allMatch(x -> x > 0);
false
(ci sono elementi minori o uguali a zero?)
Stream<Integer> stream = Stream.of(1, -2, 3, -4, 5);
boolean result = stream.filter(x -> x < 0).allMatch(x -> x < 0);
true
(abbiamo mantenuto gli elementi che sono minori di zero)

Nell'ultimo esempio, per prima cosa permettiamo solo agli elementi che sono minori di zero di passare attraverso il filtro, e poi controlliamo se tutti gli elementi conservati sono minori di zero. Il controllo dà esito positivo.

metodo booleano noneMatch(rule).

Il noneMatch()metodo controlla se il flusso non ha elementi che corrispondono alla regola passata. È come l'opposto del anyMatch()metodo.

Codice Nota
Stream<Integer> stream = Stream.of(1, 2, 3, 4, 5);
boolean result = stream.noneMatch(x -> x > 0);

false
Stream<Integer> stream = Stream.of(1, -2, 3, -4, 5);
boolean result = stream.noneMatch(x -> x > 0);

false
Stream<Integer> stream = Stream.of(1, -2, 3, -4, 5);
boolean result = stream.filter(x -> x < 0).noneMatch(x -> x > 0);

true


2. Classi di utilità: Optionalclasse

A volte è molto scomodo per i programmatori lavorare con nulli riferimenti. Ad esempio, supponi di confrontare due stringhe. Se entrambe le variabili non lo sono null, puoi semplicemente chiamare s1.equals(s2)e tutto funzionerà. Ma se s1potrebbe essere null, allora devi scrivere codice che gestisca questa situazione per evitare un errore NullPointerException.

Ecco perché i programmatori hanno inventato la Optional<T>classe di utilità. Il suo codice assomiglia più o meno a questo:

Codice Nota
class Optional<Type>
{
   private final Type value;
   private Optional() { this.value = null;}
   private Optional(value) { this.value = value;}
   public static <Type> Optional<Type> of(Type value)
   {
      return new Optional<Type>(value);
   }

   public boolean isPresent()
   {
      return value != null;
   }

   public boolean isEmpty()
   {
      return value == null;
   }

   public Type get()
   {
      if (value == null)
      {
         throw new NoSuchElementException();
      }
      return value;
   }

   public Type orElse(Type other)
   {
      return value != null ? value : other;
   }

   public Type orElseThrow()
   {
      if (value == null)
      {
         throw new NoSuchElementException();
      }
      return value;
   }
}










Controlla se il valore non è null



Controlla se il valore è null




Restituisce il valore memorizzato. Genera un'eccezione se il valore è null.







Restituisce il valore non nullo archiviato. Oppure, se il valore archiviato è null, restituisce il valore passato come argomento del metodo



Restituisce il valore non nullo archiviato o genera un'eccezione se il valore è nullo.

Lo scopo di questa classe è semplicemente quello di memorizzare un oggetto T (un riferimento a un oggetto il cui tipo è T). Il riferimento all'oggetto all'interno di un Optional<T>oggetto può essere null.

Questa classe consente ai programmatori di scrivere un codice leggermente più carino. Confrontiamo:

Utilizzo facoltativo Non usare Opzionale
public void printString(String s)
{
   Optional<String> str = Optional.ofNullable(s);
   System.out.println(str.orElse(""));
}
public void printString(String s)
{
   String str = s != null ? s : "";
   System.out.println(str)
}

Un Optionaloggetto può sempre essere confrontato con un altro Optionaloggetto utilizzando il equalsmetodo, anche se memorizzano nulli riferimenti.

In parole povere, la Optionalclasse ti consente di scrivere controlli "belli" nulle azioni "belli" nel caso in cui un Optionaloggetto memorizzi un nullvalore.



3. Trovare elementi

Torniamo alla Streamclasse. La Streamclasse ha altri 4 metodi che ti consentono di cercare elementi in un flusso. Questi metodi sono findFirst(), findAny(), min()e max().

Optional<T> findFirst()metodo

Il findFirst()metodo restituisce semplicemente il primo elemento nel flusso. Questo è tutto ciò che fa.

La cosa più interessante da notare qui è che il metodo non restituisce un Toggetto, ma piuttosto un Optional<T>oggetto wrapper. Ciò garantisce che il metodo non ritorni mai nulldopo aver fallito nel trovare un oggetto.

Esempio:

ArrayList<String> list = new ArrayList<String>();
Collections.addAll(list, "Hello", "how's", "life?");
String str = list.stream().findFirst().get(); // Hello

Per maggiore chiarezza, suddividiamo l'ultima riga in più righe:

ArrayList<String> list = new ArrayList<String>();
Collections.addAll(list, "Hello", "how's", "life?");

Stream<String> stream = list.stream();
Optional<String> result = stream.findFirst();
String str = result.get(); // Hello

L'ultimo get()metodo recupera semplicemente il valore memorizzato all'interno dell'oggetto Optional.

Optional<T> findAny()metodo

Il findAny()metodo restituisce qualsiasi elemento dal flusso e termina lì. Questo metodo è simile a findFirst(), ma è ottimo per i flussi utilizzati in operazioni parallele.

Durante l'elaborazione di flussi in parallelo, potrebbe essere che un elemento sia già stato trovato in qualche parte di un flusso, ma non è ancora chiaro se sia il primo o meno.

Se molti elementi corrispondono a tutti i filtri ed è importante che il programmatore ottenga esattamente il primo di essi, allora il findFirst()metodo è quello che dovrebbe essere chiamato. Se il programmatore sa che in realtà 0 o 1 elemento corrisponderà a tutti i filtri, allora è sufficiente semplicemente chiamare findAny()- e questo sarà più veloce.

Optional<T> min(Comparator<T>)metodo

Il min()metodo utilizza un comparatoroggetto per confrontare tutti gli elementi nel flusso e restituisce l'elemento minimo. Il modo più conveniente per definire un oggetto comparatore è con una funzione lambda.

Esempio di ricerca della stringa più breve:

ArrayList<String> list = new ArrayList<String>();
Collections.addAll(list, "Hello", "how's", "life?");
String min = list.stream().min( (s1, s2)-> s1.length()-s2.length() ).get();

Optional<T> max(Comparator<T>)metodo

Il max()metodo utilizza un comparatoroggetto per confrontare tutti gli elementi nel flusso e restituisce l'elemento massimo. Il modo più conveniente per definire un oggetto comparatore è con una funzione lambda.

Esempio di ricerca della stringa più lunga:

ArrayList<String> list = new ArrayList<String>();
Collections.addAll(list, "Hello", "how's", "life?");
String max = list.stream().max( (s1, s2)-> s1.length()-s2.length() ).get();