Che cos'è un tipo raw e perché non dovremmo usarlo?


662

Domande:

  • Quali sono i tipi non elaborati in Java e perché sento spesso che non dovrebbero essere utilizzati nel nuovo codice?
  • Qual è l'alternativa se non possiamo usare i tipi grezzi e come è meglio?

le esercitazioni java usano ancora JComboBox che causa questo avviso. Quale versione della casella combinata non causerà questo avviso? docs.oracle.com/javase/tutorial/uiswing/components/…
SuperStar

1
Si noti che il motivo per cui esistono tipi non elaborati è la retrocompatibilità con Java 1.4 e precedenti, che non avevano affatto generici.
Jesper,

Risposte:


744

Che cos'è un tipo grezzo?

La specifica del linguaggio Java definisce un tipo non elaborato come segue:

JLS 4.8 Tipi grezzi

Un tipo grezzo è definito come uno di:

  • Il tipo di riferimento che si forma prendendo il nome di una dichiarazione di tipo generico senza un elenco di argomenti di tipo associato.

  • Un tipo di matrice il cui tipo di elemento è un tipo non elaborato.

  • Un statictipo non membro di un tipo Rnon elaborato che non è ereditato da una superclasse o superinterfaccia di R.

Ecco un esempio per illustrare:

public class MyType<E> {
    class Inner { }
    static class Nested { }

    public static void main(String[] args) {
        MyType mt;          // warning: MyType is a raw type
        MyType.Inner inn;   // warning: MyType.Inner is a raw type

        MyType.Nested nest; // no warning: not parameterized type
        MyType<Object> mt1; // no warning: type parameter given
        MyType<?> mt2;      // no warning: type parameter given (wildcard OK!)
    }
}

Qui, MyType<E>è un tipo con parametri ( JLS 4.5 ). È comune riferirsi colloquialmente a questo tipo semplicemente come MyTypeabbreviazione, ma tecnicamente il nome è MyType<E>.

mtha un tipo non elaborato (e genera un avviso di compilazione) dal primo punto elenco nella definizione sopra; innha anche un tipo non elaborato dal terzo punto elenco.

MyType.Nestednon è un tipo con parametri, anche se è un tipo membro di un tipo con parametri MyType<E>, perché lo è static.

mt1e mt2sono entrambi dichiarati con parametri di tipo reali, quindi non sono tipi non elaborati.


Cosa c'è di così speciale nei tipi grezzi?

In sostanza, i tipi grezzi si comportano esattamente come prima dell'introduzione dei farmaci generici. Cioè, quanto segue è completamente legale in fase di compilazione.

List names = new ArrayList(); // warning: raw type!
names.add("John");
names.add("Mary");
names.add(Boolean.FALSE); // not a compilation error!

Il codice sopra funziona bene, ma supponiamo che tu abbia anche il seguente:

for (Object o : names) {
    String name = (String) o;
    System.out.println(name);
} // throws ClassCastException!
  //    java.lang.Boolean cannot be cast to java.lang.String

Ora ci troviamo in difficoltà in fase di esecuzione, perché namescontiene qualcosa che non è un instanceof String.

Presumibilmente, se si desidera namescontenere solo String, è possibile utilizzare comunque un tipo non elaborato e controllare manualmente tutti gli elementiadd , quindi eseguire manualmente il cast su Stringogni elemento names. Ancora meglio , sebbene NON sia usare un tipo grezzo e lasciare che il compilatore faccia tutto il lavoro per te , sfruttando la potenza dei generici Java.

List<String> names = new ArrayList<String>();
names.add("John");
names.add("Mary");
names.add(Boolean.FALSE); // compilation error!

Naturalmente, se si SI desidera namesdi consentire una Boolean, allora è possibile dichiarare come List<Object> names, e il codice di cui sopra sarebbe la compilazione.

Guarda anche


In che modo un tipo grezzo è diverso dall'uso <Object>come parametri di tipo?

Quella che segue è una citazione da Effective Java 2nd Edition, Item 23: Non usare tipi grezzi nel nuovo codice :

