2015-01-04 7 views
14

ich eine Funktion erstellt mit mehreren Prädikaten zu filtern, für die ich eine logische führen und für sie:Der Zieltyp dieser Ausdruck muss eine funktionale Schnittstelle sein

@SafeVarargs 
public static <T> Stream<T> filter(Stream<T> source, Predicate<T>... predicates) { 
    return source.filter(Arrays.stream(predicates).reduce(predicates[0], Predicate::and)); 
} 

Beim Aufruf:

filter(IntStream.range(0, 10).boxed(), x -> x % 2 != 0, x -> x%3 == 0).forEach(System.out::println); 

Es funktioniert gut und druckt 3 und 9. Wenn ich jedoch ein einzelnes Prädikat wie:

erhalte, bekomme ich ein Übersetzungsfehler:

The target type of this expression must be a functional interface 

Warum ist das?

enter image description here Für Infos verwende ich Eclipse-Luna-Version 1.

+0

Können Sie mehr Code posten .... – Devavrata

+1

@Devavrat Mehr Code von was? Alles ist schon gepostet ... Die Methodensignatur und der Body + der Aufruf, der den Kompilierungsfehler erzeugt. – user2336315

+3

Funktioniert die Kompilierung in der Befehlszeile? Ich konnte beide Beispiele in IntelliJ 14.0.2 ausführen und bekam '3',' 9' und '1',' 3', '5',' 7', '9'. Sieht so aus, als könnte es ein Eclipse-Problem sein. – mkobit

Antwort

7

Dies ist ein Eckfall für den Compiler. Um zu bestimmen, ob Varargs das Wrappen von Argumenten in ein Array anwenden oder einfach ein Array übergeben soll, muss es den Typ des letzten Arguments kennen. Im Fall eines Lambda-Ausdrucks benötigt es jedoch die aufgerufene Methodensignatur Art. Aber es ist klar, was passieren sollte, da ein Lambda-Ausdruck niemals ein Array-Typ sein kann und so javac kompiliert es ohne Probleme.

Eine akzeptable Behelfslösung wäre die Methode zu überlasten:

@SafeVarargs 
public static <T> Stream<T> filter(Stream<T> source, Predicate<T>... predicates) { 
    return source.filter(
     Arrays.stream(predicates).reduce(predicates[0], Predicate::and)); 
} 
public static <T> Stream<T> filter(Stream<T> source, Predicate<T> predicate) { 
    return source.filter(predicate); 
} 

Dies wäre eine akzeptable Behelfslösung sein, da es keine Änderungen auf der rufenden Seite erfordert, während die Effizienz für die einzelnen zu verbessern -arg Fall zur gleichen Zeit.


Bitte beachten Sie, dass Ihre varargs-Methode null Argumente zulässt, aber fehlschlägt, wenn sie so aufgerufen wird. Sie sollten also entweder, fügen Sie eine weitere Überlastung:

public static <T> Stream<T> filter(Stream<T> source) { 
    return source; 
} 

oder machen das Verfahren sicher für die Null-Argument Fall:

@SafeVarargs 
public static <T> Stream<T> filter(Stream<T> source, Predicate<T>... predicates) { 
    return Arrays.stream(predicates).reduce(Predicate::and) 
       .map(source::filter).orElse(source); 
} 
2

Sowohl Netbeans und Eclipse haben eine Reihe von Fehlern im Bereich der Lambda-Ausdrücke in Java-Parsing. Sie sind langsam behoben, aber, bis sie sind, sind die besten Umgehungsmöglichkeiten, die ich gefunden habe: 1. deklarieren Sie Typen 2. Wenn das nicht funktioniert, verwenden Sie einen Block 3. Wenn das nicht funktioniert, erstellen Sie eine anonyme Objekt, das das Prädikat/Funktion usw. implementiert.

Diese machen Ihren Code unordentlicher, aber sie sind in einer Reihe von Situationen notwendig.

0

Manchmal braucht Eklipse eine gute ol‘sauber und den Wiederaufbau aller Projekte und das Problem geht weg.