Basic concepts
The Java container library takes the idea of "holding your objects" and divides it into two distinct concepts, expressed as the basic interfaces of the library:
1. Collection: a sequence of individual elements with one or more rules applied to them. A List must hold the elements in the way that they were inserted, a Set cannot have duplicate elements, and a Queue produces the elements in the order determined by a queuing discipline (usually the same order in which they are inserted).
2. Map: a group of key-value object pairs, allowing you to look up a value using a key. An ArrayList allows you to look up an object using a number, so in a sense it associates numbers to objects. A map allows you to look up an object using another object. It’s also called an associative array, because it associates objects with other objects, or a dictionary, because you look up a value object using a key object just like you look up a definition using a word. Maps are powerful programming tools.
Although it’s not always possible, ideally you’ll write most of your code to talk to these interfaces, and the only place where you’ll specify the precise type you’re using is at the point of creation. So you can create a List like this:
List<Apple> apples = new ArrayList<Apple>();
Notice that the ArrayList has been upcast to a List, in contrast to the way it was handled in the previous examples. The intent of using the interface is that if you decide you want to change your implementation, all you need to do is change it at the point of creation, like this:
List<Apple> apples = new LinkedList<Apple>();
Thus, you’ll typically make an object of a concrete class, upcast it to the corresponding interface, and then use the interface throughout the rest of your code.
This approach won’t always work, because some classes have additional functionality. For example, LinkedList has additional methods that are not in the List interface, and a TreeMap has methods that are not in the Map interface. If you need to use those methods, you won’t be able to upcast to the more general interface.
The Collection interface generalizes the idea of a sequence—a way of holding a group of objects. Here’s a simple example that fills a Collection (represented here with an ArrayList) with Integer objects and then prints each element in the resulting container:
//: holding/SimpleCollection.java import java.util.*; public class SimpleCollection { public static void main(String[] args) { Collection<Integer> c = new ArrayList<Integer>(); for(int i = 0; i < 10; i++) c.add(i); // Autoboxing for(Integer i : c) System.out.print(i + ", "); } } /* Output: 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, *///:~
Since this example only uses Collection methods, any object of a class inherited from Collection would work, but ArrayList is the most basic type of sequence.
The name of the add( ) method suggests that it puts a new element in the Collection. However, the documentation carefully states that add( ) "ensures that this Collection contains the specified element." This is to allow for the meaning of Set, which adds the element only if it isn’t already there. With an ArrayList, or any sort of List, add( ) always means "put it in," because Lists don’t care if there are duplicates.
All Collections can be traversed using the foreach syntax, as shown here. Later in this chapter you’ll learn about a more flexible concept called an Iterator.
[Thinking in Java, 278]