¿Qué es un tipo sin procesar y por qué no deberíamos usarlo?

663

Preguntas:

  • ¿Qué son los tipos sin formato en Java y por qué a menudo escucho que no deberían usarse en un código nuevo?
  • ¿Cuál es la alternativa si no podemos usar tipos sin formato y cómo es mejor?
poligenelubricantes
fuente
los tutoriales de Java todavía usan el JComboBox que causa esta advertencia. ¿Qué versión del cuadro combinado no causará esta advertencia? docs.oracle.com/javase/tutorial/uiswing/components/…
SuperStar
1
Tenga en cuenta que la razón por la que existen tipos sin formato es la compatibilidad con versiones anteriores de Java 1.4 y anteriores, que no tenían genéricos en absoluto.
Jesper

Respuestas:

745

¿Qué es un tipo crudo?

La especificación del lenguaje Java define un tipo sin procesar de la siguiente manera:

Tipos sin procesar de JLS 4.8

Un tipo sin formato se define como uno de:

  • El tipo de referencia que se forma tomando el nombre de una declaración de tipo genérico sin una lista de argumentos de tipo acompañante.

  • Un tipo de matriz cuyo tipo de elemento es un tipo sin formato.

  • Un statictipo no miembro de un tipo sin formato Rque no se hereda de una superclase o superinterfaz de R.

Aquí hay un ejemplo para ilustrar:

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!)
    }
}

Aquí, MyType<E>es un tipo parametrizado ( JLS 4.5 ). Es común referirse coloquialmente a este tipo simplemente MyTypepara abreviar, pero técnicamente el nombre es MyType<E>.

mttiene un tipo sin formato (y genera una advertencia de compilación) por el primer punto en la definición anterior; inntambién tiene un tipo sin formato en el tercer punto de viñeta

MyType.Nestedno es un tipo parametrizado, aunque es un tipo de miembro de un tipo parametrizado MyType<E>, porque lo es static.

mt1, y mt2ambos se declaran con parámetros de tipo reales, por lo que no son tipos sin formato.


¿Qué tienen de especial los tipos sin procesar?

Esencialmente, los tipos sin procesar se comportan tal como eran antes de que se introdujeran los genéricos. Es decir, lo siguiente es completamente legal en tiempo de compilación.

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

El código anterior funciona bien, pero supongamos que también tiene lo siguiente:

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

Ahora nos encontramos con problemas en tiempo de ejecución, porque namescontiene algo que no es un instanceof String.

Presumiblemente, si solo desea namescontener String, tal vez aún podría usar un tipo sin formato y verificar manualmente cada add uno, y luego emitir manualmente a Stringcada elemento desde names. Aún mejor , aunque NO es usar un tipo sin procesar y dejar que el compilador haga todo el trabajo por usted , aprovechando el poder de los genéricos de Java.

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

Por supuesto, si QUÉ desea namespara permitir una Boolean, entonces se puede declarar como List<Object> names, y el código anterior se compilará.

Ver también


¿En qué se diferencia un tipo sin formato de usar <Object>como parámetros de tipo?

La siguiente es una cita de Effective Java 2nd Edition, Artículo 23: No use tipos sin procesar en el nuevo código :

¿Cuál es la diferencia entre el tipo sin formato Listy el tipo parametrizado List<Object>? Hablando en términos generales, el primero ha optado por la verificación de tipos genéricos, mientras que el segundo le dijo explícitamente al compilador que es capaz de contener objetos de cualquier tipo. Si bien puede pasar List<String>a un parámetro de tipo List, no puede pasarlo a un parámetro de tipo List<Object>. Hay reglas de subtipo para genéricos, y List<String>es un subtipo del tipo sin formato List, pero no del tipo parametrizado List<Object>. Como consecuencia, pierde seguridad de tipo si usa un tipo sin formato como List, pero no si usa un tipo con parámetros comoList<Object> .

Para ilustrar el punto, considere el siguiente método que toma List<Object>ay agrega a new Object().

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

