280 likes | 421 Views
Java Collection: Data structure framework. Background. collections store and organize objects for efficient access Java collections: traditional data structures implemented as an object-oriented framework currently only "basic data structures sufficient for most needs"
E N D
Background • collections store and organize objects for efficient access • Java collections: traditional data structures implemented as an object-oriented framework • currently only "basic data structures sufficient for most needs" • sets, linked lists, arrays, and maps • efficiency depends on organization and use • linked vs. sequential allocation, and hashing vs. sorted search trees
Collection architecture • the collections library utilizes heavily inheritance and polymorphism • the library is implemented as a kind of (lightweight) framework, and it enables user-defined extensions • separation of interfaces + their implementations: • Collection • List implemented by ArrayList and LinkedList • Set implemented by HashSet and LinkedHashSet • SortedSet implemented by TreeSet
Collection architecture (cont.) • Map implemented by HashMap, IdentityHashMap, and LinkedHashMap • SortedMap implemented by TreeMap • we have Iterable, Iterator and ListIterator interfaces • Iterable: provides the method iterator () • Iterator: hasNext (), next (), and remove () • ListIterator: add (), set (), hasPrevious (), previous (), nextIndex (), etc.. • additionally, a set of abstract classes that provide skeletons for implementations • apply the Template Method pattern
Generic utility methods • you can write utility methods that can operate on any kind of collection public static <E> boolean contains (Collection <E> c, Object obj) { for (E e : c) if (e.equals (obj) ) return true; return false; } • the above for statement is a short-hand notation for . .for (it = c.iterator (); it.hasNext (); ) { e = it.next ();. .
Using object-oriented collections • the idea: always use collections through interfaces, and separately create them as concrete collections: Set <String> set = new HashSet <String> (); set.add ("first"); set.add ("second"); int n = set.size (); // n is 2 assert set.contains ("first"); • you should always ask what is the most general class or interface that can do the required job
Design of Collection framework • a built-in class library should satisfy many mutually conflicting requirements: • easy to learn and convenient to use • as general as possible: dynamic / flexible / immutable, etc. structures • idiot-proof with complete run-time checks, and • as efficient as hand-coded algorithms • fit some language limitations: • Java cannot express and enforce constness at compile time • Java generics involves no run-time type info
Design of framework (cont.) • the concrete implementations provide different performance and errors • the interfaces abstract these differences away providing very general and concise interfaces • the design makes compromises between practical requirements and pure conceptual modelling • for example, interfaces have so-called optional operations, forbidden by specific implementations, e.g., Iterator.remove () • a called forbidden optional operation throws UnsupportedOperationException (unchecked) • thus, constant views on collections are supported (only) by run-time checks
Design of framework (cont.) • such refusal of inherited operations is clearly an is-a violation, at the conceptual level • the general object-oriented substitution principle: "operation that expects an instance of a supertype must also accept an instance of a subtype" does not hold here • such solutions are strongly discouraged by most object-oriented methodologies • you should (generally) avoid applying these techniques in the design and interfaces of your own object-oriented applications
Overview: Collection • expressed as hierarchically organized interfaces • Collection represents a "bag" (multiset) of values: duplicates are (in principle) allowed • List is a sequentially ordered set of values • values in a List are ordered by position and can be identified by integer indices (0..) • implemented as an array or as a linked list • Set provides otherwise identical interface to Collection but allows no duplicates • values in a Set are not necessarily ordered or sorted • SortedSet is sorted by comparison of element values
Overview: Map Map is an "associative table" of key-value pairs • insert key-value pair: V oldValue = map.put (keyObject, newValue) • get value, or null if the key is not found: value = map.get (keyObject) For example, Map <String, V> map = new HashMap <String, V> (); map.put ("first", x); map.put ("second", y); map.put ("third", x); assert map.get ("first").equals (x); V v = map.remove ("first");
Overview: SortedMap • SortedMap is sorted by comparison of element values • either by natural order given by the object class, or by a separate comparison method • must either implement the Comparable interface, or use a Comparator object
Views into collections • in the Java data structure library, Maps are not considered to be Collections • however, views use Collection interfaces • aMap.entrySet () returns a Set of Map.Entries • Map.Entry provides methods: getKey (), getValue (), and setValue (v) • however, no getEntry (key) is provided (vs. C++ STL) - Entry is an interface, only • note that collection views are an application of the Proxy design pattern [Gamma et al, p. 207]
Views into collections (cont.) • collection methods are not by default thread-safe, i.e., not synchronized for concurrent access • this avoids unnecessary overheads • interfaces do not determine whether implemented methods are synchronized or not (as usual) • thread-safe collection handling is supported by separate synchronized views, created by a call: Collections.synchronizedX (X c), where X can be Collection, List, Map, Set, SortedMap, or SortedSet • note: class Collections is not interface Collection
Views into collections (cont.) • similarly, a constant collection may be created by a call: • Collections.unmodifiableX (X c) • framework also offers "generic" (C++ STL like) algorithms: searching and sorting, etc. • the old "legacy" classes (Vector, Hashtable, etc.) have been fitted into the framework • however, the legacy classes are synchronized, and thus involve a substantial overhead
Collections and iterators • all Collection objects and their iterators show similar general behaviour: // implementation-dependency here only: Collection <E> coll = new LinkedList <E> (); // use through abstract interface: coll.add (element); ... Iterator <E> iterator = coll.iterator (); while (iterator.hasNext ()) { E element = iter.next (); // .. do something with element } ...
Using iterators • the method iterator () returns an implementation of Iterator that can be used to traverse and possibly modify the collection: while (iter.hasNext ()) . . . obj = iter.next () obj = iter.remove () • of course, accessing past the already reached end of a list is considered a programming error • if hasNext () returns false, then calling next () will throw (unchecked) NoSuchElementException
Using iterators (cont.) • iterator represents a position between two elements in the data structure • note: C++ containers use a different strategy: iterators are (abstract) pointers to elements • an iterator can provide a way to remove an element related to that position • iterator.remove () removes the element returned by the last next () • note that next () must be called (at least once) before each removal
Collection services • a sample of Collection methods: Iterator iterator () int size (); boolean isEmpty () boolean contains (Object v) boolean containsAll (Collection <?> c) boolean equals (Object other) boolean add (E element) boolean addAll (Collection <? extends E> c) boolean remove (Object element)
Collection services (cont.) . . . boolean removeAll (Collection <?> c) void clear () boolean retainAll (Collection <?> c) Object [ ] toArray () <T> T [ ] toArray(T [ ] a) // may allocate bigger • note that E [ ] array = ... List <E> list = Arrays.asList (array) // a proxy can be used to create a fixed-size listbacked by the specified array (changes "write through" to the array)
Collection services (cont.) • many operations (add, etc.) return a boolean value to indicate whether the operation really modified the data structure • e.g., remove (obj) returns true if a maching (equals) object was removed • note that iterator's remove returns void (as does ListIterator) • for a more detailed description of java.util.Collection services, see the API or the textbook, pp. 85 - 93
The List Interface • the List interface defines a sequentially ordered set of values: // pos means position index 0..size list.add (pos, obj) list.addAll (pos, aCollection) list.get (pos) list.set (pos, obj) obj = list.remove (pos) ListIterator <E> iter = list.listIterator () ListIterator <E> iter = list.listIterator (fromPos)
The List Interface . . . pos = list.indexOf (obj) pos = list.lastIndexOf (obj) sublist = list.subList (from, beyond) // get view • subList creates a proxy object that • is backed by this list, so non-structural changes are reflected in the original list, and vice-versa • supports all of the optional list operations supported by the backing list • becomes undefined if the backing list is structurally modified in other way than via the proxy
ListIterator • the related ListIterator traverses the elements in order, possibly also modifying the data structure iter = list.listIterator (fromPos); • backwards traversing, index handling, and insertion of values: while (iter.hasPrevious ()) . . . obj = iter.previous () iter.add (obj) iter.set (obj) pos = iter.nextIndex () pos = iter.previousIndex ()
ListIterator (cont.) • ListIterator represents an indexed position within a sequential data structure • the iterator represents a position between two elements; or at beginning before all others (0); or at end, after all elements (size ()) • the method add (v) inserts the new element at the current position, i.e., before the next element • if previous () is called after add, the new element is returned • so, calling add repeatedly puts elements in the exact order they are given • increases by one nextIndex and previousIndex • note that the Iterator interface allowed only a removal of an element (optional)