2014-11-24 13 views
11

Ho il seguente titolare del trattamento generica nel mio progetto (semplificato):Java 8 - la conversione di un numero intero di un problema di lunga compilation

public abstract static class Value<E> { 

    E value; 

    public void setValue(E value) { 
     this.value = value; 
    } 

    public E getValue() { 
     return this.value; 
    } 

    public String toString() { 
     return "[" + value + "]"; 
    } 
} 

Insieme ad un InputCollection che contiene un elenco di Objects:

public static class InputCollection { 

    private ArrayList<Object> values; 

    public InputCollection() { 
     this.values = new ArrayList<>(); 
    } 

    public void addValue(Value<?> value) { 
     System.out.println("addding " + value + " to collection"); 
     this.values.add(value); 
    } 

    public <D> D getValue(Value<D> value, D defaultValue) { 
     int index = this.values.indexOf(value); 
     if (index == -1) 
      return defaultValue; 

     Object val = this.values.get(index); 
     if (val == null) { 
      return defaultValue; 
     } 

     return ((Value<D>)val).getValue(); 
    } 
} 

L'idea è di essere in grado di definire un insieme di variabili final che implementa questa abstractValue<E> in uno 'stato' cosiddetto, in questo modo:

012.
public static final class Input<E> extends Value<E> { 
    public static final Input<String> STRING_ONE = new Input<String>(); 
    public static final Input<Integer> INTEGER_ONE = new Input<Integer>(); 
} 

Quindi, aggiungere queste variabili a un'istanza di InputCollection, che a sua volta è condivisa da molti "stati" o "processi". Il valore di un Input<E> può quindi essere modificato da uno stato diverso e quindi essere recuperato quando necessario dallo stato originale. Una sorta di modello di memoria condivisa.

Questo concetto è stato lavorando bene per anni (sì, questo è l'eredità), ma recentemente abbiamo cominciato a muoversi verso Java 8, e questo ha creato errori di compilazione, anche se l'implementazione ha lavorato su Java 7.

Add il seguente main per gli esempi di codice di cui sopra:

public static void main (String [] args) { 

    InputCollection collection = new InputCollection(); 
    //Add input to collection 
    collection.addValue(Input.STRING_ONE); 
    collection.addValue(Input.INTEGER_ONE); 

    //At some later stage the values are set 
    Input.INTEGER_ONE.setValue(1); 
    Input.STRING_ONE.setValue("one"); 

    //Original values are then accessed later 
    long longValue = collection.getValue(Input.INTEGER_ONE, -1); 

    if (longValue == -1) { 
     System.out.println("Error: input not set"); 
    } else { 
     System.out.println("Input is: " + longValue); 
    } 
} 

Se il livello di conformità del compilatore in Eclipse è impostato su 1,7, non c'è problemi di compilazione, e l'uscita sarà correttamente essere:

addding [null] to collection 
addding [null] to collection 
Input is: 1 

ma se è impostato su errore di compilazione 1.8 Type mismatch: cannot convert from Integer to long sulla linea

long longValue = collection.getValue(Input.INTEGER_ONE, -1); 

Ma se accedo il valore di fare questo:

long longVal = Input.INTEGER_ONE.getValue(); 

non ci sono problemi di compilazione, il che è fonte di confusione.

Può essere risolto con un cast, ma questo è utilizzato in tutto il progetto e richiederebbe un bel po 'di test obbligatori per cambiare ogni occorrenza.

Cosa è cambiato in Java 8 che richiede il cast? La compilazione è diventata più severa in qualche modo? E perché il compilatore non si lamenta se il valore è l'accesso diretto e non attraverso la raccolta?

ho letto How do I convert from int to Long in Java? e Converting Integer to Long, ma non abbiamo davvero ottenere risposte soddisfacenti alla mia domanda.

+1

Puoi provare a compilarlo con 'javac'? Ho anche avuto questo problema e credo che sia un bug di eclissi. Se ho aggiunto il cast nel mio codice, ha emesso un avviso "Cast non necessario" ... :) –

+0

Non riesco a replicare sul mio computer. Funziona perfettamente bene nella mia con Java8. – Jatin

+2

Questo è in effetti un bug nel compilatore interno di Eclipse. Nota: Eclipse non usa il comando 'javac' da un JDK installato, ma usa un compilatore interno. Questo compilatore riporta l'errore. La compilazione con gli strumenti JDK funziona bene. – Seelenvirtuose

risposta

7

Secondo il JLS for Java 8 questo non dovrebbe accadere:

5.1.2. Ampliamento di conversione Primitive

19 conversioni specifiche su tipi primitivi sono chiamati i allargando conversioni primitive:

[..]

  • int a long, float, o doppio

[..]

5.1.8. Conversione Unboxing

[..]

  • Dal tipo Integer al tipo int

Che cosa dovrebbe accadere è un unboxing da Integer a int, e quindi una conversione ampliamento a long. In realtà ciò sta accadendo come previsto in Oracle JDK (1.8.0.25).

Credo che tu abbia trovato un bug del compilatore nel tuo JDK. Probabilmente dovresti provare una versione aggiornata o presentare un bug ai manutentori.

+1

Hai ragione. Usare 'javac' da un JDK funziona bene. Sembra un bug nel compilatore di Eclipse. – Seelenvirtuose

+2

Questo sembra essere risolto in Eclipse Mars 4.5.0 – Ian2thedv

6

Un bug noto Eclipse: https://bugs.eclipse.org/bugs/show_bug.cgi?id=440019

fissato in Eclipse 4.5 M3.

+0

Vorrei avere un modo per ottenere la correzione in STS 3.6 .. è lì? – jayP

+0

Non ne sono a conoscenza. Ho semplicemente scaricato la nuova versione e va bene. Ma sì, posso immaginare una configurazione in cui non si desidera aggiornare (o non è possibile). Cerca di contattare le persone dalla sts da qualche parte. –

Problemi correlati