32

I think I get what unchecked cast means (casting from one to another of a different type), but what does it mean to "Check" the cast? How can I check the cast so that I can avoid this warning in Eclipse?

Whymarrh
  • 11,635
  • 13
  • 55
  • 96
SIr Codealot
  • 4,843
  • 8
  • 31
  • 44
  • 17
    Don't post the code! Don't let them give you a fish instead of teaching fishing :) No, seriously, is there should be a generic answer for generic question even if question is asked in an amateur style. – Mike Jul 15 '14 at 15:25

3 Answers3

46

To elaborate on what Peter wrote:

Casts from non-generic types to generic types may work just fine at runtime, because the generic parameters are erased during compilation, so we are left with a legitimate cast. However, the code may fail later with an unexpected ClassCastException due to an incorrect assumption regarding the type parameter. For example:

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

The unchecked warning at line 3 indicates that the compiler is not able to guarantee type safety, in the sense that an unexpected ClassCastException may occur at a later point. Indeed, this happens at line 4, which performs an implicit cast.

mouselabs
  • 245
  • 2
  • 7
Eyal Schneider
  • 21,096
  • 4
  • 43
  • 73
32

Unchecked cast means that you are (implicitly or explicitly) casting from a generic type to a nonqualified type or the other way around. E.g. this line

Set<String> set = new HashSet();

will produce such a warning.

Usually there is a good reason for such warnings, so you should try to improve your code instead of suppressing the warning. Quote from Effective Java, 2nd Edition:

Eliminate every unchecked warning that you can. If you eliminate all warnings, you are assured that your code is typesafe, which is a very good thing. It means that you won’t get a ClassCastException at runtime, and it increases your confidence that your program is behaving as you intended.

If you can’t eliminate a warning, and you can prove that the code that provoked the warning is typesafe, then (and only then) suppress the warning with an @SuppressWarnings("unchecked") annotation. If you suppress warnings without first proving that the code is typesafe, you are only giving yourself a false sense of security. The code may compile without emitting any warnings, but it can still throw a ClassCastException at runtime. If, however, you ignore unchecked warnings that you know to be safe (instead of suppressing them), you won’t notice when a new warning crops up that represents a real problem. The new warning will get lost amidst all the false alarms that you didn’t silence.

Of course, it is not always as easy to eliminate warnings as with the code above. Without seeing your code, there is no way to tell how to make it safe though.

Péter Török
  • 109,525
  • 28
  • 259
  • 326
  • How about this unchecked cast: `FoodBag> bag2 = new FoodBag();` `((FoodBag)bag2).setFood(new CheeseSandwich());` from a generic type to a generic type? – Datoraki Apr 21 '11 at 14:57
  • @Datoraki, could you be more specific with your question? – Péter Török Apr 21 '11 at 15:10
  • 26
    -1 because answer does not address "how to check cast" part of question. Ok, we know we should check cast, **how** do we do it? – Mike Jul 14 '14 at 14:44
  • @Mike, you haven't shown a single concrete code example, how do you expect concrete solutions from us? As indicated in other answers as well as mine, this is a complex topic with no one-size-fits-all solution. – Péter Török Jul 15 '14 at 09:23
  • @PéterTörök, Ok, first of all here's different Mike :) userid is what makes us unique. Second, after reading SO for me a java newcomer it seems that safe typing in java when dealing with generics is majorly obstructed due to java generics nature. Warnings on the code with generics brought me here. It would be super-awesome if you could share at least a link on practices of how to deal with warnings. Otherwise it stays -1, because we all know warnings are not ok but we are still at original point where we ask for a solution. – Mike Jul 15 '14 at 15:27
  • @Mike, apologies for messing you with the OP. Re how to work safely with Java generics, if you haven't read [a good tutorial](http://docs.oracle.com/javase/tutorial/java/generics/), better start there. After that, if you still have a concrete problem for which you haven't found a good answer on SO, feel free to post it. – Péter Török Jul 15 '14 at 20:13
  • From the spec: Definition of "unchecked conversion" https://docs.oracle.com/javase/specs/jls/se7/html/jls-5.html#jls-5.1.9 – Josiah Yoder May 07 '15 at 16:30
  • 1
    This question has not been answered. Hiding it with an annotation is not an answer and sometimes the code cannot changed to properly avoid the warning. The warning itself appears to state that there is some way to check the cast. But a programmatic test does not seem to do that. – Josef.B May 16 '15 at 00:10
  • OP, what do you mean by "nonqualified type"? First paragraph. – carloswm85 Sep 25 '19 at 12:56
1

An unchecked cast, as opposed to checked cast, does not check type safety at runtime.

Here's an example based on the Consider typesafe heterogenous containers section of the 3rd ed. of "Effective Java" by Joshua Bloch, but the container class is intentionally broken - it stores and returns the wrong type:

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

}


If the retrieve() uses an unchecked cast -(T)map.get(key) - running this program will lead to ClassCastException occurring at Integer i = ints.get(0) line. The retrieve() method will complete because the actual type was not checked at runtime:

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


But if the retrieve() uses a checked cast - key.cast(map.get(key)) - running this program will lead to ClassCastException occurring at key.cast(map.get(key)) line, because the checked cast will find out that the type is wrong and throw the exception. The retrieve() method will not complete:

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)

Little difference it may seem, but in the case with the unchecked cast, a String successfully made its way into a List<Integer>. In real world applications, consequences of this may be... well, severe. In case with the checked cast, the type mismatch was discovered as early as possible.


To avoid the unchecked casts warning, @SuppressWarnings("unchecked") can be used, if the programmer is really sure the method is in fact safe. The better alternative is to use generics and checked casts when possible.

As Joshua Bloch put it,

...unchecked warnings are important. Don’t ignore them.


For the sake of completeness, this answer deals with the Eclipse specifics.

jihor
  • 2,138
  • 11
  • 24