Java 1.5 Tiger A Developers Notebook [Electronic resources]

David Flanagan, Brett McLaughlin

نسخه متنی -صفحه : 131/ 78
نمايش فراداده

7.4 Avoiding Unnecessary Typecasts

While for/in is nice, you still have to perform all those typecasts, as seen in Example 7-1. If you recall from Chapter 2, though, Tiger introduces some pretty powerful language structures in the form of generics. The main thrust of those new structures is to increase type safety, and that, paired with what you already know about for/in, can increase the convenience of this new loop. You can get away with being specific in your loop iterations, rather than getting an Object from each iteration and then casting that Object to the appropriate type.

7.4.1 How do I do that?

The first step in working with type-specific iterators actually has to occur before you ever type for/in. You need to declare your collections using generics:

// These are collections we'll iterate over below.
List<String> wordlist = new ArrayList<String>( );
Set<String> wordset = new HashSet<String>( );

Then write your code normally, except substitute a type-specific variable instead of a generic Object and remove any typecasts:

    for(String word : wordlist) {
System.out.print(word + " ");
}

Example 7-1.

Example 7-2. Using the for/in loop with generics
package com.oreilly.tiger.ch07;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
public class ForInGenericsDemo {
public static void main(String[] args) {
// These are collections we'll iterate over below.
List<String> wordlist = new ArrayList<String>( );
Set<String> wordset = new HashSet<String>( );
// We start with a basic loop over the elements of an array.
// The body of the loop is executed once for each element of args[].
// Each time through one element is assigned to the variable word.
System.out.println("Assigning arguments to lists...");
for(String word : args) {
System.out.print(word + " ");
wordlist.add(word);
wordset.add(word);
}
System.out.println( );
// Iterate through the elements of the List now.
// Since lists have an order, these words should appear as above
System.out.println("Printing words from wordlist " +
"(ordered, with duplicates)...");
for(String word : wordlist) {
System.out.print(word + " ");
}
System.out.println( );
// Do the same for the Set. The loop looks the same but by virtue of
// using a Set, we lose the word order and also discard duplicates.
System.out.println("Printing words from wordset " +
"(unordered, no duplicates)...");
for(String word : wordset) {
System.out.print(word + " ");
}
}
}

The output is identical to that from Example 7-1 (previously shown in "Iterating over Collections"), so I've omitted it here.

7.4.2 What just happened?

When using generics in this manner, you're essentially offloading all the typecasting (and possible ClassCastExceptions) onto the compiler, rather than dealing with them at runtime. When the collections were declared, the use of generics (<String>, syntactically) allowed the compiler to limit the accepted types passed into the collections. As a nice side effect, your for/in statement can make this same assumption, and since the compiler checks all of this at compile-time, rather than runtime, your code works, and saves you some typecasting in the process.