Qual è la differenza tra il tipo grezzo Liste il tipo parametrizzato List<Object>? In parole povere, il primo ha disattivato il controllo di tipo generico, mentre il secondo ha esplicitamente dichiarato al compilatore che è in grado di contenere oggetti di qualsiasi tipo. Mentre puoi passare List<String>a un parametro di tipo List, non puoi passarlo a un parametro di tipo List<Object>. Esistono regole di sottotipo per generici ed List<String>è un sottotipo di tipo raw List, ma non di tipo parametrizzato List<Object>. Di conseguenza, si perde la sicurezza del tipo se si utilizza un tipo grezzo simile List, ma non se si utilizza un tipo con parametri simileList<Object> .

Per illustrare il punto, considerare il seguente metodo che accetta a List<Object>e aggiunge a new Object().

void appendNewObject(List<Object> list) {
   list.add(new Object());
}

I generici in Java sono invarianti. A List<String>non è a List<Object>, quindi quanto segue genererebbe un avviso del compilatore:

List<String> names = new ArrayList<String>();
appendNewObject(names); // compilation error!

Se avessi dichiarato appendNewObjectdi prendere un tipo Listnon elaborato come parametro, questo verrebbe compilato e perderai quindi la sicurezza del tipo che ottieni dai generici.

Guarda anche


In che modo un tipo grezzo è diverso dall'uso <?>come parametro di tipo?

List<Object>, List<String>ecc. sono tutti List<?>, quindi potrebbe essere allettante dire che sono solo Listinvece. Tuttavia, c'è una grande differenza: dal momento che a List<E>definisce solo add(E), non è possibile aggiungere qualsiasi oggetto arbitrario a List<?>. D'altra parte, dal momento che il tipo grezzo Listnon ha la sicurezza del tipo, puoi fare addqualsiasi cosa a List.

Considera la seguente variazione del frammento precedente:

static void appendNewObject(List<?> list) {
    list.add(new Object()); // compilation error!
}
//...

List<String> names = new ArrayList<String>();
appendNewObject(names); // this part is fine!

Il compilatore ha fatto un ottimo lavoro nel proteggerti dal violare potenzialmente l'invarianza del tipo di List<?>! Se avessi dichiarato il parametro come tipo non elaborato List list, il codice verrebbe compilato e violeresti il ​​tipo invariante List<String> names.


Un tipo grezzo è la cancellazione di quel tipo

Torna a JLS 4.8:

È possibile utilizzare come tipo la cancellazione di un tipo con parametri o la cancellazione di un tipo di array il cui tipo di elemento è un tipo con parametri. Tale tipo è chiamato tipo grezzo .

[...]

Le superclassi (rispettivamente, superinterfacce) di un tipo grezzo sono le cancellazioni delle superclasse (superinterfacce) di una qualsiasi delle parametrizzazioni del tipo generico.

Il tipo di un costruttore, metodo di istanza o non staticcampo di un tipo grezzo Cche non è ereditato dalle sue superclassi o superinterfacce è il tipo grezzo che corrisponde alla cancellazione del suo tipo nella dichiarazione generica corrispondente C.

In termini più semplici, quando viene utilizzato un tipo non staticelaborato, vengono eliminati anche i costruttori, i metodi di istanza e i non campi .

Prendi il seguente esempio:

class MyType<E> {
    List<String> getNames() {
        return Arrays.asList("John", "Mary");
    }

    public static void main(String[] args) {
        MyType rawType = new MyType();
        // unchecked warning!
        // required: List<String> found: List
        List<String> names = rawType.getNames();
        // compilation error!
        // incompatible types: Object cannot be converted to String
        for (String str : rawType.getNames())
            System.out.print(str);
    }
}

Quando usiamo il raw MyType, anche questo getNamesviene cancellato, in modo che restituisca un raw List!

JLS 4.6 continua a spiegare quanto segue:

