43
Page 1 of 43 TalentSprint Collection Framework Introduction to the Collections Framework Collection Interfaces Iterator Interface Group Operations AbstractCollection Class Collection Framework Design Concerns Set Interface HashSet, TreeSet Classes List Interface Map interface Sorting Historical Collection Classes

Collectn framework

Embed Size (px)

Citation preview

Page 1: Collectn framework

Page 1 of 43

TalentSprint

Collection Framework

Introduction to the Collections Framework Collection Interfaces

Iterator Interface Group Operations

AbstractCollection Class

Collection Framework Design Concerns Set Interface

HashSet, TreeSet Classes List Interface

Map interface Sorting

Historical Collection Classes

Page 2: Collectn framework

Page 2 of 43

TalentSprint

Collection Framework

Objective

At the end of this chapter, you will be able to:

Learn about the implementation of Collection Interfaces:

Understand the Iterator Interface and Group Operation

Know in details about the AbstractCollection Class

Prepare yourself for Collection Framework Design Concerns

Gain knowledge about the Set Interface

Get some ideas about the HashSet, TreeSet Classes

Deal with List Interface, Map interface and Sorting

Have a basic idea about Historical Collection Classes such as Dictionary, Hashtable and Properties Classes

Page 3: Collectn framework

Page 3 of 43 TalentSprint

Collection Framework

Introduction

Data encapsulation is one of the important features of OOPs. But, this doesn‘t mean the

data organization inside classes is not important. The way you structure your data

depends on your requirement and the problem you need to solve. Does your class need to

search for items quickly? Does it require sorted elements and rapid inserts and deletions of

elements? Does it need an array-like structure with random-access ability that can grow at

run time? The way data is structured inside classes is very important to improve the

performance.

This chapter tells you how Java helps you structure your data needed for programming.

Prior to JDK1.2, only a few classes were provided for data structures by the standard

library. Vector, Stack, HashTable, BitSet and Enumeration interface are some of them.

Enumeration interface provided an abstract mechanism to access elements in an arbitrary

container. It takes time and skill to come up with a comprehensive collection class library.

With the advent of JDK 1.2 the Standard Library supplied a full-fledged set of data

structures. The designers had faced a number of conflicting design decisions. Hence they

wanted the library to be small and easy to learn. They wanted the benefit of ―generic

algorithms‖ that STL pioneered and not the complexity of the ―Standard Template Library‖

(or STL) of C++,. They wanted the new framework to accommodate the legacy classes.

They had to make some hard choices, and came up with a number of distinctive design

decisions. This chapter takes you through the basic design of the Java collections

framework, let you know how to make it work, and reasons behind some of its

controversial features.

Just like other data structure libraries, the Java collection library also separates interfaces

and implementations.

Collections Overview

This chapter deals with one of the powerful subsystems: Collections. Collections provide a

well-defined set of interfaces and classes to store and manipulate groups of data as a

single unit. This unit is called a collection.

The framework provides a convenient API to many of the abstract datatypes like maps,

sets, lists, trees, arrays, hashtables and other collections. The Java classes in the

Collections Framework encapsulate both the data structures and the algorithms associated

with these abstractions because of their object-oriented design.

The framework provides a standard programming interface to many of the most common

abstractions, without complicating it with too many procedures and interfaces. The

programmer can easily define higher-level data abstractions like stacks and queues with

the help of a variety of operations supported by the collections framework.

The major goals of the Collections Framework are:

High-performance.

Implementations for the fundamental collections (dynamic arrays, linked lists,

trees, and hash tables) are highly efficient.

Should avoid coding of these ―data engines‖ manually.

Should allow different types of collections to work in a similar manner.

Page 4: Collectn framework

Page 4 of 43

TalentSprint

Collection Framework

Should have a high degree of interoperability.

Should be easy to extend and/or adapt a collection.

Towards this end, the entire collections framework is designed around a set of standard

interfaces.

Several standard implementations (such as LinkedList, HashSet, and TreeSet) of these

interfaces are ready to use. You can also use your own collections. Various special-purpose

implementations are created for your convenience, and some partial implementations are

provided to make it easier to have user-defined Collection class. Mechanisms were added

to integrate standard arrays into the collections framework.

Algorithms are another major part of the collection mechanism, which operate on

collections and are defined as static methods within the Collections class. Thus, they are

available for all collections. Each collection class need not implement its own version. A

standard means of manipulating collections is provides by these algorithms.

Iterator interface is another item created by the collections framework. It provides a

general-purpose, standardized way of accessing the elements within a collection, one at a

time. Thus, an iterator provides a means of enumerating the contents of a collection.

Because each collection implements Iterator, the elements of any collection class can be

accessed through the methods defined by Iterator. Thus, with only small changes, the

code that cycles through a set can also be used to cycle through a list, for example.

In addition to collections, several map interfaces and classes are defined within the

framework. Maps store key/value pairs. Though maps are not actually collections, they are

completed integrated with collections. In the language of the collections framework, you

can obtain a collection-view of a map. Such a view contains the elements from the map

stored in a collection. Thus, you can process the contents of a map as a collection.

The collection mechanism was retrofitted to some of the original classes defined by

java.util so that they too could be integrated into the new system. Although the addition

of collections altered the architecture of many of the original utility classes, it did not

cause the deprecation of any. Collections simply provide a better way to do many things.

One last thing: familiarity to C++ will help you to know that the Java collections

technology is similar in spirit to the Standard Template Library (STL) defined by C++.

What C++ calls a container, Java calls it ,a collection.

Collection Interfaces

The Collections Framework is made up of a set of interfaces for working with groups of

objects. The different interfaces describe the different types of groups. Once you are clear

with the interfaces, you can easily understand the framework. While you always need to

create specific implementations of the interfaces, access to the actual collection should be

restricted to the use of the interface methods, thus allowing you to change the underlying

data structure, without altering the rest of your code. The following diagrams show the

framework interface hierarchy.

Page 5: Collectn framework

Page 5 of 43 TalentSprint

Collection Framework

Fig 1:The hierarchy of collection interfaces.

The root of the hierarchy of the collections interfaces is the Collection interface. It is also

referred to as the superinterface of the collections. There is another kind of collection

called maps, which are represented by the superinterface Map, which is not derived from

the Collection interface. Both kinds of collections interfaces are shown in Fig 1 above.

The List and Set interfaces extend from the Collection interface, and there is no direct

implementation of the Collection interface. Some of characteristics of the subinterfaces of

Collection (that is, List and Set) and of Map are as follows:

• List: An ordered collection of data items; i.e. The position of each data item is defined

and known. A list can have duplicate elements.

ArrayList, LinkedList, and Vector are the classes that implement the List interface.

• Map: An object that maps keys to values: each key can map to at most one value. Maps

cannot have duplicate keys.

HashMap and HashTable are some of the classes that implement the Map

interface. Duplicate keys are not allowed in maps but duplicate values are

allowed.

• Set: A collection of unique items; i.e. there are no duplicates.

HashSet and LinkedHashSet are examples of classes that implement the Set

interface.

Implementations of Collections Interfaces:

Classes, which implement the interfaces and represent reusable data structures to hold the

data items, are the Implementations of the collections interfaces. As you know, the

purpose of a collection is to represent a group of related objects, known as its elements.

Depending upon the application requirements, these related data items could be grouped

together in various ways.

Following Fig 2 shows the hierarchy of collection and map implementations.

Page 6: Collectn framework

Page 6 of 43

TalentSprint

Collection Framework

Fig 2:The hierarchy of collection and map implementations

As per the application requirements, duplicate elements are allowed with some collections.

Some are ordered and others are unordered. There are certain restrictions on elements

that an implementation can contain, such as no null elements, and there can be

restrictions on the types of their elements. Consider the following features. The

implementation you choose depends on which of them is important for your application.

• Performance: It refers to the time taken by a specific operation on the data as a

function of the number of data items in the structure, such as accessing a given data item

(search) and inserting or deleting an item in the data structure. In some data structures,

the search and insertion/deletion may have opposing performance requirements. That

means if a data structure offers fast search, the insertion/deletion may be slow.

• Ordered/sorted: A data structure is said to be ordered if the data items are in a

specific order. For example, an array is an ordered data structure because the data items

are ordered by index; that is, we can refer to the data items with their index, such as the