Los genéricos en Java son invariables. A List<String>no es a List<Object>, por lo que lo siguiente generaría una advertencia de compilación:

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

Si hubiera declarado appendNewObjecttomar un tipo sin formato Listcomo parámetro, esto se compilaría y, por lo tanto, perdería la seguridad de tipo que obtiene de los genéricos.

Ver también


¿En qué se diferencia un tipo sin formato del uso <?>como parámetro de tipo?

List<Object>, List<String>etc. son todos List<?>, por lo que puede ser tentador decir que son simplemente en su Listlugar. Sin embargo, hay una gran diferencia: dado que a List<E>solo define add(E), no puede agregar cualquier objeto arbitrario a a List<?>. Por otro lado, dado que el tipo sin Listformato no tiene seguridad de tipo, puede addcasi cualquier cosa para a List.

Considere la siguiente variación del fragmento anterior:

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

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

¡El compilador hizo un trabajo maravilloso al protegerlo de violar potencialmente la invariancia de tipo del List<?>! Si hubiera declarado el parámetro como tipo sin formato List list, el código se compilaría y violaría el tipo invariante de List<String> names.


Un tipo sin formato es el borrado de ese tipo

Volver a JLS 4.8:

Es posible utilizar como tipo la eliminación de un tipo parametrizado o la eliminación de un tipo de matriz cuyo tipo de elemento es un tipo parametrizado. Tal tipo se llama tipo crudo .

[...]

Las superclases (respectivamente, superinterfaces) de un tipo sin formato son los borrados de las superclases (superinterfaces) de cualquiera de las parametrizaciones del tipo genérico.

El tipo de constructor, método de instancia o no staticcampo de un tipo sin formato Cque no se hereda de sus superclases o superinterfaces es el tipo sin formato que corresponde a la eliminación de su tipo en la declaración genérica correspondiente a C.

En términos más simples, cuando se usa un tipo sin formato, los constructores, los métodos de instancia y los no staticcampos también se borran .

Tome el siguiente ejemplo:

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

Cuando usamos el raw MyType, también getNamesse borra, ¡para que devuelva un raw List!

JLS 4.6 continúa explicando lo siguiente:

El borrado de tipos también asigna la firma de un constructor o método a una firma que no tiene tipos parametrizados o variables de tipo. El borrado de una firma de constructor o método ses una firma que consta del mismo nombre sy borra todos los tipos de parámetros formales dados en s.

El tipo de retorno de un método y los parámetros de tipo de un método genérico o constructor también se borran si se borra la firma del método o del constructor.

La eliminación de la firma de un método genérico no tiene parámetros de tipo.

El siguiente informe de error contiene algunas reflexiones de Maurizio Cimadamore, un desarrollador del compilador, y Alex Buckley, uno de los autores de JLS, sobre por qué debería ocurrir este tipo de comportamiento: https://bugs.openjdk.java.net/browse / JDK-6400189 . (En resumen, simplifica la especificación).


Si no es seguro, ¿por qué está permitido usar un tipo sin formato?

Aquí hay otra cita de JLS 4.8:

El uso de tipos sin formato solo se permite como una concesión a la compatibilidad del código heredado. Se desaconseja el uso de tipos sin formato en el código escrito después de la introducción de la genérica en el lenguaje de programación Java. Es posible que futuras versiones del lenguaje de programación Java no permitan el uso de tipos sin formato.

Efectivo Java 2nd Edition también tiene esto para agregar:

Dado que no debe usar tipos sin formato, ¿por qué los diseñadores de idiomas lo permitieron? Para proporcionar compatibilidad.

La plataforma Java estaba a punto de entrar en su segunda década cuando se introdujeron los genéricos, y existía una enorme cantidad de código Java que no usaba genéricos. Se consideró crítico que todo este código siga siendo legal e interoperable con el nuevo código que usa genéricos. Tenía que ser legal pasar instancias de tipos parametrizados a métodos diseñados para su uso con tipos normales, y viceversa. Este requisito, conocido como compatibilidad de migración , llevó a la decisión de admitir tipos sin formato.