La cancellazione del tipo associa anche la firma di un costruttore o metodo a una firma che non ha tipi con parametri o variabili di tipo. La cancellazione della firma di un costruttore o di un metodo sè una firma composta dallo stesso nome se dalla cancellazione di tutti i tipi di parametri formali indicati s.

Anche il tipo restituito di un metodo e i parametri del tipo di un metodo generico o di un costruttore vengono cancellati se viene cancellata la firma del metodo o del costruttore.

La cancellazione della firma di un metodo generico non ha parametri di tipo.

La seguente segnalazione di bug contiene alcuni pensieri di Maurizio Cimadamore, un compilatore e Alex Buckley, uno degli autori del JLS, sul perché questo tipo di comportamento dovrebbe verificarsi: https://bugs.openjdk.java.net/browse / JDK-6400189 . (In breve, rende le specifiche più semplici.)


Se non è sicuro, perché è consentito utilizzare un tipo non elaborato?

Ecco un'altra citazione da JLS 4.8:

L'uso di tipi grezzi è consentito solo come concessione alla compatibilità del codice legacy. L'uso di tipi grezzi nel codice scritto dopo l'introduzione della genericità nel linguaggio di programmazione Java è fortemente scoraggiato. È possibile che le versioni future del linguaggio di programmazione Java non consentano l'utilizzo di tipi non elaborati.

Efficace Java 2nd Edition ha anche questo da aggiungere:

Dato che non dovresti usare tipi non elaborati, perché i designer linguistici li hanno autorizzati? Per fornire compatibilità.

La piattaforma Java stava per entrare nel suo secondo decennio quando furono introdotti i generici e esisteva un'enorme quantità di codice Java che non usava i generici. È stato ritenuto fondamentale che tutto questo codice rimanga legale e interoperabile con il nuovo codice che utilizza generici. Doveva essere legale passare istanze di tipi parametrizzati a metodi che erano progettati per l'uso con tipi ordinari e viceversa. Questo requisito, noto come compatibilità della migrazione , ha guidato la decisione di supportare tipi non elaborati.

In sintesi, i tipi non elaborati non devono MAI essere utilizzati nel nuovo codice. È necessario utilizzare sempre tipi con parametri .


Non ci sono eccezioni?

Sfortunatamente, poiché i generici Java non sono reificati, ci sono due eccezioni in cui i tipi non elaborati devono essere utilizzati nel nuovo codice:

  • Letterali di classe, ad esempio List.class, nonList<String>.class
  • instanceofoperando, ad es o instanceof Set. noo instanceof Set<String>

Guarda anche


16
Cosa intendi con "I generici Java non sono reificati"?
Carl G,

7
Per la seconda eccezione, la sintassi o instanceof Set<?>può anche evitare il tipo grezzo (anche se in questo caso è solo superficiale).
Paul Bellora,

1
I tipi non elaborati sono molto utili e riducono il codice del boilerplate nel caso di ricerche JNDI per un bean che estende un'interfaccia. Ciò risolve la necessità di scrivere nbean remoti per ogni classe di implementazione con codice identico.
djmj,

8
"Non reificato" è un altro modo di dire che sono stati cancellati. Il compilatore sa quali sono i parametri generici, ma tali informazioni non vengono trasmesse al bytecode generato. JLS richiede che i letterali di classe non abbiano parametri di tipo.
Erick G. Hagstrom,

2
@OldCurmudgeon È interessante. Intendo ufficialmente non è nessuno dei due , perché una classe letterale definita come giusta TypeName.class, dove TypeNameè un semplice identificatore ( jls ). Parlando ipoteticamente, immagino che potrebbe essere davvero neanche. Forse come indizio, List<String>.classè la variante che JLS chiama specificamente un errore del compilatore, quindi se mai lo aggiungessero alla lingua mi aspetterei che sia quello che usano.
Radiodef,

62

Quali sono i tipi non elaborati in Java e perché sento spesso che non dovrebbero essere utilizzati nel nuovo codice?

