St.Antario
St.Antario

Reputation: 27385

What's wrong with the unchecked cast?

I'm reading J. Bloch's effective Java and now I'm at the arrays vs lists section. Here is an example of unchecked cast he provided:

interface Function<T> {
    T apply(T arg1, T arg2);
}

public class Main{
    public static void main( String[] args ){
        Function<String> f = null;
        List<String> str = Arrays.asList("asd");
        //staff
        reduce(str, f, ""); //E's deduced to String. Where is type-unsafe?
    }
    static <E> E reduce(List<E> list, Function<E> f, E initVal) {
        E[] snapshot = (E[]) list.toArray(); // Unchecked cast
        E result = initVal;
        for (E e : snapshot)
            result = f.apply(result, e);
        return result;  
    }
}

He said that the method is not type-safe and we can easily get the ClassCastException. But I don't see how. Where's the type-unsafe, the type variable E will always be deduced to the appropriate type so we're no worried about class-cast-exeption.

Couldn't you give an example with throwing ClassCastException?

Upvotes: 15

Views: 3179

Answers (4)

Pranav Mishra
Pranav Mishra

Reputation: 197

Object[] toArray() Returns an array containing all of the elements in this list in proper sequence (from first to last element).

We are casting this to E[] inferring generics so the cast is unchecked because jvm doesnt know what type E will be so the warning.

Say for example, E is String type(as in code by you). And we are trying to cast Object[] to String[], which can very well be Object[] to Integer[] for some other case. This validity cant be tested at compile/run time by jvm so the issue.

 public static void main( String[] args ){
    List<String> str = Arrays.asList("asf");
    //staff

    System.out.println(reduce(str, 2)); //E's deduced to String. Where is type-unsafe?
}
static <E, T> E reduce(List<E> list, T initVal) {
    Object snapshot = list.size(); // Unchecked cast   
    return (E) snapshot;
}

This will create class cast exception.

Upvotes: 4

Mena
Mena

Reputation: 48404

The list.toArray idiom you employ here is not parametrized by an array of your List's parametrized type, so it returns Object[].

For instance, with your List<String> str, you can invoke: String[] foo = str.toArray(new String[str.size()]); without casting.

The problem here is that, due to Java generics' design, you can never initialize a new E[], hence you have to cast to (E[]).

I cannot see this throwing a ClassCastException ever as is.

As others have mentioned, the "cosmetic" workaround is to add @SuppressWarnings("unchecked") before your toArray invocation, which will suppress the warning.

Upvotes: 4

Tagir Valeev
Tagir Valeev

Reputation: 100209

There's no compile-time guarantee that list.toArray() will return the array of type E[]. Moreover it almost always returns an array of type Object[]. Thus depending on the later usage of this array you may have a ClassCastException. For example, consider the following code:

public static void main( String[] args ){
    List<String> str = Collections.singletonList("asd");
    String[] array = test(str);
}

static <E> E[] test(List<E> list) {
    E[] snapshot = (E[]) list.toArray(); // Unchecked cast
    return snapshot;
}

Here you return this E[] array and the receiver expects that String[] array is returned. But actually it's Object[] array, thus you will get the ClassCastException in main method after the returned generic type is implicitly cast to the String[].

In your code you can be sure that the array is used in safe way. But compiler is not smart enough to make this analysis, so it just warns you.

Upvotes: 13

Binkan Salaryman
Binkan Salaryman

Reputation: 3048

There is nothing wrong with your cast, but with Java Generics:

static <E> E reduce(List<E> list, Function<E> f, E initVal) {
    @SuppressWarnings({"unchecked"}) //nevermind
    E[] snapshot = (E[]) list.toArray(); //Unchecked cast
    E result = initVal;
    for (E e : snapshot)
        result = f.apply(result, e);
    return result;
}

Upvotes: 3

Related Questions