O que é SuppressWarnings ("desmarcado") em Java?


443

Em algum momento, ao examinar o código, vejo muitos métodos especificando uma anotação:

@SuppressWarnings("unchecked")

O que isto significa?

Respostas:


420

Às vezes, os genéricos Java simplesmente não permitem que você faça o que deseja, e você precisa informar efetivamente ao compilador que o que você está fazendo realmente será legal no momento da execução.

Normalmente, acho isso um problema quando estou zombando de uma interface genérica, mas há outros exemplos também. Geralmente, vale a pena tentar descobrir uma maneira de evitar o aviso, em vez de suprimi-lo (as Perguntas frequentes sobre o Java Generics ajudam aqui), mas às vezes, mesmo que seja possível, o código fica fora de forma tanto que suprimir o aviso é mais organizado. Sempre adicione um comentário explicativo nesse caso!

As mesmas perguntas frequentes sobre genéricos têm várias seções sobre esse tópico, começando com "O que é um aviso" desmarcado "?" - vale a pena ler.


10
Em alguns casos, você pode evitá-lo usando YourClazz.class.cast (). Funciona para contêineres de elemento genérico único, mas não para coleções.
Akarnokd

Ou, de preferência, use genéricos curinga (YourClazz<?>)- o Java nunca avisa sobre as transmissões por serem seguras. No entanto, isso nem sempre funciona (consulte as Perguntas frequentes sobre genéricos para obter detalhes).
precisa saber é o seguinte

48

É uma anotação para suprimir avisos de compilação sobre operações genéricas não verificadas (não exceções), como projeções. Isso implica essencialmente que o programador não deseja ser notificado sobre eles, dos quais ele já está ciente ao compilar um determinado pedaço de código.

Você pode ler mais sobre esta anotação específica aqui:

Suprimir avisos

Além disso, o Oracle fornece alguma documentação tutorial sobre o uso de anotações aqui:

Anotações

Como eles dizem,

"O aviso 'desmarcado' pode ocorrer ao fazer interface com o código herdado escrito antes do advento dos genéricos (discutido na lição intitulada Genéricos)."


19

Também pode significar que a versão atual do sistema do tipo Java não é boa o suficiente para o seu caso. Havia várias proposições / hacks de JSR para corrigir isso: Type tokens, Super Type Tokens , Class.cast ().

Se você realmente precisa dessa supressão, reduza-a o máximo possível (por exemplo, não a coloque na própria classe ou em um método longo). Um exemplo:

public List<String> getALegacyListReversed() {
   @SuppressWarnings("unchecked") List<String> list =
       (List<String>)legacyLibrary.getStringList();

   Collections.reverse(list);
   return list;
}


8

Simplesmente: é um aviso pelo qual o compilador indica que não pode garantir a segurança do tipo.

Método de serviço JPA, por exemplo:

@SuppressWarnings("unchecked")
public List<User> findAllUsers(){
    Query query = entitymanager.createQuery("SELECT u FROM User u");
    return (List<User>)query.getResultList();
}

Se eu não anotasse o @SuppressWarnings ("desmarcado") aqui, haveria um problema com a linha, onde desejo retornar minha ResultList.

No atalho, segurança de tipo significa: Um programa é considerado com segurança de tipo se compilar sem erros e avisos e não gerar nenhum ClassCastException inesperado em tempo de execução.

Eu construo em http://www.angelikalanger.com/GenericsFAQ/FAQSections/Fundamentals.html


2
Este é um bom exemplo para a situação em que precisamos usar SuppressWarnings.
Jimmy

8

Em Java, os genéricos são implementados por meio do apagamento de tipo. Por exemplo, o seguinte código.

List<String> hello = List.of("a", "b");
String example = hello.get(0);

É compilado para o seguinte.

List hello = List.of("a", "b");
String example = (String) hello.get(0);

E List.ofé definido como.

static <E> List<E> of(E e1, E e2);

Qual após o apagamento do tipo se torna.

static List of(Object e1, Object e2);

O compilador não tem idéia do que são tipos genéricos em tempo de execução, portanto, se você escrever algo parecido com isto.

Object list = List.of("a", "b");
List<Integer> actualList = (List<Integer>) list;

O Java Virtual Machine não tem idéia do que são tipos genéricos durante a execução de um programa, portanto, ele compila e executa, como no Java Virtual Machine, esse é um Listtipo de conversão para o tipo (é a única coisa que pode ser verificada e verificada apenas isso).

Mas agora adicione esta linha.

Integer hello = actualList.get(0);

E a JVM lançará um inesperado ClassCastException, pois o compilador Java inseriu uma conversão implícita.

java.lang.ClassCastException: java.base/java.lang.String cannot be cast to java.base/java.lang.Integer

Um uncheckedaviso informa ao programador que uma conversão pode fazer com que um programa lance uma exceção em outro lugar. Suprimir o aviso com @SuppressWarnings("unchecked")informa ao compilador que o programador acredita que o código é seguro e não causará exceções inesperadas.

Por que você gostaria de fazer isso? O sistema de tipos Java não é bom o suficiente para representar todos os padrões de uso de tipos possíveis. Às vezes, você pode saber que um elenco é seguro, mas o Java não fornece uma maneira de dizer isso - ocultar avisos como esse @SupressWarnings("unchecked")pode ser usado, para que um programador possa se concentrar em avisos reais. Por exemplo, Optional.empty()retorna um singleton para evitar a alocação de opcionais vazios que não armazenam um valor.

