Using @Supresswarnings in Java

Asked

Viewed 6,033 times

9

Good morning.

Until when it is recommended to use the annotation @SuppressWarnings to hide a Warning of a certain problem that the compiler finds in your code and show that you know what you’re doing? I do this so as not to pollute the Packages and the classes with the yellow alert using Eclipse.

What do you recommend and what do you have to say about it? There are other options to hide a Warning? What are?

Thank you in advance.

  • 1

    The best option is not to hide Warning but to eliminate its cause. I can’t remember the last time I used a @Suppresswarnings... What I do is read the Warning reason and fix the problem.

1 answer

11


General rules on how to deal with warnings

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

  • When you come across a Warning in particular, try to understand what the cause first. Don’t go putting @SuppressWarnings either way on anything!
  • Try to eliminate the warnings by changing the code to make it disappear, that is to correct the problem that the Warning is saying you have. See below for my answer how to deal with the most common cases.
  • If you can’t eliminate one Warning in particular, think if 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 have a solution to the Warning it will not be forgotten. Moreover, the Warning always serves as a reminder that there are some technical charges pending resolution.
  • If you really want to silence the Warning, put the @SuppressWarnings in the smallest possible scope. That is, if you can put it in a local variable instead of in the whole method, prefer to put in the local variable.
  • If you put a @SuppressWarnings in your code, it is good to put a comment (with // ... or /* ... */) explaining why you are suppressing a Warning in particular, unless it’s a very obvious case.
  • If you are going to make changes to some code that uses the @SuppressWarnings, see this as a potential opportunity to remove the @SuppressWarnings. Always take a look if when changing the code, you do not end up deleting/correcting the stituation that generates the Warning, and therefore no longer need to suppress it.

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

1. Warning unchecked

This is the most common case, and often it can happen when generic types do not match, but even so you can ensure that the program works.

A Warning unchecked is shot more often in Casts. In general Casts are checked at runtime, but with generic types due to the type-Rasure, the generic type check is not performed at runtime, which 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 this is because the generic type is lost because of the type-Rasure, which allows me to insert elements into the array that violate the type restrictions that the compiler imposes (which is called heap Pollution). The 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 that you have ClassCastExceptions being thrown into unexpected places.

Having return of methods, parameters or variables whose types depend on circumstances that cannot be verified by the compiler in general is not a good idea, and the ideal is that the code is restructured to ensure that the compiler is able to do type checking properly. Generic arrays are rarely a good idea either. However, from time to time this situation happens in a way that cannot be avoided, which is why we have the @SuppressWarnings("unchecked").

To eliminate this Warning, the ideal is:

  • Study very well the Generics and learn how to use them also to create generic classes, including how to use wildcard types (such as List<? super Foo>). Many of the places where the Warning unchecked appears is the result of code developed by people who do not know how to properly use the Generics.
  • Understand what is heap Pollution, because that is exactly what the Warning unchecked tries to warn.
  • Do not use raw types (such as List and Map instead of List<Foo> and Map<Foo, Bar>). Always try to declare all necessary generic types, even if some of them are wild types (with <?>) or are type variables.
  • Use the methods java.util.Collections.checked* 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 since arrays are a low-level data structure and ideally should be abstracted if possible. The method java.util.Arrays.asList(T... a) is very useful in these circumstances.
  • Avoid declaring type parameters Object and returns of the type Object. When this happens, it may be that using a generic type would be better than using Object.
  • Use the methods java.lang.Class.cast(Class<U> c) and java.lang.Class.asSubclass(Class<S> c). With these methods it is possible to implement Casts dynamics at runtime.
  • Not do Casts for type variables (such as return (T) obj;). If possible, use the object Class suitable for this (as in return classT.cast(obj);).
  • Declare parameters with a generic type Class<X>, where X is a type variable declared in the method in question.
  • Avoid creating heterogeneous data structures (i.e., they may contain more than one type of object, such as a list containing a mixture of cats and dogs).
  • If you really need to mix arrays with generic types instead of using one List or a Map, make sure you know very well what you’re doing.

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

2. Warning rawtypes

Similar to @SuppressWarnings("unchecked"), This one happens when brute types are declared. Crude types are those types should be generic, but generics were not used, typically due to the use of legacy classes prior to Java 5.

For example:

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

The solution to the warnings of this type are the same as those that apply to unchecked, only the specific situation in which it occurs is a little different. And obviously, there are cases where it cannot be eliminated, and therefore the @SuppressWarnings("rawtypes") can be used.

3. Warning deprecation

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

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

To eliminate this Warning, the ideal is:

  • Do not use method, attribute or class deprecated, after all it was marked as deprecated is because there’s some reason why it shouldn’t be used. And when it does, there’s usually something else that should be used instead.
  • If the method or class you are implementing/coding/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 a tag @deprecated, but without the note @Deprecated, you will receive a Warning Dep-Ann. To fix it just add the annotation @Deprecated.

In general, there is no point in ignoring Warning Dep-Ann, even more than fixing it is easy. The only situation where it cannot be corrected is in code that must be compatible with versions of Java prior to 5 and therefore cannot be annotated. But in this case, you will also not be able to suppress the Warning with the @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 a bad programming practice (only setters in general are forgiven, but there are those who disagree with this, including me).

To correct this Warning, the ideal is to rename one of the variables that is colliding. And it is easier to rename the one that has the smallest scope. In the case of local variables, there is no reason why this correction should not be made. It is rare for a correction not to be possible, as in the case of an inner class to have 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 is a sign that you have much bigger problems in your code. But if you can’t fix, then use the @SuppressWarnings("hiding").

6. Warning unused

It occurs when you have methods, fields, constructors or internal classes (usually private) that are not used. It can also occur with local parameters and variables that are not used.

  • In the case of local variables, there is no excuse to keep them, it is best to just eliminate them.
  • In the case of private internal fields, methods, constructors and classes that do not seem to be used, the ideal is only to eliminate them.
  • In the case of parameters, except in the case of Overriding or parameters that must remain to ensure compatibility, the ideal is to eliminate them.
  • In cases where a field, constructor, method or private and apparently never used internal class can be accessed by Reflection, in this case it is valid to use @SuppressWarnings("unused").

7. Warning varargs

You have declared a parameter that is a vararg array of a generic type, which can bring you problems from heap Pollution (see in the item of unchecked). In general the solution to this is to try to use a List or a Map instead of the array, or use the java.util.Arrays.asList(T...). Also worth taking a look at the note @SafeVarargs. Only if none of these options is valid, is the @SuppressWarnings("varargs") must be considered.

8. Warning fallthrough

The switch is already a hideous language construct that Java inherited from C. Even worse is having inherited fallthrough. In most cases where this occurs, it is because you have forgotten one break (or maybe a throw or return) in his switch, and in this case what you have to do is correct the error.

Even when the fallthrough is intentional, using it in general is bad programming practice, and you should code your switch so as not to need the fallthrough, or even so as not to need the switch. A way of not needing the switch is to try to transform each case in an overscript of an abstract polymorphic method and invoke it instead of doing the switch. From Java 8, you can find ways to replace with some Amblas Expressions, although this is a bit difficult in the case of fallthrough.

But, if the fallthrough is really necessary and you cannot eliminate it (or less, not easily), so put the @SuppressWarnings("fallthrough").

9. Warning restriction

Are you using any class that is not part of the public API and should not be used directly, such as those in packages sun.*. And the best solution is simply not to use this class but to use some alternative that is not in a forbidden package. If you are trying to decide at runtime whether it will be used, or whether an alternative will be sought, the ideal is to access it only via Reflection.

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

10. Warning serial

You have defined a serializable class that does not have the serialVersionUID. A serializable class is one that implements the interface java.io.Serializable, even if indirectly (i.e., implements an interface that inherits from java.io.Serializable or inherit from a class that implements java.io.Serializable).

In cases where you don’t care about serialization, it’s safe to suppress this Warning. But it’s better if instead you just declare the field serialVersionUID adequately.

11. Warning cast

You are using a cast unnecessary in code (such as doing 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 deleted instead of only corrected.

12. Other warnings

There are many others warnings. See these links:

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

Many of these warnings are simple to correct and has no sense in being ignored, such as empty, dep-ann and cast. Others may be just compiler hassle, and in this case, if they cannot be fixed, it is 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 arrange, such as unchecked, finally and fallthrough. But remember, always try first to correct the Warning, and only if you can’t correct and you don’t think it best to let the compiler continue to complain, do you think about silencing her with the @SuppressWarnings.

13. @SuppressWarnings("all")

Use the @SuppressWarnings("all") is the last resort, because it silences all warnings. Ideally you should not use @SuppressWarnings("all") never, but there are two cases that come to mind in which it makes sense:

  • The class is automatically generated and governed by some tool before or during the build process, and because of this, it is not desirable for the compiler to complain about warnings in it.
  • The class was copied and pasted from somewhere else or received from somewhere else and for some reason it should not be changed (other than the change of adding the class itself @SuppressWarnings). In this case, it’s best to silence all warnings that the compiler will issue about this class.

Browser other questions tagged

You are not signed in. Login or sign up in order to post.