En resumen, los tipos sin formato NUNCA deben usarse en un código nuevo. Siempre debe usar tipos parametrizados .


¿No hay excepciones?

Desafortunadamente, debido a que los genéricos de Java no están reificados, hay dos excepciones en las que se deben usar tipos sin formato en el nuevo código:

  • Literales de clase, por ejemplo List.class, noList<String>.class
  • instanceofoperando, por ejemplo o instanceof Set, noo instanceof Set<String>

Ver también

poligenelubricantes
fuente
16
¿Qué quiere decir que "los genéricos de Java no están reificados"?
Carl G
77
Para la segunda excepción, la sintaxis o instanceof Set<?>también permite evitar el tipo sin formato (aunque en este caso solo es superficial).
Paul Bellora
1
Los tipos sin formato son muy útiles y reducen el código repetitivo en caso de búsquedas JNDI para un bean que extiende una interfaz. Esto resuelve la necesidad de escribir nbeans remotos para cada clase de implementación con código idéntico.
djmj
8
"No reificado" es otra forma de decir que se borran. El compilador sabe cuáles son los parámetros genéricos, pero esa información no se transmite al código de bytes generado. El JLS requiere que los literales de clase no tengan parámetros de tipo.
Erick G. Hagstrom
2
@OldCurmudgeon Eso es interesante. Quiero decir oficialmente que no es ninguno , porque un literal de clase definido como justo TypeName.class, donde TypeNamees un identificador simple ( jls ). Hablando hipotéticamente, supongo que realmente podría ser cualquiera. Tal vez como una pista, List<String>.classes la variante que JLS llama específicamente un error del compilador, por lo que si alguna vez lo agregan al lenguaje, esperaría que ese sea el que usan.
Radiodef
62

¿Qué son los tipos sin formato en Java y por qué a menudo escucho que no deberían usarse en un código nuevo?

Los tipos sin procesar son historia antigua del lenguaje Java. Al principio hubo Collectionsy no tenían Objectsnada más y nada menos. Cada operación en Collectionslos moldes requeridos del Objecttipo deseado.

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

Si bien esto funcionó la mayor parte del tiempo, ocurrieron errores

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

Las antiguas colecciones sin tipo no podían hacer cumplir la seguridad de tipo, por lo que el programador tuvo que recordar lo que almacenaba dentro de una colección.
Los genéricos se inventaron para evitar esta limitación, el desarrollador declararía el tipo almacenado una vez y el compilador lo haría en su lugar.

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

Para comparacion:

// 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

Más compleja es la interfaz Comparable:

//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;}
}

Tenga en cuenta que es imposible implementar la CompareAbleinterfaz con compareTo(MyCompareAble)tipos sin formato. Por qué no deberías usarlos:

  • Todo lo Objectalmacenado en un Collectiondebe ser lanzado antes de poder ser utilizado.
  • El uso de genéricos permite comprobaciones de tiempo de compilación
  • Usar tipos sin formato es lo mismo que almacenar cada valor como Object

Lo que hace el compilador: los genéricos son compatibles con versiones anteriores, usan las mismas clases de Java que los tipos sin formato. La magia ocurre principalmente en tiempo de compilación.

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

Será compilado como:

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

Este es el mismo código que escribiría si utilizara los tipos sin formato directamente. Aunque no estoy seguro de lo que sucede con la CompareAbleinterfaz, creo que crea dos compareTofunciones, una toma una MyCompareAbley la otra toma una Objecty se la pasa a la primera después de lanzarla.

¿Cuáles son las alternativas a los tipos sin procesar: usar genéricos

josefx
fuente
30

Un tipo sin formato es el nombre de una clase o interfaz genérica sin ningún tipo de argumento. Por ejemplo, dada la clase genérica Box:

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

Para crear un tipo parametrizado de Box<T>, debe proporcionar un argumento de tipo real para el parámetro de tipo formal T:

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

Si se omite el argumento de tipo real, crea un tipo sin formato de Box<T>:

Box rawBox = new Box();

Por lo tanto, Boxes el tipo sin formato del tipo genérico Box<T>. Sin embargo, una clase no genérica o tipo de interfaz no es un tipo sin formato.

Los tipos sin formato aparecen en el código heredado porque muchas clases de API (como las clases de Colecciones) no eran genéricas antes de JDK 5.0. Cuando se usan tipos sin procesar, esencialmente se obtiene un comportamiento pre-genérico: a Boxda Objects. Por compatibilidad con versiones anteriores, se permite asignar un tipo parametrizado a su tipo sin formato:

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

Pero si asigna un tipo sin formato a un tipo parametrizado, recibirá una advertencia:

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

También recibe una advertencia si usa un tipo sin procesar para invocar métodos genéricos definidos en el tipo genérico correspondiente:

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

La advertencia muestra que los tipos sin procesar omiten las comprobaciones de tipos genéricos, aplazando la captura de código inseguro en tiempo de ejecución. Por lo tanto, debe evitar el uso de tipos sin formato.

La sección de borrado de tipo tiene más información sobre cómo el compilador de Java usa tipos sin formato.

Mensajes de error no verificados

Como se mencionó anteriormente, al mezclar código heredado con código genérico, puede encontrar mensajes de advertencia similares a los siguientes:

Nota: Example.java utiliza operaciones no verificadas o inseguras.

Nota: Recompile con -Xlint: sin marcar para más detalles.

Esto puede suceder cuando se usa una API anterior que funciona con tipos sin formato, como se muestra en el siguiente ejemplo:

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

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

El término "desmarcado" significa que el compilador no tiene suficiente información de tipo para realizar todas las verificaciones de tipo necesarias para garantizar la seguridad de tipo. La advertencia "sin marcar" está deshabilitada, de forma predeterminada, aunque el compilador da una pista. Para ver todas las advertencias "sin marcar", vuelva a compilar con -Xlint: sin marcar.

Volver a compilar el ejemplo anterior con -Xlint: sin marcar revela la siguiente información adicional:

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

Para deshabilitar completamente las advertencias no verificadas, use el indicador -Xlint: -unchecked. La @SuppressWarnings("unchecked")anotación suprime las advertencias no verificadas. Si no está familiarizado con la @SuppressWarningssintaxis, vea Anotaciones.

Fuente original: Tutoriales de Java

Adelin
fuente
21

Un tipo "en bruto" en Java es una clase que no es genérica y trata con objetos "en bruto", en lugar de parámetros de tipo genérico con seguridad de tipo.

Por ejemplo, antes de que los genéricos de Java estuvieran disponibles, usaría una clase de colección como esta:

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

Cuando agrega su objeto a la lista, no le importa qué tipo de objeto es, y cuando lo obtiene de la lista, debe convertirlo explícitamente al tipo que espera.

Usando genéricos, elimina el factor "desconocido", porque debe especificar explícitamente qué tipo de objetos pueden ir en la lista:

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

Tenga en cuenta que con los genéricos no tiene que emitir el objeto proveniente de la llamada get, la colección está predefinida para funcionar solo con MyObject. Este mismo hecho es el principal factor impulsor de los genéricos. Cambia una fuente de errores de tiempo de ejecución en algo que se puede verificar en tiempo de compilación.

Andy White
fuente
3
Más específicamente, un tipo sin formato es lo que obtienes cuando simplemente omites los parámetros de tipo para un tipo genérico. Los tipos sin formato solo eran en realidad una característica de compatibilidad con versiones anteriores, y están potencialmente sujetos a eliminación. Puede obtener un comportamiento similar usando? Parámetros comodín.
John Flatness
@zerocrates: ¡similar pero diferente! Usar ?todavía ofrece seguridad de tipo. Lo cubrí en mi respuesta.
Polygenelubricants
19
 private static List<String> list = new ArrayList<String>();

Debe especificar el tipo-parámetro.

La advertencia informa que los tipos definidos para admitir genéricos deben ser parametrizados, en lugar de usar su forma sin formato.

