Using @SupressWarnings in Java

Question:

Good Morning.

How long is it recommended to use the @SuppressWarnings annotation to hide a warning of a particular problem that the compiler finds in your code and show that you know what you're doing? I do this to not pollute packages and classes with the yellow alert using Eclipse.

What do you recommend and what do you have to say about it? Are there other options to hide a warning ? Which are they?

Thanks in advance.

Answer:

General rules for handling warnings

Obviously, the purpose of @SuppressWarnings is to make the compiler not issue warnings . However, using it properly requires common sense. Here are some rules on how to use it properly:

  • When faced with a particular warning , try to understand what causes it first. Don't go around putting @SuppressWarnings on anything anyway!
  • Try to eliminate the warnings by changing the code to make it go away, in other words, correct the problem that warning is saying you have. See further down here in my answer how to handle the most common cases.
  • If you can't eliminate a particular Warning , think about whether you really want to suppress it. Sometimes letting the compiler keep screaming insistently every time you compile the code is better than silencing it, because in the future, if/when someone/you has a solution for warning it won't be forgotten. In addition, warning always serves as a reminder that there are some technical debts pending resolution.
  • If you really want to silence the warning , put @SuppressWarnings in the smallest possible scope. That is, if you can put it in a local variable instead of putting it in the whole method, prefer to put it in the local variable.
  • If you put an @SuppressWarnings in your code, it's good to put a comment (with // ... or /* ... */ ) explaining why you're suppressing a particular warning , unless it's a very case. obvious.
  • If you're going to make changes to some code that uses @SuppressWarnings , see this as a potential opportunity to remove @SuppressWarnings . Always take a look if when changing the code, you don't end up eliminating/fixing the situation that generates the warning , and therefore no longer needing to suppress it.

And the most common cases where warnings can be eliminated are:

1. Warning unchecked

This is the most common case, and it can often happen when the generic types don't match, but you can still make sure the program works.

The unchecked warning is fired more often in casts . In general casts are checked at runtime, but with generic types, due to type-erasure , the generic type checking is not performed at runtime, it is restricted to the base type only. For example:

public List<?> devolveAlgumaLista() {
    if (condicaoQualquer) {
        return new ArrayList<Gato>();
    } else {
        return new ArrayList<Cachorro>();
    }
}

@SuppressWarnings("unchecked")
public void metodoQualquer() {
    List<?> lista = devolveAlgumaLista();

    if (outraCondicao) {
        for (Cachorro c : (List<Cachorro>) lista) { // Cast unchecked.
             System.out.println(c.latir());
        }
    } else {
        for (Gato g : (List<Gato>) lista) { // Cast unchecked.
             System.out.println(g.miar());
        }
    }
}

Another example:

public List metodoBemAntigoEmAlgumaBiblioteca() {
    // ...
}

public void meuMetodoNovo() {
    @SuppressWarnings("unchecked")
    List<Abacaxi> lista = (List<Abacaxi>) metodoBemAntigoEmAlgumaBiblioteca();
}

Another place where it can occur is in generic arrays:

public <T> void metodo() {
    T[] array = ...; // warning unchecked
}

And that's because the generic's type is lost because of type-erasure , which allows me to insert elements into the array that violate the type restrictions the compiler imposes (which is called heap pollution ). Heap pollution can also happen to lists, maps, and other data structures when generics rules are violated. When your application suffers from heap pollution , the most common result is you have ClassCastException s being thrown in unexpected places.

Having returned methods, parameters, or variables whose types depend on circumstances that cannot be verified by the compiler in general is not a good idea, and ideally, the code is restructured to ensure that the compiler has a way of verifying types properly. Generic arrays are rarely a good idea either. However, every now and then this situation happens in a way you can't avoid, which is why we have @SuppressWarnings("unchecked") .