seventh element. A data structure is said to be sorted if the data items are ordered either

by ascending order or descending order of their values. So, by definition, a sorted data

structure is an ordered data structure, but not vice versa.

• Uniqueness of items: If you require each data item of the data structure to be

uniquely identifiable, or on the contrary, you want to allow duplicate items.

• Synchronized: Implementations are synchronized when they provide thread safety (i.e.

they can be run in a multithreaded environment). However, need not be considered while

Page 7: Collectn framework

Page 7 of 43 TalentSprint

Collection Framework

choosing an implementation, because you can always use synchronization methods from

the Collections class even if the implementation is unsynchronized.

The characteristics of different implementations of the collections interfaces are

summarized in the following Table1:

Table 1: Implementations of the Collections Interfaces characteristics

Usage of Pre-defined Methods of Collection Interface:

The Collection interface is used to represent any group of objects, or elements. The

interface is used when you want to work with a group of elements in a very generalized

manner.

Below is a list of the public methods of Collection:

boolean add(Object element)

boolean add(Collection col)

void clear()

boolean contains(Object element)

boolean containsAll(Collection col)

boolean equals(Object element)

int hashcode()

Iterator iterator()

boolean remove(Object element)

boolean removeAll(Collection col)

boolean retainAll(Collection col)

int size()

Object[] toArray()

Object[] toArray(Object[] array)

Page 8: Collectn framework

Page 8 of 43

TalentSprint

Collection Framework

The interface supports basic operations like adding and removing. When an element is

removed, only an instance of the element in the collection is removed, if present.

boolean add(Object element)

boolean remove(Object element)

The Collection interface also supports query operations:

int size()

boolean isEmpty()

boolean contains(Object element)

Iterator iterator()

Iterator Interface

The iterator() method of the Collection interface returns an Iterator interface type. An

Iterator is similar to the Enumeration interface, which will be discussed later. You can

traverse a collection from start to finish and safely remove elements from the underlying

Collection with the help of the iterator() method:

boolean hasNext()

Object next()

void remove()

The remove() method is optionally supported by the underlying collection. Its function is to

remove the element returned by the last next() call. To illustrate, the following shows the

use of the Iterator interface for a general Collection:

//DEMONSTRATE ITERATOR TO ACCESS A COLLECTION

import java.util.*;

class iteratordemo

{

public static void main(String args[])

{

ArrayList al=new ArrayList();

al.add("pehla");

al.add("dusra");

al.add("teesra");

al.add("chautha");

al.add("panchwa");

al.add("chhatha");

al.add("sathwa");

al.add("athwa");

al.add("nawa");

al.add("daswa");

//Use iterator to display contents of al.

Page 9: Collectn framework

Page 9 of 43 TalentSprint

Collection Framework

System.out.println("Original contents of al :");

Iterator itr = al.iterator();

while(itr.hasNext())

{

Object element=itr.next();

System.out.print(element+" ");

}

System.out.println();

//Modify objects being created.

ListIterator litr = al.listIterator();

while(litr.hasNext())

{

Object element=litr.next();

litr.set(element+"+ ");

}

System.out.println("Modified contents of al :");

itr = al.iterator();

while(itr.hasNext())

{

Object element=itr.next();

System.out.print(element+" ");

}

System.out.println();

//Now display the list backwards.

System.out.println("Modified list backwards :");

while(litr.hasPrevious())

{

Object element=litr.previous();

System.out.print(element+" ");

}

System.out.println();

}

}

Group Operations

Group operations are tasks done on groups of elements or the entire collection at once:

boolean containsAll(Collection collection)

boolean addAll(Collection collection)

void clear()

void removeAll(Collection collection)

void retainAll(Collection collection)

Page 10: Collectn framework

Page 10 of 43

TalentSprint

Collection Framework

The containsAll() method tells you whether the current collection contains all the elements

of another collection, a subset. The remaining methods are optional, in that a specific

collection might not support the altering of the collection.

The addAll() method ensures the addition of all elements from another collection to the

current collection, usually a union.

The clear() method removes all elements from the current collection.

The removeAll() method is like clear() but only removes a subset of elements.

The retainAll() method is similar to the removeAll() method, but does what might be

perceived as the opposite. It removes from the current collection those elements not in the

other collection, an intersection.

The remaining two interface methods, which convert a Collection to an array, will be

discussed later.

AbstractCollection Class

The AbstractCollection class provides the foundation for the concrete collection framework

classes. While you can implement all the methods of the Collection interface yourself, the

AbstractCollection class provides implementations for all the methods, except for the

iterator() and size() methods, which are implemented in the appropriate subclass. Optional

methods like add() will throw an exception if the subclass doesn't override the behavior.

Collection Framework Design Concerns

While creating the Collections Framework, the Sun development team had to provide

flexible interfaces that manipulated groups of elements. To keep the design simple, the

interfaces define all the methods an implementation class may provide. However, some of

the interface methods are optional. Because an interface implementation must provide

implementations for all the interface methods, there needed to be a way for a caller to

know if an optional method is not supported. The manner the framework development

team chose to signal callers when an optional method is called was to throw an

UnsupportedOperationException exception. If while using a collection, an

UnsupportedOperationException is thrown while trying to add to a read-only collection,

then it indicates that the operation failed because it is not supported.Yhe

UnsupportedOperationException class is an extension of the RuntimeException class.

In addition to handling optional operations with a runtime exception, the iterators for the

concrete collection implementations are fail-fast. That means that if you are using an

Iterator to traverse a collection while underlying collection is being modified by another

thread, then the Iterator fails immediately by throwing a ConcurrentModificationException

(another RuntimeException). That means the next time an Iterator method is called, and

the underlying collection has been modified, the ConcurrentModificationException

exception gets thrown.

Set Interface

The Set interface defines a set and extends the Collection interface. It forbids duplicates

within the collection. All the original methods are present and no new methods are

introduced. The concrete Set implementation classes rely on the equals() method of the

object added to check for equality.

Page 11: Collectn framework

Page 11 of 43 TalentSprint

Collection Framework

boolean add(Object element)

boolean addAll(Collection col)

void clear()

boolean contains(Object element)

boolean containsAll(Collection col)

boolean equals(Object object)

int hashCode()

Iterator iterator()

boolean remove(Object element)

boolean removeAll(Collection col)

boolean retainAll(Collection col)

int size()

Object[] toArray()

HashSet, TreeSet Classes

HashSet and TreeSet are the two general-purpose implementations of the Set interface

provided by the Collections framework. Generally, you will use a HashSet for storing your

duplicate-free collection. In order to improve the efficiency, objects added to a HashSet

need to implement the hashCode() method in a manner that properly distributes the hash

codes. Most of the system classes override the default hashCode() implementation in

Object. You have to override hashCode() when creating your own classes to add to a

HashSet. You will find the TreeSet implementation to be useful when you need to extract

elements from a collection in a sorted manner. In order to work properly, elements added

to a TreeSet must be sortable. The Collections Framework adds support for Comparable

elements and will be covered in detail later. As of now, assume a tree knows how to keep

elements of the java.lang wrapper classes sorted. It is generally faster to add elements to

a HashSet and then convert the collection to a TreeSet for sorted traversal.

Tuning the initial capacity and the load factor you will be able to make optimal usage of

HashSet space. The TreeSet has no tuning options, as the tree is always balanced,

ensuring log(n) performance for insertions, deletions, and queries.

Both HashSet and TreeSet implement the Cloneable interface.

HashSet Usage Example

import java.util.*;

class hashsetdemo

{

public static void main(String args[])

{

HashSet hs=new HashSet();

hs.add("TERA");

hs.add("JADOO");

hs.add("CHAL");

hs.add("GAYA");

Page 12: Collectn framework

Page 12 of 43

TalentSprint

Collection Framework

System.out.println(hs);

}

}

TreeSet Usage example:

import java.util.*;

class treesetdemo

{

public static void main(String args[])

{

TreeSet t=new TreeSet();

t.add("t");

t.add("j");

t.add("c");

t.add("g");

System.out.println(t);

}

}

AbstractSet Class

To ensure two equal sets return the same hash code, the AbstractSet class overrides the

equals() and hashCode() methods. If both the sets are the same size and contain the

same elements, then they are said to be equal. By definition, the hash code for a set is the

sum of the hash codes for the elements of the set. Thus, irrespective of what the internal