Listse define a los genéricos de apoyo: public class List<E>. Esto permite muchas operaciones de tipo seguro, que se verifican en tiempo de compilación.

Bozho
fuente
3
Ahora reemplazado por la inferencia de diamantes en Java 7 -private static List<String> list = new ArrayList<>();
Ian Campbell
14

¿Qué es un tipo sin formato y por qué a menudo escucho que no deberían usarse en un código nuevo?

Un "tipo sin formato" es el uso de una clase genérica sin especificar un argumento de tipo (s) para su tipo (s) parametrizado, por ejemplo, usando en Listlugar de List<String>. Cuando se introdujeron los genéricos en Java, se actualizaron varias clases para usar los genéricos. El uso de estas clases como un "tipo sin formato" (sin especificar un argumento de tipo) permitió que el código heredado aún se compilara.

Los "tipos sin formato" se utilizan para la compatibilidad con versiones anteriores. No se recomienda su uso en código nuevo porque el uso de la clase genérica con un argumento de tipo permite una escritura más fuerte, lo que a su vez puede mejorar la comprensión del código y conducir a detectar problemas potenciales antes.

¿Cuál es la alternativa si no podemos usar tipos sin formato y cómo es mejor?

La alternativa preferida es utilizar clases genéricas según lo previsto, con un argumento de tipo adecuado (por ejemplo List<String>). Esto permite que el programador especifique tipos más específicamente, transmite más significado a los futuros mantenedores sobre el uso previsto de una estructura de datos o variable, y permite al compilador hacer cumplir una mejor seguridad de tipos. Estas ventajas juntas pueden mejorar la calidad del código y ayudar a prevenir la introducción de algunos errores de codificación.

Por ejemplo, para un método donde el programador quiere asegurarse de que una variable de Lista llamada 'nombres' contenga solo Cadenas:

List<String> names = new ArrayList<String>();
names.add("John");          // OK
names.add(new Integer(1));  // compile error
Bert F
fuente
1
Ah, estoy tentado de copiar polygenelubricantslas referencias de "tipo sin formato " de stackoverflow.com/questions/2770111/… en mi propia respuesta, pero supongo que las dejaré para usar en su propia respuesta.
Bert F
1
Sí, esencialmente he estado copiando y pegando ese segmento en todas partes donde las personas usan tipos sin procesar en stackoverflow, y finalmente decidí tener una pregunta para hacer referencia a partir de ahora. Espero que sea una buena contribución para la comunidad.
Polygenelubricants
1
@polygenelubricants que noté - respondimos algunas de las mismas preguntas :-)
Bert F
1
@ ha9u63ar: De hecho. En general, las respuestas concisas y simples son al menos tan buenas como las largas y aceptadas.
displayName
¿Qué es un "syping más fuerte"?
carloswm85
12

El compilador quiere que escribas esto:

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

porque de lo contrario, podría agregar cualquier tipo que desee list, haciendo que la instanciación no tenga new ArrayList<String>()sentido. Los genéricos de Java son solo una característica de tiempo de compilación, por lo que un objeto creado con new ArrayList<String>()felicidad aceptará elementos Integero JFrameelementos si se les asigna una referencia del "tipo sin formato" List: el objeto en sí mismo no sabe nada sobre los tipos que se supone que debe contener, solo el compilador lo sabe.

Michael Borgwardt
fuente
12

Aquí estoy considerando múltiples casos a través de los cuales puedes aclarar el concepto

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

Caso 1

ArrayList<String> arres una ArrayListvariable de referencia con tipo Stringque hace referencia a un ArralyListObjeto de tipo String. Significa que solo puede contener objetos de tipo cadena.

Es estricto Stringno un tipo sin procesar, por lo que nunca generará una advertencia.

    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

En este caso ArrayList<String> arres un tipo estricto pero su objeto new ArrayList();es un tipo sin formato.

    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)

Aquí arrhay un tipo estricto. Por lo tanto, generará un error de tiempo de compilación al agregar a integer.

