Respuestas:
A veces, los genéricos de Java simplemente no te permiten hacer lo que quieres y debes decirle al compilador de manera efectiva que lo que estás haciendo realmente será legal en el momento de la ejecución.
Por lo general, me parece un dolor cuando me estoy burlando de una interfaz genérica, pero también hay otros ejemplos. Por lo general, vale la pena intentar encontrar una forma de evitar la advertencia en lugar de suprimirla (las preguntas frecuentes de Java Generics ayudan aquí), pero a veces, incluso si es posible, dobla el código fuera de forma tanto que suprimir la advertencia es más ordenado. ¡Siempre agregue un comentario explicativo en ese caso!
Las mismas preguntas frecuentes sobre genéricos tienen varias secciones sobre este tema, comenzando con "¿Qué es una advertencia" no verificada "?" Vale la pena leerlo.
(YourClazz<?>)
: Java nunca advierte sobre dichos lanzamientos, ya que son seguros. Sin embargo, esto no siempre funcionará (consulte las preguntas frecuentes sobre genéricos para obtener más información)
Es una anotación para suprimir las advertencias de compilación sobre operaciones genéricas no verificadas (no excepciones), como las conversiones. Básicamente, implica que el programador no desea que se le notifique acerca de esto, de lo que ya tiene conocimiento al compilar un fragmento de código en particular.
Puede leer más sobre esta anotación específica aquí:
Además, Oracle proporciona una documentación tutorial sobre el uso de anotaciones aquí:
Como lo dicen,
"La advertencia 'no verificada' puede ocurrir al interactuar con el código heredado escrito antes del advenimiento de los genéricos (discutido en la lección titulada Genéricos)".
También podría significar que la versión actual del sistema de tipo Java no es lo suficientemente buena para su caso. Hubo varias propuestas / hacks de JSR para solucionar esto: tokens de tipo, Super Type Tokens , Class.cast ().
Si realmente necesita esta supresión, acóplela tanto como sea posible (por ejemplo, no la ponga en la clase misma o en un método largo). Un ejemplo:
public List<String> getALegacyListReversed() {
@SuppressWarnings("unchecked") List<String> list =
(List<String>)legacyLibrary.getStringList();
Collections.reverse(list);
return list;
}
La anotación SuppressWarning se usa para suprimir las advertencias del compilador para el elemento anotado. Específicamente, la unchecked
categoría permite la supresión de advertencias del compilador generadas como resultado de conversiones de tipo no verificadas.
Simplemente: es una advertencia por la cual el compilador indica que no puede garantizar la seguridad del tipo.
Método de servicio JPA, por ejemplo:
@SuppressWarnings("unchecked")
public List<User> findAllUsers(){
Query query = entitymanager.createQuery("SELECT u FROM User u");
return (List<User>)query.getResultList();
}
Si no anotara el @SuppressWarnings ("sin marcar") aquí, tendría un problema con la línea, donde quiero devolver mi ResultList.
En acceso directo, la seguridad de tipo significa: Un programa se considera seguro de tipo si se compila sin errores y advertencias y no genera ninguna clase inesperada de ClassCastException en tiempo de ejecución.
Construyo sobre http://www.angelikalanger.com/GenericsFAQ/FAQSections/Fundamentals.html
En Java, los genéricos se implementan mediante borrado de tipo. Por ejemplo, el siguiente código.
List<String> hello = List.of("a", "b");
String example = hello.get(0);
Se compila a lo siguiente.
List hello = List.of("a", "b");
String example = (String) hello.get(0);
Y List.of
se define como.
static <E> List<E> of(E e1, E e2);
Que después del tipo de borrado se hace.
static List of(Object e1, Object e2);
El compilador no tiene idea de cuáles son los tipos genéricos en tiempo de ejecución, así que si escribe algo como esto.
Object list = List.of("a", "b");
List<Integer> actualList = (List<Integer>) list;
Java Virtual Machine no tiene idea de qué tipos genéricos son mientras se ejecuta un programa, por lo que esto se compila y ejecuta, en cuanto a Java Virtual Machine, este es un molde para List
escribir (esto es lo único que puede verificar, por lo que solo verifica eso).
Pero ahora agregue esta línea.
Integer hello = actualList.get(0);
Y JVM arrojará un inesperado ClassCastException
, ya que el compilador de Java insertó un elenco implícito.
java.lang.ClassCastException: java.base/java.lang.String cannot be cast to java.base/java.lang.Integer
Una unchecked
advertencia le dice al programador que un lanzamiento puede hacer que un programa arroje una excepción en otro lugar. Suprimir la advertencia con @SuppressWarnings("unchecked")
le dice al compilador que el programador cree que el código es seguro y no causará excepciones inesperadas.
¿Por qué querrías hacer eso? El sistema de tipos Java no es lo suficientemente bueno como para representar todos los patrones de uso de tipos posibles. A veces puede saber que un reparto es seguro, pero Java no proporciona una manera de decirlo: @SupressWarnings("unchecked")
puede usarse para ocultar advertencias como esta , de modo que un programador pueda centrarse en advertencias reales. Por ejemplo, Optional.empty()
devuelve un singleton para evitar la asignación de opciones vacías que no almacenan un valor.
private static final Optional<?> EMPTY = new Optional<>();
public static<T> Optional<T> empty() {
@SuppressWarnings("unchecked")
Optional<T> t = (Optional<T>) EMPTY;
return t;
}
Esta conversión es segura, ya que el valor almacenado en una opción vacía no se puede recuperar, por lo que no hay riesgo de excepciones inesperadas de conversión de clase.
Puede suprimir las advertencias del compilador y decirle a los genéricos que el código que ha escrito es legal de acuerdo con él.
Ejemplo:
@SuppressWarnings("unchecked")
public List<ReservationMealPlan> retreiveMealPlan() {
List<ReservationMealPlan> list=new ArrayList<ReservationMealPlan>();
TestMenuService testMenuService=new TestMenuService(em, this.selectedInstance);
list = testMenuService.getMeal(reservationMealPlan);
return list;
}
Un truco es crear una interfaz que extienda una interfaz base genérica ...
public interface LoadFutures extends Map<UUID, Future<LoadResult>> {}
Luego puedes verificarlo con instanceof antes del elenco ...
Object obj = context.getAttribute(FUTURES);
if (!(obj instanceof LoadFutures)) {
String format = "Servlet context attribute \"%s\" is not of type "
+ "LoadFutures. Its type is %s.";
String msg = String.format(format, FUTURES, obj.getClass());
throw new RuntimeException(msg);
}
return (LoadFutures) obj;
Hasta donde sé, por ahora tiene que ver con suprimir las advertencias sobre los genéricos; los genéricos son una nueva construcción de programación no admitida en las versiones JDK anteriores a JDK 5, por lo que cualquier combinación de las construcciones antiguas con las nuevas podría presentar algunos resultados inesperados.
El compilador advierte al programador al respecto, pero si el programador ya lo sabe, puede desactivar esas temidas advertencias utilizando SuppressWarnings.
Una advertencia por la cual el compilador indica que no puede garantizar la seguridad del tipo. El término advertencia "no verificada" es engañoso. No significa que la advertencia no esté marcada de ninguna manera. El término "desmarcado" se refiere al hecho de que el compilador y el sistema de tiempo de ejecución no tienen suficiente información de tipo para realizar todas las verificaciones de tipo que serían necesarias para garantizar la seguridad de tipo. En este sentido, ciertas operaciones están "desmarcadas".
La fuente más común de advertencias "no verificadas" es el uso de tipos sin formato. Las advertencias "no verificadas" se emiten cuando se accede a un objeto a través de una variable de tipo sin formato, porque el tipo sin formato no proporciona suficiente información de tipo para realizar todas las verificaciones de tipo necesarias.
Ejemplo (de advertencia no verificada junto con tipos sin formato):
TreeSet set = new TreeSet();
set.add("abc"); // unchecked warning
set.remove("abc");
warning: [unchecked] unchecked call to add(E) as a member of the raw type java.util.TreeSet
set.add("abc");
^
Cuando se invoca el método add, el compilador no sabe si es seguro agregar un objeto String a la colección. Si TreeSet es una colección que contiene String s (o un supertipo de la misma), entonces sería seguro. Pero a partir de la información de tipo proporcionada por el tipo sin formato TreeSet, el compilador no puede saberlo. Por lo tanto, la llamada es potencialmente insegura y se emite una advertencia "no verificada".
Las advertencias "no verificadas" también se informan cuando el compilador encuentra una conversión cuyo tipo de destino es un tipo parametrizado o un parámetro de tipo.
Ejemplo (de una advertencia no verificada junto con una conversión a un tipo parametrizado o variable de tipo):
class Wrapper<T> {
private T wrapped ;
public Wrapper (T arg) {wrapped = arg;}
...
public Wrapper <T> clone() {
Wrapper<T> clon = null;
try {
clon = (Wrapper<T>) super.clone(); // unchecked warning
} catch (CloneNotSupportedException e) {
throw new InternalError();
}
try {
Class<?> clzz = this.wrapped.getClass();
Method meth = clzz.getMethod("clone", new Class[0]);
Object dupl = meth.invoke(this.wrapped, new Object[0]);
clon.wrapped = (T) dupl; // unchecked warning
} catch (Exception e) {}
return clon;
}
}
warning: [unchecked] unchecked cast
found : java.lang.Object
required: Wrapper <T>
clon = ( Wrapper <T>)super.clone();
^
warning: [unchecked] unchecked cast
found : java.lang.Object
required: T
clon. wrapped = (T)dupl;
Una conversión cuyo tipo de destino es un tipo parametrizado (comodín concreto o acotado) o un parámetro de tipo no es seguro, si se trata de una verificación dinámica de tipo en tiempo de ejecución. En tiempo de ejecución, solo está disponible el borrado de tipo, no el tipo estático exacto que es visible en el código fuente. Como resultado, la parte de tiempo de ejecución del reparto se realiza en función del tipo de borrado, no del tipo estático exacto.
En el ejemplo, la conversión a Wrapper comprobaría si el objeto devuelto por super.clone es un Wrapper, no si es un contenedor con un tipo particular de miembros. Del mismo modo, las conversiones al parámetro de tipo T se convierten para escribir Object en tiempo de ejecución, y probablemente optimizadas por completo. Debido a la eliminación de tipos, el sistema de tiempo de ejecución no puede realizar verificaciones de tipos más útiles en tiempo de ejecución.
En cierto modo, el código fuente es engañoso, porque sugiere que se realiza una conversión al tipo de objetivo respectivo, mientras que, de hecho, la parte dinámica de la conversión solo verifica la eliminación del tipo de tipo objetivo. La advertencia "sin marcar" se emite para llamar la atención del programador sobre este desajuste entre el aspecto estático y dinámico del elenco.
Consulte: ¿Qué es una advertencia "sin marcar"?
La anotación @SuppressWarnings es una de las tres anotaciones integradas disponibles en JDK y se agrega junto con @Override y @Deprecated en Java 1.5.
@SuppressWarnings le indica al compilador que ignore o suprima la advertencia especificada del compilador en el elemento anotado y todos los elementos del programa dentro de ese elemento. Por ejemplo, si una clase se anota para suprimir una advertencia particular, entonces una advertencia generada en un método dentro de esa clase también se separará.
Es posible que haya visto @SuppressWarnings ("sin marcar") y @SuppressWarnings ("serial"), dos de los ejemplos más populares de anotación @SuppressWarnings. El primero se usa para suprimir la advertencia generada debido a la conversión sin control, mientras que la advertencia posterior se usa para recordar acerca de agregar SerialVersionUID en una clase serializable.