I tipi grezzi sono la storia antica del linguaggio Java. All'inizio c'erano Collectionse non contenevano Objectsniente di più e niente di meno. Ogni operazione su Collectionscast richiesto dal Objecttipo desiderato.

List aList = new ArrayList();
String s = "Hello World!";
aList.add(s);
String c = (String)aList.get(0);

Mentre questo ha funzionato per la maggior parte del tempo, si sono verificati errori

List aNumberList = new ArrayList();
String one = "1";//Number one
aNumberList.add(one);
Integer iOne = (Integer)aNumberList.get(0);//Insert ClassCastException here

Le vecchie raccolte senza nome non potevano applicare la sicurezza dei tipi, quindi il programmatore doveva ricordare ciò che aveva archiviato all'interno di una raccolta.
I generici sono stati inventati per aggirare questa limitazione, lo sviluppatore avrebbe dichiarato il tipo memorizzato una volta e il compilatore invece lo avrebbe fatto.

List<String> aNumberList = new ArrayList<String>();
aNumberList.add("one");
Integer iOne = aNumberList.get(0);//Compile time error
String sOne = aNumberList.get(0);//works fine

Per confronto:

// Old style collections now known as raw types
List aList = new ArrayList(); //Could contain anything
// New style collections with Generics
List<String> aList = new ArrayList<String>(); //Contains only Strings

Più complessa l'interfaccia Compareable:

//raw, not type save can compare with Other classes
class MyCompareAble implements CompareAble
{
   int id;
   public int compareTo(Object other)
   {return this.id - ((MyCompareAble)other).id;}
}
//Generic
class MyCompareAble implements CompareAble<MyCompareAble>
{
   int id;
   public int compareTo(MyCompareAble other)
   {return this.id - other.id;}
}

Si noti che è impossibile implementare l' CompareAbleinterfaccia con compareTo(MyCompareAble)tipi non elaborati. Perché non dovresti usarli:

  • Qualsiasi oggetto Objectmemorizzato in a Collectiondeve essere lanciato prima di poter essere utilizzato
  • L'uso di generics abilita i controlli del tempo di compilazione
  • L'uso di tipi non elaborati equivale a memorizzare ciascun valore di Object

Cosa fa il compilatore: i generici sono retrocompatibili, usano le stesse classi java dei tipi grezzi. La magia avviene principalmente in fase di compilazione.

List<String> someStrings = new ArrayList<String>();
someStrings.add("one");
String one = someStrings.get(0);

Sarà compilato come:

List someStrings = new ArrayList();
someStrings.add("one"); 
String one = (String)someStrings.get(0);

Questo è lo stesso codice che scriveresti se utilizzassi direttamente i tipi grezzi. Pensato che non sono sicuro di cosa accada con l' CompareAbleinterfaccia, immagino che crei due compareTofunzioni, una che prende una MyCompareAblee l'altra che la prende Objecte la passa alla prima dopo averla lanciata.

Quali sono le alternative ai tipi grezzi: usa generici


30

Un tipo non elaborato è il nome di una classe o interfaccia generica senza argomenti di tipo. Ad esempio, data la classe Box generica:

public class Box<T> {
    public void set(T t) { /* ... */ }
    // ...
}

Per creare un tipo con parametri di Box<T>, si fornisce un argomento di tipo effettivo per il parametro di tipo formale T:

Box<Integer> intBox = new Box<>();

Se l'argomento del tipo effettivo viene omesso, si crea un tipo non elaborato di Box<T>:

Box rawBox = new Box();

Pertanto, Boxè il tipo non elaborato del tipo generico Box<T>. Tuttavia, una classe non generica o un tipo di interfaccia non è un tipo non elaborato.

I tipi non elaborati vengono visualizzati nel codice legacy perché molte classi API (come le classi Collections) non erano generiche prima di JDK 5.0. Quando si utilizzano tipi non elaborati, si ottiene essenzialmente un comportamento pre-generico - a Boxti dà Objects. Per compatibilità con le versioni precedenti, è consentita l'assegnazione di un tipo con parametri al suo tipo non elaborato:

Box<String> stringBox = new Box<>();
Box rawBox = stringBox;               // OK

Ma se si assegna un tipo non elaborato a un tipo con parametri, viene visualizzato un avviso:

Box rawBox = new Box();           // rawBox is a raw type of Box<T>
Box<Integer> intBox = rawBox;     // warning: unchecked conversion

Viene inoltre visualizzato un avviso se si utilizza un tipo non elaborato per richiamare metodi generici definiti nel tipo generico corrispondente:

Box<String> stringBox = new Box<>();
Box rawBox = stringBox;
rawBox.set(8);  // warning: unchecked invocation to set(T)

L'avvertimento mostra che i tipi non elaborati ignorano i controlli dei tipi generici, rinviando la cattura del codice non sicuro al runtime. Pertanto, è necessario evitare di utilizzare tipi non elaborati.

La sezione Cancellazione del tipo contiene ulteriori informazioni su come il compilatore Java utilizza tipi non elaborati.

Messaggi di errore non selezionati

Come accennato in precedenza, quando si mescolano codice legacy con codice generico, è possibile che vengano visualizzati messaggi di avviso simili ai seguenti:

Nota: Example.java utilizza operazioni non selezionate o non sicure.

Nota: ricompilare con -Xlint: deselezionato per i dettagli.

Ciò può accadere quando si utilizza un'API precedente che opera su tipi non elaborati, come mostrato nell'esempio seguente:

public class WarningDemo {
    public static void main(String[] args){
        Box<Integer> bi;
        bi = createBox();
    }

    static Box createBox(){
        return new Box();
    }
}

Il termine "deselezionato" significa che il compilatore non ha abbastanza informazioni sul tipo per eseguire tutti i controlli del tipo necessari per garantire la sicurezza del tipo. L'avviso "deselezionato" è disabilitato, per impostazione predefinita, anche se il compilatore dà un suggerimento. Per visualizzare tutti gli avvisi "non selezionati", ricompilare con -Xlint: non selezionato.

Ricompilare l'esempio precedente con -Xlint: deselezionato rivela le seguenti informazioni aggiuntive:

WarningDemo.java:4: warning: [unchecked] unchecked conversion
found   : Box
required: Box<java.lang.Integer>
        bi = createBox();
                      ^
1 warning

Per disabilitare completamente gli avvisi non controllati, utilizzare il flag -Xlint: -unchecked. L' @SuppressWarnings("unchecked")annotazione elimina gli avvisi non selezionati. Se non si ha familiarità con la @SuppressWarningssintassi, consultare Annotazioni.

Fonte originale: Java Tutorials


21

Un tipo "raw" in Java è una classe non generica che si occupa di oggetti "grezzi" anziché di parametri di tipo generico sicuri per il tipo.

Ad esempio, prima che i generici Java fossero disponibili, dovresti usare una classe di raccolta come questa:

LinkedList list = new LinkedList();
list.add(new MyObject());
MyObject myObject = (MyObject)list.get(0);

Quando aggiungi il tuo oggetto all'elenco, non importa quale sia il tipo di oggetto e quando lo ottieni dall'elenco, devi esplicitamente lanciarlo sul tipo che ti aspetti.

Usando generics, rimuovi il fattore "sconosciuto", perché devi specificare esplicitamente quale tipo di oggetti può andare nella lista:

LinkedList<MyObject> list = new LinkedList<MyObject>();
list.add(new MyObject());
MyObject myObject = list.get(0);

Si noti che con generici non è necessario eseguire il cast dell'oggetto proveniente dalla chiamata get, la raccolta è predefinita per funzionare solo con MyObject. Questo fatto è il principale fattore trainante per i generici. Cambia una fonte di errori di runtime in qualcosa che può essere verificato in fase di compilazione.


3
Più specificamente, un tipo non elaborato è ciò che si ottiene omettendo semplicemente i parametri del tipo per un tipo generico. I tipi non elaborati erano in realtà solo una funzionalità di retrocompatibilità e sono potenzialmente soggetti a rimozione. Puoi ottenere un comportamento simile usando? parametri jolly.
John Flatness,