ordering of the sets is, same hash code is reported by the two equal sets.

List Interface

The List interface extends the Collection interface to define an ordered collection and it

permits duplicates. The interface adds position-oriented operations, and also the ability to

work with just a part of the list. Below is a list of methods provided by the List Interface:

boolean add(Object element)

void add(int index, Object element)

boolean addAll(Collection collection)

boolean addAll(int index, Collection collection)

void clear()

boolean contains(Object element)

boolean containsAll(Collection collection)

Page 13: Collectn framework

Page 13 of 43 TalentSprint

Collection Framework

boolean equals(Object object)

Object get(int index)

int hashCode()

Iterator iterator()

int lastIndexOf(Object element)

ListIterator listIterator()

ListIterator listiterator(int startIndex)

boolean remove(Object element)

Object remove(int index)

boolean removeAll (Collection collection)

boolean retainAll(Collection collection)

Object set(int index, Object element)

int size()

List sublist(int fromIndex, int toIndex)

Object[] toArray()

Object[] toArray(Object[] array )

The position-oriented operations include the ability to insert an element or Collection, get

an element, as well as remove or change an element. Searching for an element in a List

can be started from the beginning or end and will report the position of the element, if

found. Some of the methods to implement position-oriented operations are:

void add(int index, Object element)

boolean addAll(int index, Collection collection)

Object get(int index)

int indexOf(Object element)

int lastIndexOf(Object element)

Object remove(int index)

Object set(int index, Object element)

The List interface also helps working with a subset of the collection, and iterating through

the entire list in a position friendly manner:

ListIterator listIterator()

ListIterator listIterator(int startIndex)

List subList(int fromIndex, int toIndex)

It is important to mention that the element at fromIndex is in the sub list in working with

subList(), but the element at toIndex is not. This loosely maps to the following for-loop

test cases:

for (int i=fromIndex; i<toIndex; i++) {

// process element at position i

}

Page 14: Collectn framework

Page 14 of 43

TalentSprint

Collection Framework

In addition, it should be mentioned that changes to the sublist like add(), remove(), and

set() calls have an effect on the underlying List.

ListIterator Interface

To support bi-directional access, as well as adding or changing elements in the underlying

collection, Iterator interface is extended to ListIterator interface. listIterator() method

returns an object of listIterator class type.

void add(Object element)

boolean hasNext()

boolean hasPrevious()

Object next()

int nextIndex()

Obejct previous()

int previousIndex()

void remove()

void set(Obejct element)

The code below illustrates the looping backwards through a list. Notice that the ListIterator

is originally positioned beyond the end of the list [list.size()], as the index of the first

element is 0.

List list = ...;

ListIterator iterator = list.listIterator(list.size());

while (iterator.hasPrevious()) {

Object element = iterator.previous();

// Process element

}

Generally, ListIterator is not used to alternate between going forward and backward in one

iteration through the elements of a collection. While technically possible, one needs to

know that calling next() immediately after previous() results in the same element being

returned. The same thing happens when you reverse the order of the calls to next() and

previous().

In case of add() operation, adding an element results in the new element being added

immediately prior to the implicit cursor. Thus, calling previous() after adding an element

would return the new element and calling next() would have no effect, returning what

would have been the next element prior to the add operation.

ArrayList, LinkedList Classes

There are two general-purpose List implementations in the Collections Framework:

ArrayList and LinkedList. Based on your specific needs, you can choose between the two

list implementations. Suppose, random access is what you require, without inserting or

removing elements from any place other than the end, then ArrayList offers the optimal

collection. However, if your requirement is frequent addition and removal of elements from

the middle of the list and only access the list elements sequentially, then, LinkedList offers

the better implementation.

Page 15: Collectn framework

Page 15 of 43 TalentSprint

Collection Framework

Both the general-purpose implementations, ArrayList and LinkedList, implement the

Cloneable interface. Additionally, to work with the elements at the ends of the list, several

methods are provided by LinkedList. (Only the new methods are shown in the following

list):

void addFirst(Object element)

void addLast(Object element)

Object getFirst()

Object getLast()

Obejct removeFirst()

Obejct removeLast()

Below is a program to demonstrate ArrayList usage:

import java.util.* ;

class ArrayListDemo

{

public static void main(String args[])

{

ArrayList a1 = new ArrayList();

System.out.println("Initital Size Ofa1 " +a1.size()) ;

//add elements

a1.add("sql");

a1.add("niit");

a1.add("aptech");

a1.add("ssi");

a1.add("cmc");

a1.add("pannet");

a1.add("tulec");

a1.add("ignou");

a1.add("iddco");

System.out.println(" Size Of a1 After addition " +a1.size()) ;

// display array list

System.out.println("content of a1 " +a1) ;

a1.remove("tulec");

a1.remove(3);

System.out.println(" Size Of a1 After deletion " +a1.size()) ;

System.out.println(" content of a1 " +a1) ;

}

}

Page 16: Collectn framework

Page 16 of 43

TalentSprint

Collection Framework

Below is the program to implement Linkedlist:

import java.util.*;

class linkedlistdemo

{

public static void main(String args[])

{

LinkedList ll=new LinkedList();

System.out.println("Initial size of ll :"+ll.size());

//add elements

ll.add("sql");

ll.add("niit");

ll.add("nimt");

ll.add("aptech");

ll.add("first");

ll.add("ignou");

ll.add("idco");

ll.add("narimann");

ll.add("telco");

ll.add("officenet");

ll.add("hindalco");

ll.add("nalco");

ll.addLast("last mein rahe gaya");

ll.addFirst("pehle main aa gaya");

ll.add(2,"teen number pe ghus gaya");

System.out.println("Size of ll after addition :"+ll.size());

//display array list

System.out.println("Contents of ll :"+ll);

ll.removeFirst();

ll.removeLast();

System.out.println("Size of ll after this :"+ll.size());

System.out.println("Contents of ll :"+ll);

//get & set the vals

Object val=ll.get(2);

ll.set(2,(String)val+" Changed");

System.out.println("ll after changed :"+ll);

}

}

You can easily treat the LinkedList as a stack, queue, or other end-oriented data structure

by using new methods.

Page 17: Collectn framework

Page 17 of 43 TalentSprint

Collection Framework

LinkedList queue = ...;

queue.addFirst(element);

Object object = queue.removeLast();

LinkedList stack = ...;

stack.addFirst(element);

Object object = stack.removeFirst();

The Vector and Stack classes will be discussed in later sections.

List Usage Example

To illustrate the use of the concrete List classes, see the following program. The first part

creates a List backed by an ArrayList. After filling the list, specific entries are retrieved.

The LinkedList part of the example treats the LinkedList as a queue, adding things at the

beginning of the queue and removing them from the end.

import java.util.*;

public class Listdemo {

public static void main(String args[]) {

List list = new ArrayList();

list.add("Sunday");

list.add("Monday");

list.add("Tuesday");

list.add("Monday");

list.add("Wednesday");

System.out.println(list);

System.out.println("2: " + list.get(2));

System.out.println("0: " + list.get(0));

LinkedList queue = new LinkedList();

queue.addFirst("Sunday");

queue.addFirst("Monday");

queue.addFirst("Tuesday");

queue.addFirst("Monday");

queue.addFirst("Wednesday");

System.out.println(queue);

queue.removeLast();

queue.removeLast();

System.out.println(queue);

}

}

Page 18: Collectn framework

Page 18 of 43

TalentSprint

Collection Framework

Running the program produces the following output. Notice that, unlike Set, List permits

duplicates.

[Sunday, Monday, Tuesday, Monday, Wednesday]

2: Tuesday

0: Sunday

[Wednesday, Monday, Tuesday, Monday, Sunday]

[Wednesday, Monday, Tuesday]

AbstractList and AbstractSequentialList Classes

AbstractList and AbstractSequentialList are two abstract List implementations classes. Just

Like the AbstractSet class, they override the equals() and hashCode() methods to ensure

two equal collections return the same hash code. If they are the same size and contain the

same elements in the same order, then the two sets are said to be equal. The hashCode()

implementation is specified in the List interface definition and implemented here.

Apart from the equals() and hashCode() implementations, AbstractList and

AbstractSequentialList provide partial implementations of the remaining List methods. For

random-access and sequential-access data sources, respectively, they help creating

