2015-01-04 14 views
14

stworzyłem funkcję filtrowania z wieloma orzeczników, dla których wykonuję logiczne i dla nich:typ docelowy tej wypowiedzi musi być funkcjonalny interfejs

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

Dzwoniąc:

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

Działa dobrze i drukuje 3 i 9. Jednak gdy przekazuję jeden predykat taki jak:

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

Dostaję błąd kompilacji:

The target type of this expression must be a functional interface 

Dlaczego tak jest?

enter image description here uzyskać informacje o wersji używam Eclipse Luna 1.

+0

Czy możesz dodać więcej kodu ... – Devavrata

+1

@Devavrat Więcej kodu czego? Wszystko jest już opublikowane ... Sygnatura metody i treść + wywołanie, które powoduje błąd kompilacji. – user2336315

+3

Czy kompilacja działa w wierszu poleceń? Byłem w stanie uruchomić oba twoje przykłady w IntelliJ 14.0.2 i otrzymałem odpowiednio '3',' 9' i '1',' 3', '5',' 7', '9'. Wygląda na to, że może to być problem Eclipse. – mkobit

Odpowiedz

7

To jest skrzynka narożna dla kompilatora. Aby ustalić, czy powinno się zastosować varargs do pakowania argumentów do tablicy lub po prostu przekazać tablicę, musi znać typ ostatniego argumentu, jednak w przypadku wyrażenia lambda potrzebuje on wywoływanej sygnatury metody do określenia rodzaj. Ale jasne jest, co powinno się stać, ponieważ wyrażenie lambda nigdy nie może być typem tablicowym, więc javac kompiluje go bez problemów.

Jeden zaakceptowania obejście byłoby przeciążyć metodę:

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

byłoby to akceptowalne obejścia, gdyż nie wymaga żadnych zmian po stronie wywołującego przy jednoczesnej poprawie wydajności dla pojedynczego -argowanie w tym samym czasie.


Należy pamiętać, że metoda varargs umożliwia zerowe argumenty, ale nie powiedzie się, jeśli nazywa się w ten sposób. Więc albo należy dodać kolejną przeciążeniem:

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

lub dokonać sposób bezpieczny dla przypadku zerowego argumentu:

@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

Zarówno Netbeans i Eclipse posiada kilka błędów w zakresie analizowania wyrażeń lambda w Javie. Są one powoli naprawiane, ale dopóki nie zostaną znalezione, najlepsze obejścia, które znalazłem, to: 1. Zadeklaruj typy 2. Jeśli to nie działa, użyj bloku 3. Jeśli to nie działa, utwórz anonimowy obiekt implementujący predykat/funkcję itp.

Uczynią one twój kod, ale są konieczne w różnych sytuacjach.

0

Czasami Eclipse potrzebuje dobrego ol”czyste i odbudować wszystkich projektów oraz problem odchodzi.

Powiązane problemy