To eliminate this warning , the ideal is:

  • Study generics very well and learn to use them also to create generic classes, including how to use wildcard types (such as List<? super Foo> ). Many of the places where warning unchecked appears are the result of code developed by people who don't know how to properly use generics .
  • Understand what heap pollution is , because that's exactly what warning unchecked tries to warn against.
  • Do not use raw types (such as List and Map instead of List<Foo> and Map<Foo, Bar> ). Always try to declare all the necessary generic types, even if some of them are wild types (with <?> ) or are type variables.
  • Use java.util.Collections.checked* methods in collections and maps where generic types are simple, such as java.util.Collections.checkedList(lista, String.class) .
  • Avoid mixing arrays with generic types. It is best to work with lists or some other type of data structure, especially as arrays are a low-level data structure and ideally should be abstracted if possible. The java.util.Arrays.asList(T... a) is very useful in these circumstances.
  • Avoid declaring parameters of type Object and returns of type Object . When that happens, it might be that using a generic type would be better than using Object .
  • Use the java.lang.Class.cast(Class<U> c) and java.lang.Class.asSubclass(Class<S> c) methods. With these methods it is possible to implement dynamic casts at runtime.
  • Do not cast to type variables (such as return (T) obj; ). If possible, use the appropriate Class object for this (as in return classT.cast(obj); ).
  • Declaring parameters with a generic type Class<X> , where X is a type variable declared in the method in question.
  • As much as possible avoid creating heterogeneous data structures (that is, data structures that can contain more than one type of object, such as a list that contains a mix of cats and dogs).
  • If you really need to mix arrays with generic types instead of using a List or a Map , make sure you really know what you're doing.

And of course, if none of the alternatives are possible, then the solution would be to use @SuppressWarnings("unchecked") .

2. Warning rawtypes

Similar to @SuppressWarnings("unchecked") , this one happens when raw types are declared. Raw types are those types that should be generics, but where generics have not been used, typically due to the use of legacy classes prior to Java 5.

For example:

public void meuMetodo() {
    List elementos = ...; // warning rawtypes
    // ...
}

The solution for warnings of this type is the same as for unchecked , only the specific situation in which it occurs is a little different. And of course, there are cases where it can't be @SuppressWarnings("rawtypes") , so @SuppressWarnings("rawtypes") can be used.

3. Warning deprecation

This one happens when you use a deprecated method or override a deprecated method. For example:

 public void fazerAlgo() {
     JPasswordField jf = // ...
     String x = jf.getText(); // warning deprecation
     // ...
 }

To eliminate this warning , the ideal is:

  • Do not use the deprecated method, attribute or class, after all if it was marked as deprecated it is because there is some reason not to use it. And when that happens, there's usually something else that should be used instead.
  • If the method or class you are implementing/encoding/changing is also deprecated , then mark the method (or maybe even the entire class) with @Deprecated .

4. Warning dep-ann

If the method, class, field or constructor you are implementing/coding/changing has a javadoc with an @deprecated tag, but without the @Deprecated annotation, you will get a dep-ann warning . To fix it just add the @Deprecated annotation.

In general, there is no point in ignoring warning dep-ann , even though fixing it is easy. The only situation where it cannot be corrected is in code that must maintain compatibility with java versions prior to 5 and therefore cannot have annotations. But in this case, you will also not be able to suppress the warning with @SuppressWarnings .

5. Warning hiding

This is what happens when two variables with the same name are declared, but both present in the same scope, as in the code below:

public class MinhaClasse {
    private int x;

    public void metodo() {
        int x = 25; // warning hiding
        // ...
    }
}

Having two variables with the same name visible in the same scope is bad programming practice (only setters in general are forgiven, but some disagree with this, myself included).

To fix this warning , the ideal is to rename one of the colliding variables. And it's easier to rename the one with the smallest scope. In the case of local variables, there is no reason why this correction should not be made. It is rare that a fix is ​​not possible, such as in the case of the inner class having a public attribute with the same name as a public attribute in the outer class. And in general, when some more complex case of hiding happens, it's a sign that you have much bigger problems with your code. But if you can't fix it, then use @SuppressWarnings("hiding") .

6. Warning unused