@zerocrates: simile ma diverso! L'utilizzo ?offre ancora sicurezza del tipo. L'ho coperto nella mia risposta.
poligenelubrificanti

19
 private static List<String> list = new ArrayList<String>();

È necessario specificare il parametro-tipo.

L'avvertimento avvisa che i tipi definiti per supportare generici dovrebbero essere parametrizzati, piuttosto che usare la loro forma grezza.

Listè definita generici di supporto: public class List<E>. Ciò consente molte operazioni di tipo sicuro, verificate durante la compilazione.


3
Ora sostituito dall'inferenza del diamante in Java 7 -private static List<String> list = new ArrayList<>();
Ian Campbell,

14

Che cos'è un tipo non elaborato e perché sento spesso che non devono essere utilizzati nel nuovo codice?

Un "tipo grezzo" è l'uso di una classe generica senza specificare un argomento di tipo per i suoi tipi parametrizzati, ad esempio usando Listinvece di List<String>. Quando i generici furono introdotti in Java, diverse classi furono aggiornate per usare i generici. L'uso di questa classe come "tipo non elaborato" (senza specificare un argomento di tipo) ha consentito la compilazione del codice legacy.

I "tipi grezzi" vengono utilizzati per la compatibilità con le versioni precedenti. Il loro uso nel nuovo codice non è raccomandato perché l'uso della classe generica con un argomento di tipo consente una digitazione più forte, che a sua volta può migliorare la comprensibilità del codice e portare a rilevare potenziali problemi in precedenza.

Qual è l'alternativa se non possiamo usare i tipi grezzi e come è meglio?

L'alternativa preferita è utilizzare le classi generiche come previsto, con un argomento di tipo adatto (ad es List<String>.). Ciò consente al programmatore di specificare i tipi in modo più specifico, trasmette più significato ai futuri manutentori sull'uso previsto di una variabile o struttura di dati e consente al compilatore di applicare una migliore sicurezza dei tipi. Questi vantaggi insieme possono migliorare la qualità del codice e aiutare a prevenire l'introduzione di alcuni errori di codifica.

Ad esempio, per un metodo in cui il programmatore desidera assicurarsi che una variabile di elenco denominata "nomi" contenga solo stringhe:

List<String> names = new ArrayList<String>();
names.add("John");          // OK
names.add(new Integer(1));  // compile error

1
Ah, sono così tentato di copiare polygenelubricantsi riferimenti "grezzi" da stackoverflow.com/questions/2770111/… nella mia risposta, ma suppongo che li lascerò per l'uso nella propria risposta.
Bert F

1
sì, ho essenzialmente copiato e incollato quel segmento ovunque le persone usino i tipi non elaborati su StackOverflow e alla fine ho deciso di fare solo una domanda a cui fare riferimento da ora in poi. Spero sia un buon contributo per la comunità.
poligenelubrificanti

1
@polygenelubricants che ho notato - rispondiamo ad alcune delle stesse domande :-)
Bert F

1
@ ha9u63ar: Infatti. In generale, le risposte concise e semplici sono almeno altrettanto valide di quelle lunghe e accettate.
displayName

Che cos'è la "syping più forte"?
carloswm85,

12

Il compilatore vuole che tu scriva questo:

private static List<String> list = new ArrayList<String>();

perché in caso contrario, è possibile aggiungere qualsiasi tipo in cui ti piace list, rendendo l'istanza come new ArrayList<String>()inutile. I generici Java sono solo una funzione di compilazione, quindi un oggetto creato con new ArrayList<String>()esso accetterà felicemente Integero JFrameelementi se assegnato a un riferimento del "tipo grezzo" List- l'oggetto stesso non sa nulla di quali tipi dovrebbe contenere, solo il compilatore.


12

Qui sto prendendo in considerazione più casi attraverso i quali è possibile chiarire il concetto

