Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why doesn't line 4 generate an unchecked exception?

Tags:

java

/*1.*/ List l = new ArrayList<Number>();
/*2.*/ List<String> ls = l;       // unchecked warning
/*3.*/ l.add(0, new Integer(42)); // another unchecked warning
/*4.*/ String s = ls.get(0);

If the lines 2 and 3 produce an unchecked warning then why doesn't the 4th line generate a unchecked warning since compiler does not know what 'ls' is referring to (List<String> or List<Integer>).

(Note: edited from the OP's original post to make the code display as presumably intended - notably include the type parameters for List<E> everywhere.)

like image 326
Rekha Avatar asked Dec 16 '22 08:12

Rekha


2 Answers

The compiler thinks that ls will genuinely refer to a list of strings - line 4 would be "safe" (in terms of type safety) if there hadn't already been dangerous operations - namely line 2.

With no other warnings involved, a List<String> should always end referring to a list which only contains references to strings (or null). But if you've already broken type safety, all bets are off (other than that the VM will catch those type violations at execution time).

The warning shows which lines are dangerous - in this case, places where you're using a raw type, i.e. you're saying, "Well, we've got a list here. I've no idea what's in it though."

Line 4 doesn't refer to any variables of raw types - it only refers to calling get on a List<String>, and assigning the return value to a String variable. If you think this should produce a warning, please show which section of the Java Language Specification suggests that a warning is appropriate - I think you'll find it hard to do so.

like image 124
Jon Skeet Avatar answered Dec 23 '22 20:12

Jon Skeet


Line 4 produces no compile-time warning because the type of ls is List<String> which means its get methods returns a String or null. Any violation will be caught at compile time and will result in a ClassCastException.

EDIT:

There are a number of things that the compiler knows about that the bytecode verifier and interpreter do not.

  1. generic types
  2. compile-time-only annotations
  3. checked exceptions
  4. outer-class privates

The java compiler knows about these things and so points out errors in their use, but the bytecode verifier and interpreter do not so it "erases" them when producing the portion of the .class file meant for the interpreter.

So the steps in compilation are

  1. Look for all the classes needed by looking for .java and .class files.
  2. Make sure everything type checks.
  3. Erase information not needed by the interpreter (but hide it awway in case javac gets called with the .class on its input CLASSPATH).
  4. Produce the output .class files.
like image 28
Mike Samuel Avatar answered Dec 23 '22 21:12

Mike Samuel