concrete list implementations easily. Based on which behavior you want to support, you

can choose between the set of methods.

The table below shows methods that need to be implemented. But, you never to provide

the implementation of the Iterator iterator() method.

AbstractList AbstractSequentialList

unmodifiable Object get(int index)

int size()

ListIterator listIterator(int index)

- boolean hasNext()

- Object next()

- int nextIndex()

- boolean hasPrevious()

- Object previous()

- int previousIndex()

int size()

modifiable unmodifiable +

Object set(int index, Object element)

unmodifiable +

ListIterator

- set(Object element)

variable-size

and modifiable

modifiable +

add(int index, Object element)

Object remove(int index)

modifiable +

ListIterator

- add(Object element)

- remove()

Two constructors, a no-argument one and one that accepts another Collection, should also

be provided.

Page 19: Collectn framework

Page 19 of 43 TalentSprint

Collection Framework

Map Interface

The Map interface starts off its own interface hierarchy, for maintaining key-value

associations. It is not an extension to Collection interface. According to it‘s definition, the

interface describes a mapping from keys to values, without duplicate keys.

void clear()

boolean containsKey(Object key)

boolean containsValue(Object value)

Set entrySet()

Object get(Object key)

boolean isEmpty()

Set keySet()

Object put(Object key, Object value)

void putAll(Map mapping)

Object remove(Object key)

int size()

Collection values()

The interface methods can be broken down into three sets of operations: altering,

querying, and providing alternative views.

The alteration operations allow you to add and remove key-value pairs from the map even

when the key and value can be null. However, you should not add a Map to itself as a key

or value.

Object put(Object key, Object value)

Object remove(Object key)

void putAll(Map mapping)

void clear()

The query operations allow you to check on the contents of the map:

Object get(Object key)

boolean containsKey(Object key)

boolean containsValue(Object value)

int size()

boolean isEmpty()

The last set of methods allows you to work with the group of keys or values as a

collection.

public Set keySet()

public Collection values()

public Set entrySet()

Page 20: Collectn framework

Page 20 of 43

TalentSprint

Collection Framework

Since the collection of keys in a map must be unique, you get a Set back. Since the

collection of values in a map may not be unique, you get a Collection back. The last

method returns a Set of elements that implement the Map.Entry interface, described next.

Map.Entry Interface

The entrySet() method of Map returns a collection of objects that implement Map.Entry

interface. Each object in the collection is a specific key-value pair in the underlying Map.

boolean equals(Object object)

Object getKey()

Object getValue()

int hashCode()

Object setValue(Object value)

Iterating through this collection, you can get the key or value, as well as change the value

of each entry. However, the set of entries becomes invalid, causing the iterator behavior

to be undefined, if the underlying Map is modified outside the setValue() method of the

Map.Entry interface.

HashMap, TreeMap Classes

HashMap and TreeMap are the two general-purpose Map implementations provided by the

Collections Framework. As with all the concrete implementations, which implementation

you use depends on your specific needs. The HashMap offers the best alternative for

inserting, deleting, and locating elements in a Map. However, if you need to traverse the

keys in a sorted order, then TreeMap is a better alternative. Depending upon the size of

your collection, it may be faster to add elements to a HashMap, and then convert the map

to a TreeMap for sorted key traversal. Using a HashMap requires that the class of key

added have a well-defined hashCode() implementation. With the TreeMap implementation,

elements added to the map must be sortable.

Tuning the initial capacity and load factor will help you make optimal use of HashMap

space. The TreeMap has no tuning options, as the tree is always balanced.

The Cloneable interface can be implemented with both HashMap and TreeMap.

The Hashtable and Properties classes are historical implementations of the Map interface.

Map Usage Example

The following program demonstrates the use of the concrete Map classes.

First let us see the usage of HashMap class:

HashMap Example:

import java.util.*;

class HashMapDemo

{

public static void main(String args[])

{

HashMap hm = new HashMap();

Page 21: Collectn framework

Page 21 of 43 TalentSprint

Collection Framework

hm.put("amarendra mohanty",new Double(5000));

hm.put("sarada satpathy",new Double(4500));

hm.put("pravat pala",new Double(6000));

hm.put("mitrabhanu tripathy",new Double(7000));

Set set =hm.entrySet();

Iterator i =set.iterator();

while (i.hasNext())

{

Map.Entry me = (Map.Entry)i.next();

System.out.println(me.getKey()+":");

System.out.println(me.getValue());

}

System.out.println();

double balance = ((Double) hm.get("amarendra mohanty")).doubleValue();

hm.put("amarendra mohanty", new Double ( balance +1000));

System.out.println("amarendra mohanty new balance is "

+hm.get("amarendra mohanty"));

}

}

Now, let us see the usage of a TreeMap class implementation:

TreeMap Example:

import java.util.*;

class TreeMapDemo