1. ArrayList<String> arr = new ArrayList<String>();
2. ArrayList<String> arr = new ArrayList();
3. ArrayList arr = new ArrayList<String>();

Caso 1

ArrayList<String> arrè una ArrayListvariabile di riferimento con tipo Stringche fa riferimento a un ArralyListoggetto di tipo String. Significa che può contenere solo oggetti di tipo String.

È rigoroso Stringnon un tipo grezzo, quindi non genererà mai un avviso.

    arr.add("hello");// alone statement will compile successfully and no warning.

    arr.add(23);  //prone to compile time error.
     //error: no suitable method found for add(int)

Caso 2

In questo caso ArrayList<String> arrè un tipo rigoroso ma l'oggetto new ArrayList();è un tipo non elaborato.

    arr.add("hello"); //alone this compile but raise the warning.
    arr.add(23);  //again prone to compile time error.
    //error: no suitable method found for add(int)

ecco arrun tipo rigoroso. Quindi, aumenterà l'errore di compilazione quando si aggiunge a integer.

Avvertenza : - A un Rawoggetto tipo si fa riferimento a un Stricttipo Variabile referenziata di ArrayList.

Caso 3

In questo caso ArrayList arrè un tipo non elaborato ma l'oggetto new ArrayList<String>();è di tipo rigoroso.

    arr.add("hello");  
    arr.add(23);  //compiles fine but raise the warning.

Aggiungerà qualsiasi tipo di oggetto perché arrè un tipo non elaborato.

Avvertenza : - Un Strictoggetto di tipo fa riferimento a una rawvariabile di riferimento di tipo.


8

Un tipo grezzo è la mancanza di un parametro di tipo quando si utilizza un tipo generico.

Il tipo raw non dovrebbe essere usato perché potrebbe causare errori di runtime, come l'inserimento di a doublein quello che doveva essere uno Setdi ints.

Set set = new HashSet();
set.add(3.45); //ok

Quando recuperi le cose da Set, non sai cosa sta per uscire. Supponiamo che ti aspetti che sia tutto ints, lo stai lanciando Integer; eccezione in fase di esecuzione quando doublearriva la 3.45.

Con un parametro type aggiunto al tuo Set, otterrai subito un errore di compilazione. Questo errore preventivo consente di risolvere il problema prima che qualcosa rompa durante l'esecuzione (risparmiando così tempo e fatica).

Set<Integer> set = new HashSet<Integer>();
set.add(3.45); //NOT ok.

7

Ecco un altro caso in cui i tipi grezzi ti morderanno:

public class StrangeClass<T> {
  @SuppressWarnings("unchecked")
  public <X> X getSomethingElse() {
    return (X)"Testing something else!";
  }

  public static void main(String[] args) {
    final StrangeClass<String> withGeneric    = new StrangeClass<>();
    final StrangeClass         withoutGeneric = new StrangeClass();
    final String               value1,
                               value2;

    // Compiles
    value1 = withGeneric.getSomethingElse();

    // Produces compile error:
    // incompatible types: java.lang.Object cannot be converted to java.lang.String
    value2 = withoutGeneric.getSomethingElse();
  }
}

Come indicato nella risposta accettata, si perde tutto il supporto per i generici all'interno del codice di tipo raw. Ogni parametro di tipo viene convertito nella sua cancellazione (che nell'esempio sopra è solo Object).


5

Quello che sta dicendo è che si listtratta Listdi oggetti non specificati. Cioè Java non sa che tipo di oggetti sono presenti nell'elenco. Quindi, quando si desidera iterare l'elenco, è necessario eseguire il cast di tutti gli elementi, per poter accedere alle proprietà di quell'elemento (in questo caso, String).

In generale è un'idea migliore per parametrizzare le raccolte, quindi non hai problemi di conversione, sarai solo in grado di aggiungere elementi del tipo parametrizzato e il tuo editor ti offrirà i metodi appropriati per selezionare.

private static List<String> list = new ArrayList<String>();

4

pagina tutorial .

