CISC 3115
Modern Programming Techniques
Lecture 10
The Java Collection Framework (JCF)
Framework
Good definitions from Chat:
- "A framework is a set of interfaces and cooperating classes that define a common way to solve a class of problems, providing reusable
implementations and allowing code to work with abstractions rather than specific implementations."
- "The Java Collections Framework is a unified architecture of interfaces, implementations, and algorithms that lets you use and swap data
"structures consistently by programming to interfaces.
In this context we have:
- defniition of interfaces (
Collection, List, Set)
- multiple implementations of the interfaces (
ArrayList, LinkedList)
- algorithms that operate in the context of an interface (sortig , searching across imeplementations)
Collection
- Container
- Data structure whose primary purpose is to hold other
elements
- Familiar case - array
- Properties/attributes
- Random access via explicitly-specified position (index)
- Fixed-size vs variable size
- Ordered vs unordered
Some (Future) CISC 3130 Material
The different implementations of the various collections are usually primarily concerned with access/modification time
- Linked lists are linear structures and provide sequential access
- Getting to the n'th elemenet takes time proportional to n
- Hash tables provide (nearly) constant access, but no order
- Getting to any element takes about the same time as any other
- Trees provide access/insertion/removal in logarithmic time, and order.
- Getting to any element takes at most logs the number of elements (i.e., for a million element tree, about 20)
Interface Inheritance and Implementation, Class Inheritance
Remember:
- Subclasses extend (inherit) superclasses
- The subclass acquires all members (instance variables and methods) of the superclass, and possibly
adds its own
- Subinterfaces extend (inherit) superinterfaces
- The subinterface acquires the specification of all the methods of the superinterface and possibly adds
its own
- Classes implement (super)interfaces
- The class acquires the obligation to implement the methods of the interface
Constructs that Support Common Behavior
- interface
- behavior specification only
- inheritance
- Behavior specification and Implementation inheritance
- abstract class
- Partial implementation, some behavior implementation left to subclasses
Typical Common Behaviors
Here are some fundamental Java interfaces:
- Ability to compare (
Compareable)
- Consequences: min, max, sort
- Ability to traverse/be traversed (
Iterator/Iterable)
- Consequences: searching, visiting and processing each element
- Ability to add and remove items (
Collection)
- Consequences: container/collection
The Java Collections Framework
From the Oracle Java Tutorial
The Collection Hierarchy
Common Behavior -- The Polymorphic Receiver
If we program to the interface (or at the superclass level), the receiver can be an object of any implementing (sub) class
Object obj = …
…
Set set = new TreeSet(); // An implementing class of the Set interfce
set.add(obj); // collections take Object as their element type
…
set = new HashSet(); // another implement class of Set
set.add(obj);
…
Collection coll = set; // Set is a subinterfce of Collection
coll.add(obj);
…
coll = new ArrayList(); // ArrayList is an implementing class of List which is a subinterfcace of COllection
coll.add(obj);
…
coll = new Stack(); // Stack is a subclass of Vector which is an implementing class of
coll.add(obj);
…
…
void myAdd(Collection c, Object obj) {c.add(obj);} // the receiver c could be any Collection object sent to themyAdd
…
…
myAdd(set, obj);
myAdd(coll, obj);
- All
Collection objects (i.e. classes that implement Collection) accept invocations of the
add method.
Common Behavior -- The Polymorphic Argument
As we've seen above, a related notion is that an implementing class object can be passed to any reference variable that is a legitimate upcast candidate (superclass, interface that it implements)
add(Object obj) {...}
- Allows ANY object to be added to the collection
void addAll(Collection colla;) // defined in the Collection interface
- Allows ANY collection to be added to the collection
- We will shortly see that this is because any
Collection object can be iterated over
- In the
addAll method we thus iterate over coll and add each element to to
receiver.
- We thus have a method defined in the
Collection interface (ind thus mplemented by any 'collection' class), that further accepts
any argument that is an object of any (same or other) implementing class).
- This means that if we have, say 10 implementing classes of
Collection rather than coding 100 methods that permit
adding any collection type to any other, we need only one!
The Map Interface
- Maps keys to values.
- Simple-minded, 'intuitive' implementation is a pair of parallel arrays: one for key, the other for value
Map
HashMap
SortedMap
TreeMap
The Collection Hierarchy in Detail
(Iterable)
- Not part of the
Colectin hierarchy per say, sits above it
- There are other classes outside the hiserarchy that implement
Iterable
- Represents items that can bve iterated over
- In consequence, permits use of the enhanced for loop
- Operation
Collection
- Represents a group of objects called elements
- Ordered/unordered
- Duplicates/no duplicates
- Operations
- add
- clear
- contains
- equals
- isEmpty
- iterator
Actually inherited from Iterable
- Provides an object that allows iteration over the collection
- Allows iteration over non-sequence collections (e.g.
Set)
- remove
- size
- toArray - allows collections to be converted into an array
- forms one side of the bridge between arrays and collections
Iterator
- Supports iteration over a collection
- Operations
List
- A type of
Collection
- Ordered
- Sequence
- User has control over insertion point
- Elements are accssed by integer index
- Allows for duplicate elements
- Operations (in addition to those of Collection)
- add (to a particular position)
- find position of an object in list
- get
- remove (at a particular position)
- set
- Analysis
- Access may be proportional to index being accessed
- Searching may be linear in cost
Set
- A type of
Collection
- No duplicate elements
- No new operations-- merely new constraints on existing operations
Map
- maps keys to values
- One value (at most) per key
- Ordered/unordered (by key)
- Not quite a collection-- its own beast
- Though you may have seen this in math-- it's essentially a relation - a set of pairs
- Operations
- clear
- containKey
- containsValue
- entrySet - gets a Set of the key/value pairs in the map
- get (the value associated with a key)
- isEmpty
- keySet - gets the Set of keys
- put - associates a key with a value
- remove - a value associated with the given key
- values - gets the Collection of values in the map
SortedSet
- A type of
Set
- Ordered by natural order of keys
- Operations (in addition to those of a Set)
- first
- headSet
- last
- subSet
- tailSet
SortedMap
- A type of
Map
- Ordered by natural order of keys
- Operations (in addition to those of a Set)
- firstKey
- headMap
- lastKey
- subMap
- tailMap
ArrayList/Vector
- A type of
List
- Growable array of objects
- Random access via explicitly-specified position (index)
- Number of elements varies dynamically
- Automatic memory management
- Analysis
- Constant time insertion/removal at end
- Linear time insertion/removal at beginning or middle
- Operations
- add/addElement
- add (to a particular position)/insertElementAt
- elementAt/get
- firstElement
- lastElement
- remove/removeElementAt
- set/setElementAt
- Iteration
- From first to last element in index order
Vector v = new Vector();
Scanner scanner = new Scanner(new File("...));
while (scanner.hasNextLine()
v.add(scanner.nextLine());
Iterator iter = v.iterator();
while (iter.hasNext()) {
String s = (String)iter.next(); // Have to state that it's a String
System.err.println(s); // or do whatever you want with the string
}
Stack
- (A type of
Vector)
- LIFO (last-in-first-out)
- Implicit access (no real control on part of user)
- Operations (in addition to those of Vector)
Queue
- A type of
Collection
- FIFO (first-in-first-out)
- Implicit access
- Operations (in addition to those of Collection
HashSet
- A type of
Set
- No guaranteed order
- Analysis
- Constant time access/insert/remove
HashSet hs = new HashSet();
String line = br.readLine(); // assume BufferedReader br
while (line != null) {
hs.add(line); // could add ANY object to hs
line = br.readLine();
}
Iterator iter = hs.iterator();
while (iter.hasNext()) { // No particular order
String s = (String)iter.next(); // Have to state that it's a String
System.err.println(s); // or do whatever you want with the string
}
HashMap
- A type of
Map
- No guaranteed order
- Analysis
- Constant time access/insert/remove
HashMap hm = new HashMap();
Employee employee = Employee.read(br); // assume BufferedReader br
while (employee != null) {
hm.put(employee.getSSNum(), employee)); // could use ANY key or value for tm
employee = Employee.read(br);
}
Set keys = hm.keySet(); // Get the set of keys
Iterator iter = keys.iterator();
while (iter.hasNext()) { // No particular order
String sSNum = (String)iter.next(); // Have to state that it's a String
Employee e = (Employee)tm.get(sSNum);
System.err.println(e); // or do whatever you want with the Employee object
}
TreeSet
- A type of
SortedSet
- Ordered by natural order of keys
- Analysis
- Logarithmic time access/insert/remove
TreeSet ts = new TreeSet();
String line = br.readLine(); // assume BufferedReader br
while (line != null) {
ts.add(line); // could add ANY object to ts
line = br.readLine();
}
Iterator iter = ts.iterator();
while (iter.hasNext()) { // Natural order of String (alphabetical order)
String s = (String)iter.next(); // Have to state that it's a String
System.err.println(s); // or do whatever you want with the string
}
TreeMap
- A type of
SortedMap
- Ordered by natural order of keys
- Analysis
- Logarithmic time access/insert/remove
- Iteration
- Iterate over set of keys, retrieving the value for each key
- Natural order of keys
TreeMap tm = new TreeMap();
Employee employee = Employee.read(br); // assume BufferedReader br
while (employee != null) {
tm.put(employee.getSSNum, employee)); // could use ANY key or value for tm
line = br.readLine();
}
Set keys = tm.keySet(); // Get the set of keys
Iterator iter = keys.iterator();
while (iter.hasNext()) { // Natural order of the key -- a String (alphabetical order)
String sSNum = (String)iter.next(); // Have to state that it's a String
Employee e = (Employee)tm.get(sSNum);
System.err.println(e); // or do whatever you want with the Employee object
}
LinkedList
- A type of
List
- Linked list implementation
- Doubly-linked
- Operations
- addFirst
- addLast
- getFirst
- getLast
- removeFirst
- removeLast
Deque
AbstractCollection
AbstractList
AbstractMap
AbstractQueue
AbstractSet
Autoboxing and Generics
Overview
As of Java 1.5 (Java 5), two highly useful (and long-awaited) features made their debut
- Generics
- Provides increased type-safety for collections
- Eliminates most downcasting
- Autoboxing
- Eliminates much of the drudgery of working with wrapper classes
Generics
- Prior to 1.5:
Vector v = new Vector();
while (...) { // adding String's to the vector
String s = ...;
v.add(s);
}
...
Iterator iter = v.iterator();
while (iter.hasNext()) { // Extracting elements of the vector
String s = (String)iter.next(); // downcast needed
...
}
- Collections can now be declared with their element types:
Vector<String> v = new Vector<String>
- The compiler enforces this declaration
Vector<String> v = new Vector<String>
v.add(new Integer(5)); // compiler error
- Collection is then guaranteed to be homogeneous
- Above
Vector can only contain Strings
- Downcasting can then be done automatically by the compiler
Vector<String> v = new Vector<String>
String s = ...;
v.add(s);
...
String s2 = v.elementAt(0); // no need for downcast-- compiler takes care of it
- Collection processing is now much simpler
Vector<Strin>> v = new Vector<String>();
while (...) { // adding String's to the vector
String s = ...;
v.add(s);
}
...
Iterator<String> iter = v.iterator();
while (iter.hasNext()) { // Extracting elements of the vector
String s = iter.next(); // no downcast needed
...
}
- Users can create their own generic class definitions as well
Enhanced for loop
Random r = new Random();
Vector<Integer> v = new Vector<Integer>();
for (int i = 0; i < 100; i++)
v.add(new Integer(r.nextInt(200)));
for (Integer i : v)
System.out.println(i);
Map<String, Integer> concordance = new TreeMap<String, Integer>();
…
…
for (String s : concordance.keySet())
System.out.println(s + ": " + concordance.get(s));
Autoboxing
- any time a primitive type appears in a context requiring an object, the
type is wrapped (by the compiler) into its wrapper class object
Vector<Integer> v = new Vector<Integer>
...
v.add(3); // compiler automatically insert a 'new Integer(3)'
- any time an object appears in a context requiring a primitive type, the
object is unwrapped into its corresponding primtive type
Vector<Integer> v = new Vector<Integer>
...
int i = v.elementAt(0); // compiler automatically insert a '.intValue()'