{

public static void main(String args[])

{

TreeMap hm = new TreeMap();

hm.put("mitrabhanu tripathy ",new Double(5000));

hm.put("sarada satpathy",new Double(4500));

hm.put("amarendra mohanty",new Double(6000));

hm.put("pravat pala",new Double(7000));

Set set =hm.entrySet();

Iterator i =set.iterator();

while (i.hasNext())

{

Map.Entry me = (Map.Entry)i.next();

System.out.println(me.getKey()+":");

System.out.println(me.getValue());

}

System.out.println();

Page 22: Collectn framework

Page 22 of 43

TalentSprint

Collection Framework

double balance = ((Double) hm.get("pravat pala")).doubleValue();

hm.put("pravat pala", new Double ( balance +5000));

System.out.println("pravat pala new balance is " +hm.get("amarendra

mohanty"));

}

}

AbstractMap Class

Similar to the other abstract collection implementations, the AbstractMap class overrides

the equals() and hashCode() methods to ensure two equal maps return the same hash

code. Two maps are equal if they are the same size, contain the same keys, and each key

maps to the same value in both maps. By definition, the hash code for a map is the sum of

the hash codes for the elements of the map, where each element is an implementation of

the Map.Entry interface. Thus, no matter what the internal ordering of the maps, two

equal maps will report the same hash code.

WeakHashMap Class

A special-purpose implementation of Map called A WeakHashMap is provided for storing

only weak references to the keys. This allows for the key-value pairs of the map to be

garbage collected when the key is no longer referenced outside the WeakHashMap. It is

beneficial to use WeakHashMap when you have to maintain registry-like data structures,

where the utility of an entry vanishes when its key is no longer reachable by any thread.

Sorting

To add support for Sorting, many changes have been done to the core Java libraries with

the addition of Collection Framework in the Java 2 SDK version 1.2. Comparable interface

can be implemented by classes like String and Integer so that a natural sorting order is

provided. You can implement the Comparator interface to define your own order when you

desire a different order than the natural order, or for the classes without a natural order.

To take advantage of the sorting capabilities, SortedSet and SortedMap are the two

interfaces provided by Collections Framework.

Comparable Interface

The Comparable interface, in the java.lang package, is for those classes, which have a

natural ordering. The interface allows you to order the collection into that natural ordering

when a collection of objects is of the same type.

int compareTo(Object element)

compareTo(): Using this method, current instance can be compared with an element that

is passed as an argument. If the current instance comes before the argument in the

ordering, it returns a negative value, whereas if the current instance comes after, then a

positive value is returned. Otherwise, it returns a zero. It is does not mean that a zero

return value signifies equality of elements but it just signifies that two objects are ordered

at the same position.

Several classes implement the Comparable interface. You will observe from the below

table that some classes share the same natural ordering. Only mutually comparable

classes can be sorted. This goes for the current release of the SDK. (that means the same

class.)

Page 23: Collectn framework

Page 23 of 43 TalentSprint

Collection Framework

The following table shows their natural ordering.

Class Ordering

BigDecimal

BigInteger

Byte

Double

Float

Integer

Long

Short

Numerical

Character Numerical by Unicode value

CollationKey Locale-sensitive string ordering

Date Chronological

File Numerical by Unicode value of characters in fully-qualified, system-

specific pathname

ObjectStreamField Numerical by Unicode value of characters in name

String Numerical by Unicode value of characters in string

The documentation for the compareTo() method of String defines the ordering

lexicographically. This implies the comparison is of the numerical values of the characters

in the text, which is not necessarily alphabetically in all languages. For locale-specific

ordering, use Collator with CollationKey.

The following demonstrates the use of Collator with CollationKey to do a locale-specific

sorting:

import java.text.*;

import java.util.*;

public class CollatorTest {

public static void main(String args[]) {

Collator collator =

Collator.getInstance();

CollationKey key1 =

collator.getCollationKey("Som");

CollationKey key2 =

collator.getCollationKey("som");

CollationKey key3 =

collator.getCollationKey("shon");

CollationKey key4 =

collator.getCollationKey("Shon");

CollationKey key5 =

collator.getCollationKey("Shonar");

Set set = new TreeSet();

Page 24: Collectn framework

Page 24 of 43

TalentSprint

Collection Framework

set.add(key1);

set.add(key2);

set.add(key3);

set.add(key4);

set.add(key5);

printCollection(set);

}

static private void printCollection(

Collection collection) {

boolean first = true;

Iterator iterator = collection.iterator();

System.out.print("[");

while (iterator.hasNext()) {

if (first) {

first = false;

} else {

System.out.print(", ");

}

CollationKey key =

(CollationKey)iterator.next();

System.out.print(key.getSourceString());

}

System.out.println("]");

}

}

Running the program produces the following output:

[shon, Shon, Shonar, som, Som]

Making your own class Comparable is just a matter of implementing the compareTo()

method. It usually involves relying on the natural ordering of several data members. Your

own classes should also override equals() and hashCode() to ensure two equal objects

return the same hash code.

Comparator Interface

When java.lang.Comparable cannot be implemented with a class or if you don‘t like the

default Comparable behavior, you can provide your own java.util.Comparator.

int compare(Object element1, Object element2)

boolean equals(Object object)

The return values of both the methods, compare() method of Comparator and

compareTo() method of Comparable are similar. In this case, if the first element comes

before the second element in the ordering, it returns a negative value. If the first element

Page 25: Collectn framework

Page 25 of 43 TalentSprint

Collection Framework

comes after, then a positive value is returned. It returns a zero value. As we have seen in

the case of Comparable, even in comparator interface, zero return value does not signify

equality of elements. It just signifies that two objects are ordered at the same position.

It depends on the user of the Comparator to determine how to deal with it. If two unequal

elements compare to zero, you should first be sure what you want. When used with a

TreeSet or TreeMap it can be tedious to use a Comparator that is not compatible to

equals(). With a Set, only the first will be added. With a map, the value for the second will

replace the value for the second (keeping the key of the first).

To demonstrate, you may find it easier to write a new Comparator that ignores case,

instead of using Collator to do a locale-specific, case-insensitive comparison. The following

is one such implementation:

class CaseInsensitiveComparator implements

Comparator {

public int compare(Object element1,

Object element2) {

String lowerE1 = (

(String)element1).toLowerCase();

String lowerE2 = (

(String)element2).toLowerCase();

return lowerE1.compareTo(lowerE2);

}

}

Since every class subclasses Object at some point, you need not implement the equals()

method. In most cases you do not implement it. The equals() method compares only the

comparator implementations and not the objects being compared.

With the Collections class, a predefined Comparator is available for reuse. Objects that

implement the Comparable interface are sorted in reverse order by a comparator which is

returned as a result of calling Collections.reverseOrder().

SortedSet Interface

For maintaining elements in a sorted order, a special Set interface, SortedSet is provided

by the Collections Framework.

Comparator comparator()

Object first()

SortedSet headSet(Object toElement)

Object last()

SortedSet subSet(Object fromElement , Object toElement)

SortedSet tailSet(Object fromElement)

Access methods are provided to the ends of the set as well as to subsets of the set by the

interface. When you work with these subsets of the list, you can see that the changes to

the subset are reflected in the source set and vice versa. This works because elements

identify the subsets at the end points and not indices. Moreover, if the fromElement is part

of the source set then it is also a part of the subset. However, if the toElement is part of

Page 26: Collectn framework

Page 26 of 43

TalentSprint

Collection Framework

the source set, it is not part of the subset. If you want a particular to-element to be in the

subset, you have to find out the next element. In the case of a String, the next element is

the same string with a null character appended (string+"\0").

The elements added to a SortedSet must either implement Comparable or you must

provide a Comparator to the constructor of its implementation class: TreeSet. (You can

implement the interface yourself. But the Collections Framework only provides one such

concrete implementation class.)

To demonstrate, the following example uses the reverse order Comparator available from

the Collections class:

import java.text.*;

import java.util.*;

public class Comp {

public static void main(String args[]) {

Comparator comparator = Collections.reverseOrder();

Set reverseSet = new TreeSet(comparator);

reverseSet.add("January");

reverseSet.add("February");

reverseSet.add("March");

reverseSet.add("February");

reverseSet.add("April");

System.out.println(reverseSet);

}

}

Running the program produces the following output:

[March, January, February, April]

Because sets must hold unique items, if comparing two elements when adding an element

results in a zero return value (from either the compareTo() method of Comparable or the

compare() method of Comparator), then the new element is not added. If the elements

are equal, then that is okay. However, if they are not, then you should modify the

comparison method such that the comparison is compatible with equals().

Using the following creates a set with three elements: thom, Thomas, and Tom, not five

elements as might be expected.

Comparator comparator =

new CaseInsensitiveComparator();

Set set = new TreeSet(comparator);

set.add("Tom");

set.add("tom");

set.add("thom");

set.add("Thom");

Page 27: Collectn framework

Page 27 of 43 TalentSprint

Collection Framework

set.add("Thomas");

SortedMap Interface

SortedMap: It is a special Map interface provided by the Collections Framework for

maintaining keys in a sorted order.

Comparator comparator()

Object firstKey()

SortedMap headMap(Object toKey )

Object lastKey()

SortedMap subMap (Object fromKey, Object toKey)

SortedMap tailMap (Object fromKey)

Access methods are provided by the interface to the ends of the map as well as to subsets

of the map. A SortedMap workd just like a SortedSet, except that the sort is done on the

map keys. TreeMap is the implementation class provided by the Collections Framework.

Since the key value pairs are unique, (i.e. one maps can only have one value for every

key), if a zero value is returned while comparing two keys when adding a key-value pair

(from either the compareTo() method of Comparable or the compare() method of

Comparator), then new value replaces the value for the original key. If the result is zero

then it is fine. But when they are not, then comparison method should be modified such

that the comparison is compatible with equals().

Historical Collection Classes

There can be situations when you need to use some of the original collections capabilities

rather than the new ones. The capabilities of working with some of these collections

(arrays, vectors, hashtables, enumerations, and other historical capabilities.) is shown

below:

Arrays

You must have learnt about arrays while learning the basics of Java programming

language. According to their definition, Arrays are fixed-size collections of the same

datatype. You must remember that only Arrays can store primitive datatypes. All others

including arrays, can store objects. While creating an array, the number and type of object

you wish to store has to be specified. The size of an array can neither grow nor store a

different type. (unless it extends the first type).

To find out the size of an array, you ask its single public instance variable, length, as in

array.length.

To access a specific element, either for setting or getting, you place the integer argument

within square brackets ([int]), either before or after the array reference variable. The

integer index is zero-based, and accessing beyond either end of the array will throw an

ArrayIndexOutOfBoundsException at runtime. However, if a long variable is used to access

an array index, you get a compiler-time error.

Arrays are full-fledged subclasses of java.lang.Object. They can be used with the various

Java programming language constructs excepting an object:

Page 28: Collectn framework

Page 28 of 43

TalentSprint

Collection Framework

Consider the following example to implement Array class:

import java.util.*;

class ArrayDemo

{

public static void main ( String args[])

{

int array[] = new int [10];

for ( int i =1; i<10;i++)

array[i]= 3 * i ;

System.out.println(" Origina;l Content ") ;

display(array);

Arrays.sort(array);

System.out.println("Sorted : ") ;

display(array);

Arrays.fill(array,2,6,-1);

System.out.println("After fill() :") ;

display(array);

System.out.println("The value -9 is at location") ;

int index = Arrays.binarySearch(array,-9);

System.out.println(index) ;

}

static void display( int array[])

{

for ( int i=0;i<10;i++)

System.out.println(array[i]+" ") ;

System.out.println("") ;

}

}

When an array is created, it is automatically initialized, either to false for a Boolean array,

null for an Object array, or the numerical equivalent of 0 for everything else.

To make a copy of an array, perhaps to make it larger, you use the arraycopy() method of

System. In the destination array, you need to preallocate the space.

System.arraycopy(Object sourceArray, int sourceStartPosition, Object

destinationArray, int destinationStartPosition, int length)

Vector and Stack Classes

A Vector is a historical collection class whose size can grow, but it can store heterogeneous

data elements. With the Java 2 SDK, version 2, List interface can be implemented by the

Page 29: Collectn framework

Page 29 of 43 TalentSprint

Collection Framework

Vector class as it has been retrofitted into the Collections Framework hierarchy. You should

use ArrayList, if you are using the new framework.

When transitioning from Vector to ArrayList, one key difference is the arguments have

been reversed to positionally change an element's value:

From original Vector class

void setElementAt(Object element, int index)

From List interface

void set(int index, Object element)

The Stack class extends Vector to implement a standard last-in-first-out (LIFO) stack, with

push() and pop() methods. Be careful though. Since the Stack class extends the Vector

class, you can still access or modify a Stack with the inherited Vector methods.

Let us see an example to understand the usage of Vector class:

//Vector Example

import java.util.*;

class vectordemo

{

public static void main(String args[])

{

Vector v = new Vector(3,2);

System.out.println("Initial size "+v.size());

System.out.println("Initial capacity "+v.capacity());

v.addElement(new Integer(1));

v.addElement(new Integer(2));

v.addElement(new Integer(3));

v.addElement(new Integer(4));

System.out.println("Capacity after addition "+v.capacity());

v.addElement(new Double(50.20));

v.addElement(new Double(22.56));

System.out.println("Capacity after addition "+v.capacity());

v.addElement(new Float(0.20));

v.addElement(new Float(2.56));

System.out.println("Capacity after addition "+v.capacity());

v.insertElementAt( new Double(10.29),2);

v.removeElementAt(2);

System.out.println("First Element "+(Integer)v.firstElement());

System.out.println("Last Element "+(Float)v.lastElement());

}

}

Let us see an example for the usage of Stack Class:

import java.util.* ;

Page 30: Collectn framework

Page 30 of 43

TalentSprint

Collection Framework

class StackDemo

{

static void showpush( Stack st,int a)

{

st.push(new Integer(a));

System.out.println("push ( " + a + " ) " );

System.out.println("Stack : " + st);

}

static void showpop(Stack st)

{

System.out.println("POP ---- > ");

Integer a = (Integer) st.pop();

System.out.println(a);

System.out.println("Stack : " +st );

}

public static void main(String args[])

{

Stack st = new Stack();

System.out.println("Stack " + st );

showpush(st, 45);

showpush(st, 50 );

showpush(st, 65);

showpush(st,70 );

showpush(st,80);

showpop(st);

showpop(st);

showpop(st);

showpop(st);

showpop(st);

try

{

showpop(st);

}

catch (EmptyStackException e )

{

System.out.println("Empty Stack ");

}

}

Page 31: Collectn framework

Page 31 of 43 TalentSprint

Collection Framework

}

Enumeration Interface

To iterate through all the elements of a collection, you can use Enumeration interface. This

interface has been superceded by the Iterator interface in the Collections Framework. You

may use Enumeration from time to time because all libraries do not support the newer

interface.

boolean hasMoreElements()

Object nextElement()

Iterating through an Enumeration is similar to iterating through an Iterator, though

method names are more preferred with Iterator. However, there is no removal support

with Enumeration.

Enumeration enum = ...;

while (enum.hasNextElement()) {

Object element = iterator.nextElement();

// process element

}

Dictionary, Hashtable, Properties Classes

The Dictionary class is full of abstract methods. Infact, it should have been an interface. It

forms the basis for key-value pair collections in the historical collection classes, with its

replacement being Map, in the new framework. Hashtable and Properties are the two

specific implementations of Dictionary available.

Storage of any object (except null) as its key or value is permitted with the Hashtable

implementation and hence is called a generic dictionary. With the new version of Java

SDK, to implement the Map interface, the class has been reworked into the Collections

Framework. So, you can go for the original Hashtable methods or the newer Map methods.

If you need a synchronized Map, using Hashtable is slightly faster than using a

synchronized HashMap.

To work with text strings, a specialized Hashtable called Properties implementation is

used. Properties class allows gets you text values without any casting whereas you have to

cast values retrieved from a Hashtable to your desired class. Loading and saving property

settings from and input stream or to an output stream is also supported by the class.

System.getProperties() retrieves the system properties list which is the most commonly

used set of properties.

Here‘s an example to understand the usage of HashTable Class:

import java.util.*;

class hashtabledemo

{

public static void main(String args[])

{

//Create a hash table

Hashtable balance=new Hashtable();

Page 32: Collectn framework

Page 32 of 43

TalentSprint

Collection Framework

Enumeration names;

String str;

//Put elements into ‘balance’

balance.put("Benjamin gilani",new Double(3434.34));

balance.put("Nusrulla Khan",new Double(7834.33));

balance.put("Benjamin gilani",new Double(3439.80));

balance.put("Arijit bolbaka",new Double(1378.00));

balance.put("Anu Kalia",new Double(299.34));

balance.put("Ali Kuli Khan",new Double(399.34));

balance.put("Golmal Khan",new Double(-19.34));

//show all balances in hashtable

names=balance.keys();

while(names.hasMoreElements())

{

str=(String)names.nextElement();

System.out.println(str+":"+balance.get(str));

}

System.out.println();

//Deposit 1000 into Benjamin gilani's account

double balance0=((Double)balance.get("Benjamin

gilani")).doubleValue();

balance.put("Benjamin gilani", new Double(balance0+1000));

System.out.println("Benjamin gilani's new balance

"+balance.get("Benjamin gilani"));

//Deposit 2000 into Ali Kuli Khan's account

double balance1=((Double)balance.get("Ali Kuli Khan")).doubleValue();

balance.put("Ali Kuli Khan",new Double(balance1+2000));

System.out.println("Ali Kuli Khan's new balance "+balance.get("Ali

Kuli Khan"));

//Withdraw 1345 from Nusrulla Khan's account

double balance2=((Double)balance.get("Nusrulla Khan")).doubleValue();

balance.put("Nusrulla Khan",new Double(balance2-1345));

System.out.println("Nusrulla Khan's new balance

"+balance.get("Nusrulla Khan"));

}

}

Page 33: Collectn framework

Page 33 of 43 TalentSprint

Collection Framework

BitSet Class

BitSet: It gives an alternate representation of a set. If a finite number of n objects are

given, each object can be associated with a unique integer. Then each possible subset of

the objects corresponds to an n-bit vector, with each bit "on" or "off" depending on

whether the object is in the subset. For small values of n, a bit vector might be an

extremely compact representation. However, for large values of n an actual bit vector

might be inefficient, when most of the bits are off.

Collections Framework Enhancements in J2SE 5

1. Collections framework has been enhanced with the help of three new language

features:

Generics

i. Adds compile-time type safety to the collections framework

ii. Eliminates the need to cast when reading elements from

collections.

Enhanced for loop

i. When iterating over collections, it eliminates the need for explicit

iterators

Autoboxing/unboxing

i. Automatically converts primitives (such as int) to wrapper classes

(such as Integer) when inserting them into collections

ii. Converts wrapper class instances to primitives when reading

from collections.

Understanding Generics

The most important feature added to Collections API is Generics. It plays and important

role in enhanced for loop and autoboxing. Generics are Java's answer to C++ templates,

but in many ways they are much more. A specific type can be associated with collections

with the help of Generics, which was not possible before J2SE 5.0, and if tried to associate,

it created many problems.

import java.util.*;

public class BasicCollection {

public static void main(String args[]) {

ArrayList list = new ArrayList();

list.add( new String("One") );

list.add( new String("Two") );

list.add( new String("Three") );

Iterator itr = list.iterator();

while( itr.hasNext() ) {

String str = (String)itr.next();

System.out.println( str );

Page 34: Collectn framework

Page 34 of 43

TalentSprint

Collection Framework

}

}

}

The preceding code shows how a typical collection class might look prior to J2SE 5.0. The

class creates an ArrayList and adds three strings to it. Note that there's no specific type

associated with this ArrayList; you can add any class that inherits from Object to the

ArrayList.

Look at the while loop that retrieves the strings from the ArrayList.

while(itr.hasNext() ) {

String str = (String)itr.next();

System.out.println( str );

}

The loop iterates over every item in the ArrayList. But notice what you have to do for each

element retrieved—typecast each element. The typecast is required because the ArrayList

does not know what types it stores. This is the problem that generics solve in Java.

Generics allow you to associate a specific type with the ArrayList. So when you upgrade

this BasicCollection class to use generics, the problem disappears. The GenericCollection

class shown below constitutes an upgraded version

import java.util.*;

public class GenericCollection {

public static void main(String args[]) {

ArrayList<String> list = new ArrayList<String>();

list.add( new String("One") );

list.add( new String("Two") );

list.add( new String("Three") );

//list.add( new StringBuffer() );

Iterator<String> itr = list.iterator();

while( itr.hasNext() ) {

String str = itr.next();

System.out.println( str );

}

}

}

As you can see, only a few lines change when you upgrade the class to J2SE 5.0. The first

is the line of code that declares the ArrayList; this version declares the ArrayList using a

type of String.

ArrayList<String> list = new ArrayList<String>();

Page 35: Collectn framework

Page 35 of 43 TalentSprint

Collection Framework

Notice how the code combines the type with the name of the collection. This is exactly how

you specify all generics, delimiting the name of the type with angle brackets (<>), placed

immediately after the end of the collection name.

Next, when declaring the Iterator, you declare it as an Iterator for the String type. You

specify the generic type for the iterator exactly as you did for the ArrayList, for example:

Iterator<String> itr = list.iterator();

That line specifies the Iterator's type as String. Now, when you call the next method for

the iterator, you no longer need the typecast. You can simply call the next method and get

back a String type.

String str = itr.next();

Although that's a nice code-saving feature, generics does more than just save you from

having to do a typecast. It will also cause the compiler to generate a compile error when

you try to add an "unsupported" type to the ArrayList. What is an unsupported type?

Because the ArrayList was declared to accept strings, any class that is not a String or a

String subclass is an unsupported type.

The class StringBuffer is good example of an unsupported type. Because this ArrayList

accepts only Strings, it will not accept a StringBuffer object. For example, it would be

invalid to add the following line to the program.

list.add( new StringBuffer() );

Here's the real beauty of generics. If someone attempts to add an unsupported type to the

ArrayList you won't get a runtime error; the error will be detected at compile time. You will

get the following compile error.

c:\collections\GenericCollection.java:12:

cannot find symbol

symbol : method add(java.lang.StringBuffer)

location: class java.util.ArrayList<java.lang.String>

list.add( new StringBuffer() );

Catching such errors at compile time is a huge advantage for developers trying to write

bug-free code. Prior to J2SE 5.0 this error would have likely shown up later as a

ClassCastException at runtime. Catching errors at compile time is always preferable to

waiting for the right conditions at runtime to cause the bug, because those "right

conditions" may very well appear only after deployment, when your users are running the

program.

Using the Enhanced For Loop

Java did not support for each loop for some time. Using languages like Visual Basic and

C#, looping through the contents of a collection was very easy because they supported a

for loop. With the introduction of for each loop in collections, one can access the contents

of a collection without the need for an iterator. Now (finally) Java has a for each looping

construct, in the form of the enhanced for loop.

Page 36: Collectn framework

Page 36 of 43

TalentSprint

Collection Framework

The enhanced for loop was one of the most anticipated features of J2SE 5.0. It simplifies

your code to a greater extent since there is no need of an iterator. Here's a version,

upgraded to use the enhanced for loop.

import java.util.*;

public class EnhancedForCollection {

public static void main(String args[]) {

ArrayList<String> list = new ArrayList<String>();

list.add( new String("One") );

list.add( new String("Two") );

list.add( new String("Three") );

//list.add( new StringBuffer() );

for( String str : list ) {

System.out.println( str );

}

}

}

The preceding code eliminates the Iterator and while loop completely, leaving just these

three lines of code.

for( String str : list ) {

System.out.println( str );

}

The format for the enhanced for loop is as follows.

for( [collection item type] [item access variable] :

[collection to be iterated] )

The first parameter, the collection item type, must be a Java type that corresponds to the

generic type specified when the collection was created. Because this collection is type

ArrayList, the collection item type is String.

The next parameter provided to the enhanced for loop is the name of the access variable,

which holds the value of each collection item as the loop iterates through the collection.

That variable must also be the same as that specified for the collection item type.

For the last parameter, specify the collection to be iterated over. This variable must be

declared as a collection type, and it must have a generic type that matches the collection

item type. If these two conditions are not met, a compile error will result.

Primitive Data Types and Autoboxing

Page 37: Collectn framework

Page 37 of 43 TalentSprint

Collection Framework

Another feature added to J2SE 5.0 is the ability to automatically box and unbox primitive

datatypes. Using this feature, the complexity is reduced to a great extent when you have

to add and access primitive data types in the collections API.

To understand what boxing and unboxing are, have a look to how primitive data types in

Java were handled prior to J2SE 5.0. Here's a simple Java application that makes use of

primitive data types with the collections API, prior to J2SE 5.0.

import java.util.*;

public class PrimitiveCollection {

public static void main(String args[]) {

ArrayList list = new ArrayList();

// box up each integer as they are added

list.add( new Integer(1) );

list.add( new Integer(2) );

list.add( new Integer(3) );

//list.add( new StringBuffer() );

// now iterate over the collection and unbox

Iterator itr = list.iterator();

while( itr.hasNext() ) {

Integer iObj = (Integer)itr.next();

int iPrimitive = iObj.intValue();

System.out.println( iPrimitive );

}

}

}

The preceding code illustrates two distinct steps that had to occur when using primitives

with the collections API. Because the collection types hold Objects rather than primitive

types, you had to box primitive item types into a suitable wrapper object. For example,

the preceding code boxes the int primitive data type into an Integer object using the

following lines of code:

list.add( new Integer(1) );

list.add( new Integer(2) );

list.add( new Integer(3) );

But the boxing requirement presents a problem when later code tries to access the

primitive int variables stored in the collection. Because the primitive data types were

stored as Integer objects they will be returned from the collection as Integer objects, not

as int variables, forcing yet another conversion to reverse the boxing process:

Iterator itr = list.iterator();

while( itr.hasNext() ) {

Page 38: Collectn framework

Page 38 of 43

TalentSprint

Collection Framework

Integer iObj = (Integer)itr.next();

int iPrimitive = iObj.intValue();

System.out.println( iPrimitive );

}

In this case, the code first retrieves each item as an Integer object, named iObj. Next, it

converts the Integer object into an int primitive by calling its intValue method.

Using autoboxing, storing primitive types in collections and retrieving them becomes far

simpler. Here's an example.

import java.util.*;

public class AutoBoxCollection {

public static void main(String args[]) {

ArrayList<Integer> list = new

ArrayList<Integer>();

// box up each integer as it's added

list.add( 1 );

list.add( 2 );

list.add( 3 );

//list.add( new StringBuffer() );

// now iterate over the collection

for( int iPrimitive: list ) {

System.out.println( iPrimitive );

}

}

}

This autoboxing example begins by creating an ArrayList with the generic type of Integer.

ArrayList<Integer> list = new ArrayList<Integer>();

After creating the list with the wrapper type of Integer, you can add primitive ints to the

list directly.

list.add( 1 );

list.add( 2 );

list.add( 3 );

Now, you no longer need to wrap each integer in an Integer object. In addition, accessing

the individual list members is also considerably easier.

for( int iPrimitive: list ) {

System.out.println( iPrimitive );

}

Page 39: Collectn framework

Page 39 of 43 TalentSprint

Collection Framework

The preceding example shows how you can use the enhanced for loop to iterate over a

collection of primitive data types: in this case, retrieving each primitive variable directly as

an int with no type conversion required. In other words, autoboxing and unboxing let you

use primitive data types with collections as easily as objects.

With the addition of generics to J2SE 5.0, it is easy to specify what type of data a

collection can store exactly. Thus the collection accepts only the correct type of object, and

eliminates the need to typecast items stored to or retrieved from the collection. It is only

the compiler that ensures these entire things.

In many programming languages you have found ‗for‘ in each construct. Now the same

functionality has been used in Generics that allow you to use the enhanced for loop. So by

using ―enhanced for loop" the need for iterators and the whole iterating process through a

collection of items becomes simple and easy.

Finally, it is not an easy task to add primitive data types to collections. Developers have to

handle the feature called Autoboxing and Unboxing where they have to box primitive types

such as int into Integer objects and then unbox back into int primitive types. This results

in much clearer source code while using collections with primitive data types.

However due to these changes, whatever technique you use to access collection data in

J2SE 5.0 is thus been changed. But it has simplified Java code used to access the

collections API to a great extent.

2. There are three new collection interfaces that are provided:

Queue – This represents a collection that is designed to hold elements

before it goes for processing. Other than basic Collection operations, queues

also provide additional insertion, extraction, and inspection operations.

lockingQueue – This is an extension of the Queue that waits for the queue

to become non-empty while retrieving an element and also the wait for

space to become available in the queue when an element is being stored.

(This interface is included in package java.util.concurrent.)

ConcurrentMap – This extends Map with atomic putIfAbsent, remove, and

replace methods. (This interface is included in package java.util.concurrent.)

3. There are two new concrete Queue implementations that are provided, where one

existing List implementation has been retrofitted to implement Queue, and one

abstract Queue implementation is provided:

PriorityQueue – It is an unbounded priority queue backed by a heap.

ConcurrentLinkedQueue – It is an unbounded thread-safe FIFO (first-in

first-out) queue backed by linked nodes. (This class is part of

java.util.concurrent.)

LinkedList – This is retrofitted to implement the Queue interface. LinkedList

behaves as a FIFO queue, when accessed via the Queue interface.

AbstractQueue – An implementation of skeletal Queue.

4. There are five new implementations of BlockingQueue implementations that are

provided. (All of these are included in java.util.concurrent):

LinkedBlockingQueue – It is a FIFO blocking queue, optionally bounded

and backed by linked nodes.

Page 40: Collectn framework

Page 40 of 43

TalentSprint

Collection Framework

ArrayBlockingQueue – It is a FIFO blocking queue, bounded and backed

by an array.

PriorityBlockingQueue – It is an unbounded blocking priority queue

backed by a heap.

DelayQueue – It is a time-based scheduling queue backed by a heap.

SynchronousQueue – It is a simple rendezvous mechanism utilizing the

BlockingQueue interface.

5. There is one ConcurrentMap implementation:

ConcurrentHashMap – It is a ConcurrentMap implementation backed by a

hash table highly concurrent and with high-performance. When this

implementation is used, it never blocks at the time of retrieval and the client

can select the concurrency level for updates. This is done so as to have a

drop-in replacement for Hashtable, which is in addition to implementing

ConcurrentMap. It supports all of the "legacy" methods peculiar to

Hashtable.

6. There are some special-purpose List and Set implementations provided for

situations where read operations are more than write operations and also iteration

cannot or should not be synchronized:

CopyOnWriteArrayList – It is a List implementation backed by an array.

When you make a new copy of the array, all mutative operations (such as

add, set, and remove) are implemented. No synchronization is required,

even during iteration. Iterators promises never to throw

ConcurrentModificationException. This implementation is best for

maintaining event-handler lists (where it has infrequent change, and

traversal is frequent and potentially time-consuming).

CopyOnWriteArraySet – It is a Set implementation backed by a copy-on-

write array. This implementation is same as CopyOnWriteArrayList. The add,

remove, and contains methods require time proportional to the size of the

set which is unlike most Set implementations. This implementation is best

for maintaining event-handler lists that must prevent duplicates.

7. There are special-purpose Set and Map implementations that are provided for use

with enums:

EnumSet – It is a Set implementation backed by a bit-vector with a high-

performance. All elements must be elements of a single enum type of each

EnumSet instance.

EnumMap – It is a Map implementation backed by an array with a high-

performance. All keys must be elements of a single enum type in each

EnumMap instance.

8. For the use with generic collections a new family of wrapper implementations is

provided:

Collections.checkedInterface – It returns a dynamically typesafe view of

the specified collection, which throws a ClassCastException. It throws the

same if a client wants to add an element of the wrong type. You are

provided with compile-time (static) type checking in this generics

Page 41: Collectn framework

Page 41 of 43 TalentSprint

Collection Framework

mechanism but it is possible to defeat this mechanism in the language. This

possibility is eliminated entirely by dynamically typesafe views.

9. There are three new generic algorithms and one comparator converter added to the

Collections utility class:

frequency(Collection<?> c, Object o) - This counts the number of times

the specified element occurs in the specified collection.

disjoint(Collection<?> c1, Collection<?> c2) – This determines

whether they contain no elements in common or whether two collections are

disjoint.

addAll(Collection<? super T> c, T... a) – This is convenient method

where you can add all of the elements in the specified array to the specified

collection.

Comparator<T> reverseOrder(Comparator<T> cmp) – A comparator

is returned that gives you the reverse ordering of the specified comparator.

10. We have content-based hashCode and toString methods outfitted in the Arrays

utility class for arrays of all types. The existing equals() methods is complemented

by these methods. The versions of all the three methods are provided that operate

on nested (or "multidimensional") arrays. They are deepEquals, deepHashCode,

and deepToString. It is not very necessary to print the contents of any array.

The idiom for printing a "flat" array is:

System.out.println(Arrays.toString(a));

The idiom for printing a nested (multidimensional) array is:

System.out.println(Arrays.deepToString(a));

Benefits of the Java Collections Framework

Reduces Programming Effort

The Collection framework provides data structures and algorithms, so that you can

concentrate on only the important parts of your program rather than low-level ―plumbing‖

required making it work.

Interoperability among unrelated APIs is another feature provided by the Java Collections

Framework. So, you no more need to write adapter objects or conversion codes to connect

APIs.

Increases Program Speed and Quality

High-performance, high-quality implementations of useful data structures and algorithms

are some of the benefits provided by the Collections framework. Programs are easily

tunable by switching collection implementations, as implementations of each interface are

interchangeable. As you need not write your own data structures, you can concentrate on

improving programs‘ efficiency.

Reduces Effort to Learn and to Use New APIs

Many APIs naturally take collections on input and furnish them as output. Previously, each

such API had a small sub-API devoted to manipulating its collections. One had to learn

each sub API just because of the little consistency among them. There were lots of

Page 42: Collectn framework

Page 42 of 43

TalentSprint

Collection Framework

chances of making mistakes when using them. But, with the advent of standard collection

interfaces, the problem is solved.

Reduces Effort to Design New APIs

This is the flip side of the previous advantage. While creating an API that relies on

collections, Designers and implementers don't have to reinvent the wheel each time.

Instead, they can use standard collection interfaces.

Fosters Software Reuse

New data structures that conform to the standard collection interfaces are by nature

reusable. The same goes for new algorithms that operate on objects that implement these

interfaces.

Page 43: Collectn framework

Page 43 of 43 TalentSprint

Collection Framework

Summary

In this chapter, you have learnt about:

• Collections provide a well-defined set of interfaces and classes to store and manipulate

groups of data as a single unit. This unit is called a collection.

The List and Set interfaces extend from the Collection interface.

Features on which the Implementations of Collections Interfaces depend are

:Performance, Ordered/Sorted, Uniqueness of items,

Synchronized.

The iterator() method of the Collection interface returns an Iterator class

type.

While creating the Collections Framework, to keep the design simple, the

interfaces define all the methods an implementation class may provide.

The List interface extends the Collection interface to define an ordered

collection.

The Map interface starts off its own interface hierarchy, for maintaining key-

value associations.

To implement sorting, SortedSet and SortedMap are the two interfaces

provided by Collections Framework.

Situations where some of the original collections capabilities rather than the

new ones are to be used,

Collections like arrays, vectors, hashtables, enumerations, and other

historical capabilities are used.

Collections framework has been enhanced with the help of three new

language features:

Generics, Enhanced For Loop, Autoboxing/Unboxing

There are three new collection interfaces that are provided: Queue, locking Queue,

ConcurrentMap.

You will also learn about many other enhancements.

Benefits of Collections Framework:

1. Reduces Programming Effort

2. Increases Program Speed and Quality

3. Reduces Effort to Learn and to Use New APIs

4. Reduces Effort to Design New APIs

5. Fosters Software Reuse