Catena di predicati Java 8

1. Panoramica

In questo rapido tutorial, discuteremo diversi modi per concatenare i predicati in Java 8.

2. Esempio di base

Per prima cosa, vediamo come utilizzare un semplice Predicate per filtrare un elenco di nomi:

@Test public void whenFilterList_thenSuccess(){ List names = Arrays.asList("Adam", "Alexander", "John", "Tom"); List result = names.stream() .filter(name -> name.startsWith("A")) .collect(Collectors.toList()); assertEquals(2, result.size()); assertThat(result, contains("Adam","Alexander")); }

In questo esempio, abbiamo filtrato il nostro elenco di nomi per lasciare solo i nomi che iniziano con "A" utilizzando il predicato :

name -> name.startsWith("A")

Ma cosa succede se volessimo applicare più predicati ?

3. Filtri multipli

Se volessimo applicare più predicati , un'opzione è semplicemente concatenare più filtri:

@Test public void whenFilterListWithMultipleFilters_thenSuccess(){ List result = names.stream() .filter(name -> name.startsWith("A")) .filter(name -> name.length() < 5) .collect(Collectors.toList()); assertEquals(1, result.size()); assertThat(result, contains("Adam")); }

Abbiamo ora aggiornato il nostro esempio per filtrare il nostro elenco estraendo i nomi che iniziano con "A" e hanno una lunghezza inferiore a 5.

Abbiamo utilizzato due filtri, uno per ogni predicato .

4. predicato complesso

Ora, invece di utilizzare più filtri, possiamo utilizzare un filtro con un predicato complesso :

@Test public void whenFilterListWithComplexPredicate_thenSuccess(){ List result = names.stream() .filter(name -> name.startsWith("A") && name.length() < 5) .collect(Collectors.toList()); assertEquals(1, result.size()); assertThat(result, contains("Adam")); }

Questa opzione è più flessibile della prima, poiché possiamo usare operazioni bit per bit per costruire il predicato complesso quanto vogliamo.

5. Combinazione di predicati

Successivamente, se non vogliamo creare un predicato complesso utilizzando operazioni bit per bit, Java 8 Predicate dispone di metodi utili che possiamo utilizzare per combinare i predicati .

Combineremo Predicate utilizzando i metodi Predicate.and () , Predicate.or () e Predicate.negate ().

5.1. Predicate.and ()

In questo esempio, definiremo i nostri predicati in modo esplicito, quindi li combineremo utilizzando Predicate.and ():

@Test public void whenFilterListWithCombinedPredicatesUsingAnd_thenSuccess(){ Predicate predicate1 = str -> str.startsWith("A"); Predicate predicate2 = str -> str.length() < 5; List result = names.stream() .filter(predicate1.and(predicate2)) .collect(Collectors.toList()); assertEquals(1, result.size()); assertThat(result, contains("Adam")); }

Come possiamo vedere, la sintassi è abbastanza intuitiva e i nomi dei metodi suggeriscono il tipo di operazione. Usando e () , abbiamo filtrato il nostro elenco estraendo solo i nomi che soddisfano entrambe le condizioni.

5.2. Predicate.or ()

Possiamo anche usare Predicate.or () per combinare Predicates.

Estraiamo i nomi che iniziano con "J", così come i nomi con una lunghezza inferiore a 4:

@Test public void whenFilterListWithCombinedPredicatesUsingOr_thenSuccess(){ Predicate predicate1 = str -> str.startsWith("J"); Predicate predicate2 = str -> str.length() < 4; List result = names.stream() .filter(predicate1.or(predicate2)) .collect(Collectors.toList()); assertEquals(2, result.size()); assertThat(result, contains("John","Tom")); }

5.3. Predicate.negate ()

Possiamo usare Predicate.negate () anche quando combiniamo i nostri predicati :

@Test public void whenFilterListWithCombinedPredicatesUsingOrAndNegate_thenSuccess(){ Predicate predicate1 = str -> str.startsWith("J"); Predicate predicate2 = str -> str.length() < 4; List result = names.stream() .filter(predicate1.or(predicate2.negate())) .collect(Collectors.toList()); assertEquals(3, result.size()); assertThat(result, contains("Adam","Alexander","John")); }

Qui, abbiamo usato una combinazione di or () e negate () per filtrare l' elenco in base a nomi che iniziano con "J" o hanno una lunghezza non inferiore a 4.

5.4. Combina predicati in linea

Non abbiamo bisogno di definire esplicitamente i nostri predicati per usare and (), or () e negate ().

Possiamo anche usarli in linea trasmettendo il predicato :

@Test public void whenFilterListWithCombinedPredicatesInline_thenSuccess(){ List result = names.stream() .filter(((Predicate)name -> name.startsWith("A")) .and(name -> name.length()<5)) .collect(Collectors.toList()); assertEquals(1, result.size()); assertThat(result, contains("Adam")); }

6. Combinazione di una raccolta di predicati

Infine, vediamo come concatenare una raccolta di predicati riducendoli.

Nell'esempio seguente, abbiamo un elenco di predicati che abbiamo combinato utilizzando Predicate.and () :

@Test public void whenFilterListWithCollectionOfPredicatesUsingAnd_thenSuccess(){ List
    
      allPredicates = new ArrayList
     
      (); allPredicates.add(str -> str.startsWith("A")); allPredicates.add(str -> str.contains("d")); allPredicates.add(str -> str.length() > 4); List result = names.stream() .filter(allPredicates.stream().reduce(x->true, Predicate::and)) .collect(Collectors.toList()); assertEquals(1, result.size()); assertThat(result, contains("Alexander")); }
     
    

Nota che usiamo la nostra identità di base come:

x->true

Ma sarà diverso se vogliamo combinarli usando Predicate.or () :

@Test public void whenFilterListWithCollectionOfPredicatesUsingOr_thenSuccess(){ List result = names.stream() .filter(allPredicates.stream().reduce(x->false, Predicate::or)) .collect(Collectors.toList()); assertEquals(2, result.size()); assertThat(result, contains("Adam","Alexander")); }

7. Conclusione

In questo articolo, abbiamo esplorato diversi modi per concatenare i predicati in Java 8, utilizzando filter (), creando predicati complessi e combinando predicati.

Il codice sorgente completo è disponibile su GitHub.