2015-10-23 5 views
12

Ich bin oft in der Notwendigkeit, eine Stream zu filtern oder ein Prädikat zu verwenden, das überprüft, ob ein bestimmtes Feld einen bestimmten Wert hat.Gibt es eine Bequemlichkeitsmethode, um ein Prädikat zu erstellen, das prüft, ob ein Feld einem gegebenen Wert entspricht?

Sprich zum Beispiel habe ich diese POJO:

public class A { 
    private Integer field; 

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

    public Integer getField() { 
     return field; 
    } 
} 

Und ich mag ein Stream von Objekten filtern, basierend auf dem Wert der 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)) 
      ... 

Gäbe es eine bequeme Methode sein, das Prädikat für die filter Methode generieren? Ich habe bemerkt, dass es Predicate.isEqual gibt, aber es passt nicht zur Notwendigkeit.

Ich konnte ganz schreiben leicht ein wie folgt aus:

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

und verwenden Sie es als:

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

aber ich würde es vorziehen, eine bestehende Methode aus dem JDK wenn möglich wiederzuverwenden.

+5

Nicht, dass ich weiß. Wenn Sie jedoch wissen, dass 'someValue' nicht' null' ist, genügt ein einfaches 'a -> someValue.equals (a.getField())'. Es sieht für mich nicht schlechter aus als 'isEqual (A :: getField, someValue)', besonders wenn ich bedenke, dass 'A' eher eine' NameOfARealLifeClass' ist ... – Holger

Antwort

8

Es gibt keine solche integrierte Factory-Methode, die Sie einfach überprüfen können, indem Sie all usages of Predicate within the JFC betrachten und nach "Methoden in ... suchen, die Predicate zurückgeben". Neben den Methoden innerhalb Predicate selbst gibt es nur Pattern.asPredicate(), die eine Predicate zurückgibt.

Bevor Sie eine solche Fabrikmethode implementieren, sollten Sie sich fragen, ob es sich wirklich lohnt. Was Ihren Lambda-Ausdruck in .filter(a -> Objects.equals(a.getField(), someValue)) kompliziert aussehen lässt, ist die Verwendung von Objects.equals, die nicht notwendig ist, wenn Sie für mindestens ein Argument voraussagen können, ob es null ist. Da hier ist someValue nie null, können Sie den Ausdruck vereinfachen kann:

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())) 
    … 

Wenn Sie weiterhin die Factory-Methode implementieren möchten und einen Preis gewinnen für kreativ mit, was bereits vorhanden ist, können Sie:

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

jedoch für die Produktion Code, würde ich eher eine Implementierung wie folgt empfehlen:

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)); 
} 

diese Faktoren den Test, ob die con out stant ist null, um den Vorgang zu vereinfachen, der in jedem Test durchgeführt wird. So braucht es immer noch nicht Objects.equals. Beachten Sie, dass Predicate.isEqual ähnlich ist.

+0

können Sie bitte erklären, warum der 'Wert == null ?. ..'-Lösung ist gegenüber 'Objects.equals' vorzuziehen? – Roland

+0

@Roland: Wenn Sie 'Objects.equals' in jeder Funktionsauswertung aufrufen, überprüfen Sie effektiv, ob' value' in jeder Funktionsauswertung 'null' ist, obwohl es sich nicht ändert. Offensichtlich ist der Effekt am größten *, wenn * 'value'' null' ist, da die resultierende Funktion 't -> f.apply (t) == null' viel billiger ist als' Objects.equals'. Da Sie eine solche Utility-Methode oft an verschiedenen Orten verwenden, sammeln sich die Effekte an.Wie gesagt, [Prädikat.isEqual' macht das ähnlich] (http://grepcode.com/file/repository.grepcode.com/java/root/jdk/openjdk/8u40-b25/java/util/function/Predicate.java # 114) – Holger

+0

Danke für die Klarstellung! Oh mein Gott ... das war sogar der Grund, warum ich den Wert überhaupt erst rausgeholt habe ... es ist Zeit für das Wochenende. – Roland

Verwandte Themen