2015-01-04 13 views
14

ho creato una funzione di filtrare con più predicati per cui eseguire un AND logico per loro:Il tipo di destinazione di questa espressione deve essere un'interfaccia funzionale

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

quando chiamate:

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

Funziona bene e stampa 3 e 9. Tuttavia quando passo un singolo predicato come:

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

Ottengo un errore di compilazione:

The target type of this expression must be a functional interface 

Perché è questo?

enter image description here Per info Io uso la versione di Eclipse Luna 1.

+0

Puoi pubblicare altro codice .... – Devavrata

+1

@Devavrat Altro codice di cosa? Tutto è già pubblicato ... Il metodo signature e body + l'invocazione che produce l'errore di compilazione. – user2336315

+3

La compilazione funziona sulla riga di comando? Sono stato in grado di eseguire entrambi i tuoi esempi in IntelliJ 14.0.2 e ho ottenuto '3',' 9' e '1',' 3', '5',' 7', '9' rispettivamente. Sembra che potrebbe essere un problema di Eclipse. – mkobit

risposta

7

Questo è un caso angolo per il compilatore. Per determinare se deve applicare l'avvolgimento vararg di argomenti in un array o semplicemente passare un array, deve conoscere il tipo dell'ultimo argomento, tuttavia, nel caso di un'espressione lambda, ha bisogno della firma del metodo invocato per determinare il genere. Ma è chiaro che cosa dovrebbe accadere in quanto un'espressione lambda non può mai essere un tipo di array e quindi, javac lo compila senza problemi.

Un work-around accettabile sarebbe sovraccaricare il metodo:

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

Questo sarebbe un un'accettabile lavoro risolvere in quanto non richiede alcuna modifica sul lato chiamante, migliorando l'efficienza per il singolo -argo il caso allo stesso tempo.


Si prega di notare che il metodo varargs consente zero argomenti ma fallirà se chiamato in quel modo. Così si dovrebbe neanche, aggiungere un altro overload:

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

o fare il metodo sicuro per il caso argomento a zero:

@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

Sia Netbeans ed Eclipse hanno un certo numero di bug nel settore delle analisi espressioni lambda in Java. Si stanno lentamente aggiustando ma, finché non lo sono, i migliori rimedi che ho trovato sono: 1. dichiarare i tipi 2. se non funziona, usa un blocco 3. se non funziona, crea un anonimo oggetto che implementa il predicato/funzione ecc.

Questi rendono il vostro codice più disordinato ma sono necessari in un certo numero di situazioni.

0

volte Eclipse ha bisogno di un buon ol' pulita e ricostruire di tutti i progetti e il problema Va via.