java eclipse casting unchecked

java - ¿Qué es el reparto no verificado y cómo lo verifico?



eclipse casting (3)

La conversión no comprobada significa que usted está (implícitamente o explícitamente) realizando la conversión de un tipo genérico a un tipo no calificado o al revés. Por ejemplo, esta linea

Set<String> set = new HashSet();

producirá tal advertencia.

Por lo general, hay una buena razón para tales advertencias, por lo que debe intentar mejorar su código en lugar de suprimir la advertencia. Cita de Effective Java, 2ª edición:

Elimina todas las advertencias sin marcar que puedas. Si elimina todas las advertencias, puede estar seguro de que su código es seguro para el tipo, lo cual es algo muy bueno. Esto significa que no obtendrá una ClassCastException en tiempo de ejecución, y aumenta su confianza en que su programa se está comportando como esperaba.

Si no puede eliminar una advertencia y puede probar que el código que provocó la advertencia es de tipo seguro, entonces (y solo entonces) suprima la advertencia con una @SuppressWarnings("unchecked") . Si suprime las advertencias sin probar primero que el código es de tipo seguro, solo se está dando una falsa sensación de seguridad. El código puede compilarse sin emitir ninguna advertencia, pero aún puede lanzar una ClassCastException en tiempo de ejecución. Sin embargo, si ignora las advertencias sin marcar que sabe que son seguras (en lugar de suprimirlas), no notará cuándo surge una nueva advertencia que representa un problema real. La nueva advertencia se perderá en medio de todas las falsas alarmas que no silenciaste.

Por supuesto, no siempre es tan fácil eliminar las advertencias como con el código anterior. Sin ver su código, no hay forma de saber cómo hacerlo seguro.

Creo que entiendo lo que significa un elenco no verificado (emitir de uno a otro de un tipo diferente), pero ¿qué significa "verificar" el elenco? ¿Cómo puedo verificar el modelo para evitar esta advertencia en Eclipse?


Para elaborar más sobre lo que escribió Pedro:

Las conversiones de tipos no genéricos a tipos genéricos pueden funcionar bien en el tiempo de ejecución, ya que los parámetros genéricos se borran durante la compilación, por lo que nos queda una conversión legítima. Sin embargo, el código puede fallar más tarde con una excepción inesperada de ClassCastException debido a una suposición errónea con respecto al parámetro de tipo. Por ejemplo:

List l1 = new ArrayList(); l1.add(33); ArrayList<String> l2 = (ArrayList<String>) l1; String s = l2.get(0);

La advertencia no marcada en la línea 3 indica que el compilador ya no puede garantizar la seguridad de tipos, en el sentido de que puede ocurrir una excepción inesperada de clase de clase más tarde. Y esto sucede en la línea 4, que realiza un lanzamiento implícito.


Un reparto no verificado, a diferencia de un reparto controlado, no verifica el tipo de seguridad en tiempo de ejecución.

Aquí hay un ejemplo basado en la sección de Consider typesafe heterogenous containers la tercera edición. de "Java efectiva" de Joshua Bloch, pero la clase contenedora se rompe intencionalmente, almacena y devuelve el tipo incorrecto:

public class Test { private static class BrokenGenericContainer{ private final Map<Class<?>, Object> map= new HashMap<>(); public <T> void store(Class<T> key, T value){ map.put(key, "broken!"); // should''ve been [value] here instead of "broken!" } public <T> T retrieve(Class<T> key){ // return key.cast(map.get(key)); // a checked cast return (T)map.get(key); // an unchecked cast } } public static void main(String[] args) { BrokenGenericContainer c= new BrokenGenericContainer(); c.store(Integer.class, 42); List<Integer> ints = new ArrayList<>(); ints.add(c.retrieve(Integer.class)); Integer i = ints.get(0); } }


Si la retrieve() utiliza una (T)map.get(key) no verificada - (T)map.get(key) - la ejecución de este programa dará lugar a que se produzca ClassCastException en la línea Integer i = ints.get(0) . El método retrieve() se completará porque el tipo real no se verificó en el tiempo de ejecución:

Exception in thread "main" java.lang.ClassCastException: java.lang.String cannot be cast to java.lang.Integer at Test.main(Test.java:27)


Pero si la retrieve() usa una key.cast(map.get(key)) marcada - key.cast(map.get(key)) - la ejecución de este programa dará lugar a la key.cast(map.get(key)) ClassCastException en la línea key.cast(map.get(key)) , porque la key.cast(map.get(key)) comprobada descubra que el tipo es incorrecto y lance la excepción. El método retrieve() no se completará:

Exception in thread "main" java.lang.ClassCastException: Cannot cast java.lang.String to java.lang.Integer at java.lang.Class.cast(Class.java:3369) at Test$BrokenGenericContainer.retrieve(Test.java:16) at Test.main(Test.java:26)

Puede parecer una pequeña diferencia, pero en el caso de la conversión no comprobada, una String se abrió camino con éxito en una List<Integer> . En aplicaciones del mundo real, las consecuencias de esto pueden ser ... bueno, severas. En el caso de la conversión comprobada, la falta de coincidencia de tipos se descubrió lo antes posible.

Para evitar la advertencia de @SuppressWarnings("unchecked") , se puede usar @SuppressWarnings("unchecked") , si el programador está realmente seguro de que el método es realmente seguro. La mejor alternativa es usar los genéricos y los modelos controlados cuando sea posible.

Como Joshua Bloch lo puso,

... las advertencias sin marcar son importantes. No los ignores.

En aras de la integridad, this respuesta trata con los detalles de Eclipse.