Searching Example Using Generics
This example has two main purposes:
- it shows how you can make use of Java's generic classes.
- it shows how you can use interfaces to allow for easy interchangeability
of data structures
Key points about Java generics
- They always use <> brackets
- The type parameters must be classes, not primitive types. The
reason that the type parameters must be classes is that Java
keeps only one bytecode copy of a generic class rather than
one copy for each type instantiation (e.g., one for List<Integer>
and one for List<String>) as in C++. Keeping one bytecode copy
works only if all generic variables represent classes since
the bytecode depends on all variables being a descendent of the
Object class (e.g., the bytecode assumes that all variable accesses
occur through pointers, not primitive types).
A generic can go further and require that its
type parameters implement certain interfaces. For example, a
SortedMap generic requires its key parameter to implement the
Comparator interface. The Comparator interface contains a
compare and equals method, and hence any
implementation of SortedMap can obtain an ordering of keys by
calling the compare and equals methods.
The program shown at the end of this web page solves the following problem:
Write a Java main program that determines whether or not various search
terms are in a list of strings. The input will come from the command
line as follows:
- an integer, n, that represents the number of strings in the list
- n strings representing the strings in the list
- an unspecified number of strings. For each string your program
should determine if the string is in the list.
Write a search method that you call from your main program to perform
the actual search. It should return true/false depending on whether or
not it finds the string. Its parameters should include the collection of
strings and the string to be found.
Your main program should use Java's sorted tree implementation to
store the list of strings. It should then loop through
the remaining strings on the command line, call the search method, and
print the result using System.out.printf. Your program should print the
string and either true/false.
For example, the command:
java search 3 brad nels james jim nancy brad nels
should produce the output:
jim false
nancy false
brad true
nels true
The Program
import java.util.*;
class search {
// The first type parameter to Map represents the type of the key and
// the second type parameter represents the type of the value. In this
// case String represents the key type and Integer represents the value
// type
static boolean find(Set myCollection, String key) {
return myCollection.contains(key);
}
public static void main(String args[]) {
int n = Integer.parseInt(args[0]); // parseInt converts String to int
// java.util.HashSet is Java's hash table implementation for a set
Set searchCollection = new HashSet();
int i;
// add is the method provided by Set to insert a new key
for (i = 0; i < n; i++) {
searchCollection.add(args[i+1]);
}
for (i = n+1; i < args.length; i++) {
// %b is the formatting string for a boolean
System.out.printf("%s %b\n", args[i], find(searchCollection, args[i]));
}
}
}
Interchangeability of Data Structures
Since the above code declares searchCollection to be an interface
type (i.e., Set), rather than a class type (i.e., HashSet), a one word
change to the code transforms the program from using a hash table to using a
tree. I can simply change the line that reads:
Set searchCollection = new HashSet();
to
Set searchCollection = new TreeSet();
If I had instead declared searchCollection to be a specific
class type, namely HashSet, then I would need to change the
declaration of searchCollection in both the above line and in
its parameter declaration in find. Hence by using interface types
I make it easier to rapidly replace data structures if I so desire.