2015-10-23 19 views
12

Spesso mi trovo nella necessità di filtrare uno Stream o di utilizzare un predicato che controlla se un determinato campo ha un determinato valore.Esiste un metodo comodo per creare un predicato che verifica se un campo è uguale a un determinato valore?

Dire per esempio ho questa POJO:

public class A { 
    private Integer field; 

    public A(final Integer field) { 
     this.field = field; 
    } 

    public Integer getField() { 
     return field; 
    } 
} 

E voglio filtrare un Stream di oggetti in base al valore del field:

final Integer someValue = 42; 
    Stream.of(new A(42), new A(1729), new A(42), new A(87539319), new A(null)) 
      .filter(a -> Objects.equals(a.getField(), someValue)) 
      ... 

Ci sarebbe un metodo comodo per generare il predicato per il metodo filter? Ho notato che c'è lo Predicate.isEqual ma non si adatta alle necessità.

ho potuto abbastanza facilmente scrivere uno come questo:

public static <T,R> Predicate<T> isEqual(Function<? super T, ? extends R> f, R value) { 
    return v -> Objects.equals(value, f.apply(v)); 
} 

e usarlo come:

Stream.of(new A(42), new A(1729), new A(42), new A(87539319), new A(null)) 
      .filter(isEqual(A::getField, someValue)) 
      ... 

ma preferirei di riutilizzare un metodo esistente dal JDK, se possibile.

+5

Non che io sappia. Nota che se sai che 'someValue' non è' null', è sufficiente un semplice 'a -> someValue.equals (a.getField())'. Non sembra peggio di 'isEqual (A :: getField, someValue)' per me, specialmente se considero che 'A' è piuttosto un' NameOfARealLifeClass' ... – Holger

risposta

8

Non esiste un metodo di fabbrica integrato, che è possibile verificare facilmente guardando a all usages of Predicate within the JFC e cercare "Metodi in ... che restituiscono Predicato". Oltre ai metodi all'interno dello stesso Predicate, c'è solo Pattern.asPredicate() che restituisce un Predicate.

Prima di implementare un tale metodo di produzione, è necessario chiedersi se ne vale davvero la pena. Ciò che rende complicata la tua espressione lambda in .filter(a -> Objects.equals(a.getField(), someValue)) è l'uso di Objects.equals che non è necessario quando puoi prevedere per almeno un argomento se è null. Dal momento che qui, someValue non è mai null, è possibile semplificare l'espressione:

final Integer someValue = 42; 
Stream.of(new A(42), new A(1729), new A(42), new A(87539319), new A(null)) 
    .filter(a -> someValue.equals(a.getField())) 
    … 

Se si desidera continuare ad attuare il metodo factory e vincere un prezzo per sfruttare creativamente ciò che già esiste, è possibile utilizzare:

public static <T,R> Predicate<T> isEqual(Function<? super T, ? extends R> f, R value) { 
    return f.andThen(Predicate.isEqual(value)::test)::apply; 
} 

Tuttavia, per il codice di produzione, preferirei consiglio un'implementazione del genere:

public static <T,R> Predicate<T> isEqual(Function<? super T, ? extends R> f, R value) { 
    return value==null? t -> f.apply(t)==null: t -> value.equals(f.apply(t)); 
} 

questi fattori il test se l'aria stant è null per semplificare l'operazione che verrà eseguita in ogni test. Quindi non ha ancora bisogno di Objects.equals. Si noti che Predicate.isEqual fa lo stesso.

+0

puoi spiegare perché il valore == null ?. ..'-soluzione è preferibile su 'Objects.equals'? – Roland

+0

@Roland: quando chiami 'Objects.equals' in ogni valutazione di funzione, ricontrollerai efficacemente se' value' è 'null' in ogni valutazione di funzione, nonostante non cambierà. Ovviamente, l'effetto sarà maggiore * se * 'value' è' null', in quanto la funzione risultante 't -> f.apply (t) == null' sarà molto più economica di' Objects.equals'. Poiché potresti utilizzare un tale metodo di utilità molto tempo in luoghi diversi, gli effetti si accumulano.Come detto, ['Predicate.isEqual' è simile] (http://grepcode.com/file/repository.grepcode.com/java/root/jdk/openjdk/8u40-b25/java/util/function/Predicate.java # 114) – Holger

+0

Grazie per il chiarimento! Oh caro ... questo è stato anche il motivo per cui ho estratto il valore in primo luogo ... è il momento per il fine settimana. – Roland