Un tipo non elaborato è il nome di una classe o interfaccia generica senza argomenti di tipo. Ad esempio, data la classe Box generica:

public class Box<T> {
    public void set(T t) { /* ... */ }
    // ...
}

Per creare un tipo con parametri di Box, è necessario fornire un argomento di tipo effettivo per il parametro di tipo formale T:

Box<Integer> intBox = new Box<>();

Se l'argomento del tipo effettivo viene omesso, si crea un tipo grezzo di Box:

Box rawBox = new Box();

2

Evita i tipi grezzi

I tipi non elaborati si riferiscono all'utilizzo di un tipo generico senza specificare un parametro di tipo.

Per esempio ,

Un elenco è un tipo non elaborato, mentre List<String>è un tipo con parametri.

Quando i generici furono introdotti in JDK 1.5, i tipi grezzi furono mantenuti solo per mantenere la retrocompatibilità con le versioni precedenti di Java. Sebbene sia ancora possibile utilizzare tipi non elaborati,

Dovrebbero essere evitati :

  • Di solito richiedono lanci
  • Non sono sicuri, e alcuni importanti tipi di errori appariranno solo in fase di esecuzione
  • Sono meno espressivi e non auto-documentano allo stesso modo dei tipi parametrizzati Esempio

    import java.util.*;
    
    public final class AvoidRawTypes {
    
    void withRawType() {
    
        //Raw List doesn't self-document, 
        //doesn't state explicitly what it can contain
    
        List stars = Arrays.asList("Arcturus", "Vega", "Altair");
    
        Iterator iter = stars.iterator();
    
        while (iter.hasNext()) {
    
            String star = (String) iter.next(); //cast needed
    
            log(star);
        }
    
    }
    
    void withParameterizedType() {
    
        List < String > stars = Arrays.asList("Spica", "Regulus", "Antares");
    
        for (String star: stars) {
    
            log(star);
        }
    
    }
    
    private void log(Object message) {
    
        System.out.println(Objects.toString(message));
    
    }
    
    }

Per riferimento : https://docs.oracle.com/javase/tutorial/java/generics/rawTypes.html


1

Ho trovato questa pagina dopo aver fatto alcuni esercizi di esempio e avere lo stesso perplesso esatto.

============== Sono passato da questo codice come fornito dall'esempio ===============

public static void main(String[] args) throws IOException {

    Map wordMap = new HashMap();
    if (args.length > 0) {
        for (int i = 0; i < args.length; i++) {
            countWord(wordMap, args[i]);
        }
    } else {
        getWordFrequency(System.in, wordMap);
    }
    for (Iterator i = wordMap.entrySet().iterator(); i.hasNext();) {
        Map.Entry entry = (Map.Entry) i.next();
        System.out.println(entry.getKey() + " :\t" + entry.getValue());
    }

====================== A questo codice ========================

public static void main(String[] args) throws IOException {
    // replace with TreeMap to get them sorted by name
    Map<String, Integer> wordMap = new HashMap<String, Integer>();
    if (args.length > 0) {
        for (int i = 0; i < args.length; i++) {
            countWord(wordMap, args[i]);
        }
    } else {
        getWordFrequency(System.in, wordMap);
    }
    for (Iterator<Entry<String, Integer>> i = wordMap.entrySet().iterator(); i.hasNext();) {
        Entry<String, Integer> entry =   i.next();
        System.out.println(entry.getKey() + " :\t" + entry.getValue());
    }

}

================================================== =============================

Potrebbe essere più sicuro, ma ci sono volute 4 ore per sminuire la filosofia ...


0

I tipi grezzi vanno bene quando esprimono ciò che vuoi esprimere.

Ad esempio, una funzione di deserializzazione potrebbe restituire a List, ma non conosce il tipo di elemento dell'elenco. Quindi Listè il tipo di ritorno appropriato qui.


Puoi usare ? come parametro di tipo
Dániel Kis il

Sì, ma questo è più da digitare e io sono contrario a digitare di più. :)
Stefan Reich il
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.