Nota: ho trovato più domande che evidenziavano le differenze tra javac
e il compilatore Eclipse, ma per quanto ho potuto vedere tutti discutono di altri problemi.Generics e lambdas: comportamento diverso nel compilatore javac ed Eclipse
Supponiamo di avere questo metodo:
public static <T, U> void foo(Supplier<T> a, Function<T, U> b, Consumer<U> c)
{
c.accept(b.apply(a.get()));
}
ho trovato un comportamento differente tra javac
e il compilatore Eclipse Java durante la compilazione chiamate a questo metodo e non sono sicuro quale dei due ha ragione.
Un semplice uso di questo metodo potrebbe essere:
// variant 1
foo(
() -> Optional.of("foo"),
value -> value.get(),
value -> System.out.println(value));
Il compilatore dovrebbe essere in grado di legarsi al T
Optional<String>
utilizzando il primo argomento e U
al String
utilizzando il secondo. Quindi questa chiamata dovrebbe essere valida (secondo me).
Questo compila bene usando javac
ma non riesce a compilare utilizzando Eclipse:
Tipo non corrispondente: impossibile convertire da vuoto a <Sconosciuto>
Aggiunta di un argomento di tipo al primo argomento (() -> Optional.<String> of("foo")
) lo rende anche in Eclipse.
Domanda: Da un punto di vista delle specifiche, Eclipse è corretto nel rifiutare questa chiamata (e perché (non))?
Ora supponiamo che vogliamo lanciare un (runtime) eccezione personalizzata, se il Optional
è vuota:
// variant 2
foo(
() -> Optional.of("foo"),
value -> value.orElseThrow(() -> new RuntimeException()),
value -> System.out.println(value));
Questo è respinta da entrambi, javac
e il compilatore Eclipse, ma con diversi messaggi di errore :
javac
: "eccezione X non dichiarata; deve essere catturato o dichiarato di essere gettato"- Eclipse compilatore: "Tipo non corrispondente: non può convertire da vuoto a <sconosciuto>"
Quando aggiungo l'argomento di tipo al primo argomento di cui sopra, Eclipse riesce a compilare mentre javac
fallisce ancora. Quando aggiungo <RuntimeException>
come argomento di tipo al secondo argomento, è il contrario, Eclipse ha esito negativo e javac
ha esito positivo.
Domanda: Ancora una volta, i compilatori hanno ragione nel rifiutare questa chiamata e perché?
A mio parere entrambe le varianti devono compilare correttamente senza ulteriori suggerimenti utilizzando argomenti tipo. In tal caso, compilerò una segnalazione di bug per javac
(riguardante la "eccezione non segnalata") e una per il compilatore di Eclipse (riguardante la "mancata corrispondenza del tipo"). Ma prima voglio essere sicuro che le specifiche condividano il mio punto di vista.
Versioni utilizzati:
javac
: 1.8.0_66- Eclipse JDT: 3.11.1.v20151118-1100
EDIT:
ho riempito bug 482781 per il problema in Eclipse.
Il problema con javac
è già segnalato come JDK-8056983, vedere Tunakis answer.
Incolpare l'eclissi in caso di dubbio :) L'inferenza del tipo è molto complicata, l'intera sintassi lambda è ancora abbastanza nuova. Eclipse ha corretto diversi bug, ma alcuni sono stati lasciati nella versione corrente, relativi a casi limite come questo. – zapl
Il compilatore ECJ di Eclipse Mars è davvero buggato rispetto all'ultima Luna quando si tratta di espansione generica. Ho già inciampato in almeno tre casi in cui ECJ 3.11 fallisce o addirittura si blocca in loop infinito mentre javac ed ECJ 3.10 si compilano correttamente. Ecco perché sto ancora usando Luna. –
Il bug di Eclipse è già stato risolto per 4.6 M1 tramite https://bugs.eclipse.org/470826 che è anche programmato per il port back to mars.2 –