5

Using this code:

public class DowncastTest {
    public static void main(String[] args) {
        try {
            System.out.println(1);
        } catch (Exception ex) {
            Throwable cause = ex.getCause();
            if (cause != null) {
                Exception exCause = (Exception)cause;
                System.out.println(exCause);
            }
        }
    }
}

Why does the javac not give an unchecked cast warning?

Exception extends Throwable, so you cannot just convert all Throwables to an Exception.

skiwi
  • 66,971
  • 31
  • 131
  • 216
  • If such a cast produced a warning, it would only not produce a warning if the cast was redundant. i.e. it would be a warning you have used a cast at all. – Peter Lawrey Jul 22 '14 at 15:15

5 Answers5

10

Why does the javac not give an unchecked cast warning?

Because there are no generics involved. I don't think "unchecked cast" means what you think it means. It's for situations like:

List<?> list = getListFromSomewhere();
List<String> strings = (List<String>) list;

This is an unchecked cast, because the cast to List<String> doesn't really check whether list refers to a List<String>... it can't do, as there's no such concept at execution time.

The cast you've got at the moment from Throwable to Exception is just a normal cast - it will throw a ClassCastException if cause is a reference to an object which is not an Exception (or subclass).

Jon Skeet
  • 1,421,763
  • 867
  • 9,128
  • 9,194
  • 3
    "You keep using that word... I do not think it means what you think it means." – yshavit Jul 22 '14 at 14:56
  • I must've been mistaken then, shouldn't there still be a different warning that the operation is unsafe? – skiwi Jul 22 '14 at 14:56
  • @skiwi No, there is no warning for this kind of possibly unsafe operations. – flotothemoon Jul 22 '14 at 14:59
  • 1
    @skiwi The assumption is that all downcasts are "unsafe" in that they may cause a `ClassCastException`. Generic casts are _especially_ unsafe, because the `ClassCastException` may happen long after the cast, and thus be hard to debug. In the example, imagine if `list` contained an `Integer`, and then you returned `strings` from a method, stored it in a field in a different class, and later did `String s = strings.get(0)`. That last bit is what will throw the exception, which is hard to track down. It'd be nice if the cast to `(List)` threw the exception, but it can't due to erasure – yshavit Jul 22 '14 at 14:59
  • 1
    @yshavit: Not *all* casts are unsafe. You can cast from (say) `String` to `Object` for the sake of selecting the desired overload. But that's a relatively rare situation, of course. – Jon Skeet Jul 22 '14 at 15:00
  • True, I meant downcasts. – yshavit Jul 22 '14 at 15:00
1

The term "unchecked" warning is misleading. It does not mean that the warning is unchecked in any way. The term "unchecked" refers to the fact that the compiler and the runtime system do not have enough type information to perform all type checks that would be necessary to ensure type safety. In this sense, certain operations are "unchecked". Source

The warning is not saying that this cast might fail. It is saying, by doing this cast, there might be other type errors as a result.

unholysampler
  • 17,141
  • 7
  • 47
  • 64
0

Java allows this type of cast, since a Throwable may be an Exception.

Normally you would precede it with a test, such as :

    if (cause != null) {
        if (cause instanceof Exception) {
            Exception exCause = (Exception) cause;
            System.out.println(exCause);
        }
    }

This code is perfectly fine and shouldn't give a warning. The compiler is not smart enough to give a warning in your case and not give a warning in my example.

Eran
  • 387,369
  • 54
  • 702
  • 768
0

When downcasting (e.g. from Throwable to Exception) compiler doesn't and shouldn't give warning.

A failed downcast (e.g. trying to cast an Error declared as Throwable to Exception) will simply result to ClassCastException, just like dereferencing null will cause NPE, accessing array beyond bounds will cause ArrayIndexOutOfBoundsException and all the other RuntimeExceptions.

Still, this cast is safe, since at runtime JVM can tell that the cast failed (unlike casting generic instances).

TheCodeArtist
  • 21,479
  • 4
  • 69
  • 130
kajacx
  • 12,361
  • 5
  • 43
  • 70
0

There are two types of casts in Java - upcasting and downcasting.

There are two phases of code execution in Java - compilation and execution.

Compilation checks things like syntax and making sure there aren't any glaring errors.

Execution actually executes the codes and if there is something wrong it will throw an exception.

You can always do an upcast without any error.

However, downcasting can be risky. There are two types of cases when downcasting can be risky. Case #1: You downcast an Object to a String, for example. This can be risky because not all objects are strings. However, the compiler can easily check this by making sure the object that the reference variable points to is a String. This applies to your question because you downcast safely so the compiler is happy. Case #2: You have generics. In the case of generics, during compile time, the compiler does not know what the type is, so it cannot ensure that the casting will work fine. This is when it will throw a warning. If the casting does not work fine, a ClassCast exception will be thrown during runtime.

Neel Sandell
  • 429
  • 5
  • 12