Unchecked cast behavior with and without assignment to variable

Julian Rubin :

Why first line in main does not throw ClassCastException while the second does?

import java.util.function.Function;

class Scratch {

    static <T> T getSomething(Function<Integer, T> fun) {
        return (T) fun;
    }

    public static void main(String[] args) {
        Scratch.<String>getSomething(x -> "hello");
        String something = Scratch.<String>getSomething(x -> "hello");
    }
}
Andy Turner :

The difference is because you don't use the result of the method in the first case, but you do in the second.

A cast is an expression, but it's not a StatementExpression. This means that you can't write this:

(String) somethingReturningAString();

but you can write:

String aString = (String) somethingReturningAString();

At compile time, the compiler inserts checkcast instructions where it needs to, and where it can:

  • It can't insert a cast for the first case, so no checking takes place.
  • It can (and has to) insert a cast in the second case, in order to ensure that it's assigning something that's actually a String to a String variable. As such, it checks the cast, and that fails.

It's worth noting that there are some perhaps unexpected cases where a cast isn't strictly necessary, but is inserted. For example:

Scratch.<String>getSomething(x -> "hello").toString();

would fail with a ClassCastException, since it would be transformed to:

((String) Scratch.getSomething(x -> "hello")).toString();

even though Object has a toString() method, and so it could invoke that without a cast.

Guess you like

Origin http://43.154.161.224:23101/article/api/json?id=76968&siteId=1