private static final Optional<?> EMPTY = new Optional<>();
public static<T> Optional<T> empty() {
    @SuppressWarnings("unchecked")
    Optional<T> t = (Optional<T>) EMPTY;
    return t;
}

Essa conversão é segura, pois o valor armazenado em um opcional vazio não pode ser recuperado, portanto não há risco de exceções de conversão de classe inesperadas.


5

Você pode suprimir os avisos do compilador e informar aos genéricos que o código que você escreveu é legal de acordo com ele.

Exemplo:

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

5

Um truque é criar uma interface que estenda uma interface básica genérica ...

public interface LoadFutures extends Map<UUID, Future<LoadResult>> {}

Então você pode verificá-lo com instanceof antes do 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;

4

Até onde eu sei, por enquanto isso tem a ver com a supressão de avisos sobre genéricos; genéricos são uma nova construção de programação não suportada nas versões do JDK anteriores ao JDK 5, portanto, qualquer combinação das construções antigas com as novas pode representar resultados inesperados.

O compilador avisa o programador sobre isso, mas se o programador já souber, ele pode desativar esses avisos temidos usando SuppressWarnings.


1
JDK5 é novo? Ele concluiu a maior parte do seu período de vida útil final.
Tom Hawtin # tackline

Eu sei que o JDK 5 está desatualizado, o que eu quis dizer é que é novo, no sentido de que ele introduziu novos recursos no Java, anteriormente não oferecidos no JDK 4. Além disso, observe que ainda existem aqueles que aguardam o JDK 7 antes de deixar o JDK 5 para trás. para adotar o JDK 6, não posso raciocinar o porquê!
BakerTheHacker

2

Um aviso pelo qual o compilador indica que não pode garantir a segurança do tipo. O termo aviso "desmarcado" é enganoso. Isso não significa que o aviso esteja desmarcado de forma alguma. O termo "desmarcado" refere-se ao fato de que o compilador e o sistema de tempo de execução não possuem informações de tipo suficientes para executar todas as verificações de tipo que seriam necessárias para garantir a segurança do tipo. Nesse sentido, certas operações são "desmarcadas".

A fonte mais comum de avisos "não verificados" é o uso de tipos brutos. Os avisos "não verificados" são emitidos quando um objeto é acessado por meio de uma variável de tipo bruto, porque o tipo bruto não fornece informações de tipo suficientes para executar todas as verificações de tipo necessárias.

Exemplo (de aviso não verificado em conjunto com tipos brutos):

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");  
                      ^

Quando o método add é chamado, o compilador não sabe se é seguro adicionar um objeto String à coleção. Se o TreeSet for uma coleção que contenha String s (ou um supertipo), será seguro. Mas, a partir das informações de tipo fornecidas pelo tipo bruto TreeSet, o compilador não pode informar. Portanto, a chamada é potencialmente insegura e um aviso "não verificado" é emitido.

Os avisos "não verificados" também são relatados quando o compilador encontra uma conversão cujo tipo de destino é um tipo parametrizado ou um tipo de parâmetro.

Exemplo (de um aviso não verificado em conjunto com uma conversão para um tipo ou variável de tipo parametrizado):

  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;

Uma conversão cujo tipo de destino é um tipo de parâmetro (curinga concreta ou limitada) ou um parâmetro de tipo é insegura, se uma verificação de tipo dinâmico em tempo de execução estiver envolvida. No tempo de execução, apenas o apagamento do tipo está disponível, não o tipo estático exato que é visível no código-fonte. Como resultado, a parte do tempo de execução da conversão é executada com base no apagamento do tipo, não no tipo estático exato.

No exemplo, a conversão para o Wrapper verifica se o objeto retornado de super.clone é um Wrapper, não se é um wrapper com um tipo específico de membros. Da mesma forma, as transmissões para o parâmetro de tipo T são convertidas para o tipo Object em tempo de execução e provavelmente otimizadas. Devido ao apagamento do tipo, o sistema de tempo de execução não pode executar verificações de tipo mais úteis no tempo de execução.

De certa forma, o código-fonte é enganoso, porque sugere que uma conversão para o respectivo tipo de destino é executada, enquanto na verdade a parte dinâmica da conversão verifica apenas a eliminação de tipo do tipo de destino. O aviso "desmarcado" é emitido para chamar a atenção do programador para essa incompatibilidade entre o aspecto estático e dinâmico do elenco.

Consulte: O que é um aviso "não verificado"?


2

A anotação @SuppressWarnings é uma das três anotações internas disponíveis no JDK e adicionadas ao lado de @Override e @Deprecated no Java 1.5.

@SuppressWarnings instrui o compilador a ignorar ou suprimir o aviso especificado do compilador no elemento anotado e em todos os elementos do programa dentro desse elemento. Por exemplo, se uma classe for anotada para suprimir um aviso específico, um aviso gerado em um método dentro dessa classe também será separado.

Você pode ter visto @SuppressWarnings ("desmarcado") e @SuppressWarnings ("serial"), dois dos exemplos mais populares da anotação @SuppressWarnings. O Former é usado para suprimir o aviso gerado devido à conversão não verificada, enquanto o aviso posterior é usado para lembrar sobre a adição de SerialVersionUID em uma classe Serializable.

Leia mais: https://javarevisited.blogspot.com/2015/09/what-is-suppresswarnings-annotation-in-java-unchecked-raw-serial.html#ixzz5rqQaOLUa

Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.