Occurs when you have unused (usually private) methods, fields, constructors, or inner classes that aren't used. It can also occur with unused parameters and local variables.

  • In the case of local variables, there is no excuse to keep them, it is better to just eliminate them.
  • In the case of fields, methods, constructors, and private inner classes that don't seem to be used, the ideal is just to eliminate them.
  • In the case of parameters, except in the case of overriding or parameters that must remain to ensure compatibility, it is ideal to eliminate them.
  • In cases where a private and seemingly never-used field, constructor, method or inner class can be accessed through reflection , in this case it is valid to use @SuppressWarnings("unused") .

7. Warning varargs

You declared a parameter that is a vararg array of a generic type, which can give you heap pollution problems (see the unchecked item). In general the solution for this is to try using a List or a Map instead of the array, or use java.util.Arrays.asList(T...) . It's also worth taking a look at the @SafeVarargs annotation. Only if none of these options are valid should @SuppressWarnings("varargs") be considered.

8. Warning fallthrough

switch is already a hideous language construct that Java inherited from C. Even worse is that it inherited fallthrough . In most cases where this occurs, it's because you missed a break (or maybe a throw or return ) on your switch , in which case what you have to do is correct the error.

Even when fallthrough is intentional, using it is often bad programming practice, and you should code your switch so that you don't need the fallthrough , or even that you don't need the switch . One way to not need the switch is to try to turn each case into an abstract polymorphic method overwrite and invoke it instead of making the switch . Starting with Java 8, it is possible to find ways to substitute some lambdas expressions , although this is somewhat difficult in the case of fallthrough .

But, if fallthrough is really needed and you can't eliminate it (or unless, not easily), then add @SuppressWarnings("fallthrough") .

9. Warning restriction

You are using some class that is not part of the public API and should not be used directly, such as those in sun.* packages. And the best solution is simply not to use this class, but to use some alternative that is not in a prohibited package. If you're trying to decide at runtime whether it will be used, or whether an alternative will be searched for, it's ideal to just access it via reflection .

However, if you have no choice but to use such a class and you don't want to just keep the compiler complaining all the time, then the way out is to use @SuppressWarnings("restriction") .

10. serial warning

You've defined a serializable class that doesn't have the serialVersionUID . A serializable class is one that implements the java.io.Serializable interface, even if indirectly (that is, it implements an interface that inherits from java.io.Serializable or else inherits from a class that implements java.io.Serializable ).

In cases where you don't mind serialization, it's safe to suppress this warning . But it's better if you just declare the serialVersionUID field properly instead.

11. Warning cast

You are using an unnecessary cast in code (such as making String x = (String) "Hello World"; ). In this case, the ideal is to simply remove the cast . It's hard to imagine a case where this warning should be suppressed rather than just corrected.

12. Other warnings

There are many other warnings . See these links:

For these more specific warnings , check the relevant documentation to understand what's going on, and how to eliminate the problem or else and whether or not it's pertinent to use @SuppressWarnings .

Many of these warnings are simple to fix and are meaningless to ignore, such as empty , dep-ann and cast . Others may just be compiler annoyance, in which case, if they can't be fixed, it's best to ignore them, such as unqualified-field-access , serial and processing . However, there are always some that are important and can be difficult to fix, such as unchecked , finally and fallthrough . But remember, always try to fix the warning first, and only if you can't fix it and don't think it's better to let the compiler keep complaining, do you think about silencing it with @SuppressWarnings .

13. @SuppressWarnings("all")

Using @SuppressWarnings("all") is a last resort as it silences all warnings . Ideally you shouldn't use @SuppressWarnings("all") ever, but there are two cases that come to mind where this makes sense:

  • The class is automatically generated and regenerated by some tool before or during the compilation process, and because of that, it is not desirable for the compiler to be complaining about warnings on it.
  • The class was either copied and pasted from somewhere else, or it was received from somewhere else, and for some reason it shouldn't change @SuppressWarnings (other than the change to add the @SuppressWarnings itself). In this case, it is better to silence all warnings that the compiler will give about this class.
Scroll to Top