Advertencia : - Un Rawobjeto de tipo está referenciado a una Strictvariable de tipo referenciada de ArrayList.

Caso 3

En este caso ArrayList arres un tipo sin formato, pero su objeto new ArrayList<String>();es un tipo estricto.

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

Agregará cualquier tipo de objeto porque arres un tipo sin formato.

Advertencia : - Un Strictobjeto de tipo está referenciado a una rawvariable de tipo referenciado.

Vikrant Kashyap
fuente
8

Un tipo sin formato es la falta de un parámetro de tipo cuando se usa un tipo genérico.

El tipo sin formato no se debe usar porque podría causar errores de tiempo de ejecución, como insertar una doubleen lo que se suponía que era una Setde ints.

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

Al recuperar las cosas del Set, no sabes lo que está saliendo. Supongamos que espera que sea todo ints, lo está emitiendo Integer; excepción en tiempo de ejecución cuando doublellega el 3.45.

Con un parámetro de tipo agregado a su Set, obtendrá un error de compilación de inmediato. Este error preventivo le permite solucionar el problema antes de que algo explote durante el tiempo de ejecución (ahorrando así tiempo y esfuerzo).

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

Aquí hay otro caso donde los tipos crudos te morderán:

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

Como se mencionó en la respuesta aceptada, pierde todo el soporte para genéricos dentro del código de tipo sin formato. Cada parámetro de tipo se convierte en su borrado (que en el ejemplo anterior es justo Object).

GuyPaddock
fuente
5

Lo que está diciendo es que tu listes un Listobjeto no especificado. Es decir, Java no sabe qué tipo de objetos están dentro de la lista. Luego, cuando desee iterar la lista, debe convertir cada elemento para poder acceder a las propiedades de ese elemento (en este caso, Cadena).

En general, es una mejor idea parametrizar las colecciones, para que no tenga problemas de conversión, solo podrá agregar elementos del tipo parametrizado y su editor le ofrecerá los métodos adecuados para seleccionar.

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

página de ayuda .

Un tipo sin formato es el nombre de una clase o interfaz genérica sin ningún tipo de argumento. Por ejemplo, dada la clase genérica Box:

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

Para crear un tipo parametrizado de Box, debe proporcionar un argumento de tipo real para el parámetro de tipo formal T:

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

Si se omite el argumento de tipo real, crea un tipo sin formato de Box:

Box rawBox = new Box();
Mykhaylo Adamovych
fuente
2

Evitar tipos crudos

Los tipos sin formato se refieren al uso de un tipo genérico sin especificar un parámetro de tipo.

Por ejemplo ,

Una lista es un tipo sin formato, mientras que List<String>es un tipo parametrizado.

Cuando se introdujeron los genéricos en JDK 1.5, los tipos sin formato se conservaron solo para mantener la compatibilidad con versiones anteriores de Java. Aunque todavía es posible usar tipos sin formato,

Deben evitarse :

  • Por lo general requieren moldes
  • No son de tipo seguro, y algunos tipos importantes de errores solo aparecerán en tiempo de ejecución
  • Son menos expresivos y no se documentan de la misma manera que los tipos parametrizados Ejemplo

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

Para referencia : https://docs.oracle.com/javase/tutorial/java/generics/rawTypes.html

Ashish
fuente
1

Encontré esta página después de hacer algunos ejercicios de muestra y tener exactamente el mismo desconcierto.

============== Pasé de este código como lo proporciona la muestra ===============

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 este código ========================

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

}

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

Puede ser más seguro, pero tardó 4 horas en desmantelar la filosofía ...

usuario2442615
fuente
0

Los tipos sin procesar están bien cuando expresan lo que quieres expresar.

Por ejemplo, una función de deserialización puede devolver a List, pero no conoce el tipo de elemento de la lista. Entonces, Listes el tipo de retorno apropiado aquí.

Stefan Reich
fuente
Puedes usar ? como parámetro tipo
Dániel Kis
Sí, pero eso es más para escribir y estoy en contra de escribir más. :)
Stefan Reich