2015-11-03 8 views
8

Il codice seguente compila bene ma genera un'eccezione in fase di runtime. È questo il comportamento previsto e perché?LambdaConversionException quando si mescolano metodi di riferimento e generici

Codice:

public static void main(String[] args) { 
    A<Integer> a = new A<>(); 
    System.out.println(a.min()); //prints null as expected 
    System.out.println(a.max()); //throws exception 
} 

static class A<T extends Number & Comparable<? super T>> { 
    Stream<T> s = Stream.empty(); 
    public T min() { return s.min((t1, t2) -> t1.compareTo(t2)).orElse(null); } 
    public T max() { return s.max(T::compareTo).orElse(null); } 
} 

uscita:

null 
Exception in thread "main" java.lang.BootstrapMethodError: call site initialization exception 
    at java.lang.invoke.CallSite.makeSite(CallSite.java:341) 
    at java.lang.invoke.MethodHandleNatives.linkCallSiteImpl(MethodHandleNatives.java:307) 
    at java.lang.invoke.MethodHandleNatives.linkCallSite(MethodHandleNatives.java:297) 
    at abc$A.max(abc.java:19) 
    at abc.main(abc.java:8) 
Caused by: java.lang.invoke.LambdaConversionException: Invalid receiver type class java.lang.Number; not a subtype of implementation type interface java.lang.Comparable 
    at java.lang.invoke.AbstractValidatingLambdaMetafactory.validateMetafactoryArgs(AbstractValidatingLambdaMetafactory.java:233) 
    at java.lang.invoke.LambdaMetafactory.metafactory(LambdaMetafactory.java:303) 
    at java.lang.invoke.CallSite.makeSite(CallSite.java:302) 
    ... 4 more 
+0

Ottiene l'attesa 'java.lang.IllegalStateException: lo stream è già stato utilizzato o chiuso con java 1.8.0_60 –

+0

@AlexisC. Stranamente (almeno l'output ha più senso del mio) - Sono anch'io su 1.8.0_60 - Windows x64. – assylias

+0

Cosa succede se commentate la prima riga (con il minimo) in modo che lo stream sia aperto? –

risposta

1

Sembra essere un problema di Netbeans e non riesco a riprodurre il problema quando si utilizza javac dalla riga di comando. Ho registrato uno bug report.

+0

Non penso sia colpa di Netbeans, controlla la mia risposta, è stato segnalato come errore nel compilatore –

+0

@SleimanJneidi I don Penso che sia così. Quel bug è stato risolto in 8u40 e ho il problema con 8u60 + il codice compila e gira bene con javac (ma non in Netbeans). – assylias

+1

Se si disattiva "compila su salvataggio", il problema scompare. Forse questo spegne il compilatore Netbeans e passa a javac? –

5

Il tuo codice non avrebbe funzionato anche se si utilizza lambda invece di metodo riferimenti perché il flusso è già esaurita

System.out.println(a.min()); 
System.out.println(a.max()); // exhausted 

I flussi sono uno fuori. Ma lasciamo questo a parte. Quando si utilizza la versione di riferimento del metodo, acquisisce Number come parametro di tipo e non Comparable dove Number non ha compareToforse perché Number è più specifico qui. Se si basta usare Comparable che funzionerà bene

static class A<T extends Comparable<? super T>> { 
    Stream<T> s = Stream.empty(); 
    public T min() { return s.min((t1, t2) -> t1.compareTo(t2)).orElse(null); } 
    public T max() { 
     T t = s.max(T::compareTo).orElse(null); 
     return t; } 
} 

System.out.println(a.max()); //null 

IMO (tanto per essere prudenti): Credo che sia un bug.

Quello che effettivamente credo: è sicuramente un bug.

Modifica: Si scopre che questo era in realtà un bug ed è stato risolto come confermato da Brian Goetz. https://bugs.openjdk.java.net/browse/JDK-8058112. Secondo il database dei bug, questo è stato risolto in 8u40

3

La chiamata problema sito di inizializzazione viene risolto mediante una JDK-8058112 disponibile in JDK 8u40 B17 o poi.

+0

Collegamento bug: https://bugs.openjdk.java.net/browse/JDK-8058112 –

1

Per coloro che stanno affrontando questo problema nel 2017 con java8 1.8.0_141, c'è un altro rapporto di bug archiviato JDK-8142476 e la versione di correzione è solo java9.