2.3 Iterating Over Parameterized Types
Although the for/in loop provides a
means of almost completely avoiding
the java.util.Iterator class, that particular feature of Tiger isn't
covered until Chapter 7. But until you get to that chapter (and probably
occasionally after that), it's still useful to know how generic collection
types affect Iterator. You'll need to perform an extra step to get the full
power of generics.
2.3.1 How do I do that?
It would seem that once you've parameterized your collections, grabbing
an Iterator and using it would be trivial:
List<String> listOfStrings = new LinkedList<String>( );However, all is not well. Here's what the compiler spits back to you:
listOfStrings.add("Happy");
listOfStrings.add("Birthday");
listOfStrings.add("To");
listOfStrings.add("You");
for (Iterator i = listOfStrings.iterator( ); i.hasNext( ); ) {
String s = i.next( );
out.println(s);
}
[javac] code\src\com\oreilly\tiger\ch02\GenericsTester.java:54:The problem here is that while you've parameterized your List, you
incompatible types
[javac] found : java.lang.Object
[javac] required: java.lang.String
[javac] String s = i.next( );
[javac] ^
[javac] Note: code\src\com\oreilly\tiger\ch02\GenericsTester.java
uses unchecked or unsafe operations.
[javac] Note: Recompile with -Xlint:unchecked for details.
[javac] 1 error
haven't parameterized your Iterator. It's still spitting out Objects, and
doesn't know that it should only expect to receive and respond with
String types. Just like the collections, Iterator is a generic type in Java,
and is declared as public interface Iterator<E>. Its next( ) method,
then, returns E (which is a placeholder,
as detailed in "Using Type-Safe
Lists"). To parameterize it, you use the same syntax as you did for collection
classes:
List<String> listOfStrings = new LinkedList<String>( );Now this Iterator only works with String types, and your code compiles
listOfStrings.add("Happy");
listOfStrings.add("Birthday");
listOfStrings.add("To");
listOfStrings.add("You");
for (Iterator<String> i = listOfStrings.iterator( ); i.hasNext( ); ) {
String s = i.next( );
out.println(s);
}
(and runs) normally. You should always pair your Iterators with
your collections like thisif the collection is parameterized, the Iterator
should use the same parameter.
2.3.2 What about...
...if you define a typesafe Iterator, for a collection that isn't typesafe.
Well, you're basically playing with fire, and assuming that someone filled
the collection correctly. The following code, for example, compiles and
runs without a problem (although you'll get lint warnings, detailed in
"Checking for Lint":
public void testTypeSafeIterators(PrintStream out) throws IOException {In this case, it was probably just an oversight that List wasn't also
List listOfStrings = new LinkedList( );
listOfStrings.add("Happy");
listOfStrings.add("Birthday");
listOfStrings.add("To");
listOfStrings.add("You");
for (Iterator<String> i = listOfStrings.iterator( ); i.hasNext( ); ) {
String s = i.next( );
out.println(s);
}
}
parameterized. However, the following code also compiles fine, but fails
horribly at runtime:
public void testTypeSafeIterators(PrintStream out) throws IOException {The getList( ) method, which
List listOfStrings = getList( );
for (Iterator<String> i = listOfStrings.iterator( ); i.hasNext( ); ) {
String s = i.next( );
out.println(s);
}
}
private List getList( ) {
List list = new LinkedList( );
list.add(3);
list.add("Blind");
list.add("Mice");
return list;
}
presumably could have been coded by a
trusted (or even a non-trusted) source, is supposed to return only String
objects (at least, that's inferred by the use of Iterator<String>). However,
it adds a numeric object (an int that gets boxed into an Integer),
and at runtime a nasty ClassCastException pops up. This is why you
should always parameterize your collections if you want to parameterize
your Iterators. If you took that step, you'd get an error at compile-time
when trying to assign the List returned from getList( ) (which is not
parameterized) to a List<String>. That error protects you from problems
just like this one.