HTML Markup | JavaScript | Java | Home & Links

Tutorial 7 - Collections, Exceptions

The Java collections framework applies a unifying philosophy that adds operational functionality and dynamic growth to data structure object classes. Unification is accomplished through interfaces that each collection object inherits. Various types of objects may be handled in a similar manner within collection framework classes. Functionality such as searches, sorts, insertion and deletion use highly efficient algorithms.

Exception handling is a method of trapping or coping with anticipated errors (system, data entry or calculation) and handling or dealing with them in a graceful manner. The Exception class of objects offers a rich group of subclasses to trap specific errors and recover from them.

Collections and Mappings [java.util library]

The collection interfaces are dynamic data structures similar to arrays. The interfaces are Collection, List, Set, SortedSet and Queue. Collection is at the top of this hierarchy and includes the core methods add(obj), addAll(coll), clear(), contains(obj), containsAll(coll), equals(obj), hashCode(), isEmpty(), iterator(), remove(obj), removeAll(coll), retainAll(coll), size(), and toArray(). List extends Collection for classes that are a sequence of elements (similar to an array). It adds the methods get(idx), indexOf(), lastIndexOf(), set(idx) and subList(i1,i2) and overrides appropriate methods. Set extends Collection by overriding the add() method to prevent duplicate objects. SortedSet extends Set to keep all contained objects in a ordered manner. Methods include comparator(), first(), headSet(obj), last(), subSet(o1,o2) and tailSet(obj). Queue puts objects in a line pending processing.

Concrete collection classes implement the appropriate interfaces and incorporate optimized data structures. The collection classes include ArrayList, HashSet, LinkedList and TreeSet. ArrayList implements List and is similar to arrays but is dynamic (ie. size does not have to be declared at compile time). Additional methods in ArrayList include lastIndexOf(obj) to return the object's position, get(index) to return an object at a specific position, and toArray() to convert a collection back to a regular array. HashSet implements the Set interface and uses a hash table for efficient storage. LinkedList implements the appropriate data structure which can be traversed and nodes inserted and deleted. TreeSet implements the SortedSet interface using a binary tree for storage, allowing rapid access to list elements. An example of how specific list objects can be located for access by indexing is:

// Staff is a list object
for (int x=0; x<emp.size();x++) // by index number
    {if (emp.get(x) instanceof Staff) // can be of several types
      {Staff s=(Staff) emp.get(x);} } // cast to new Staff object

An example of walking through a collection with an iterator is:

Iterator it=c.iterator(); // set up iterator for the collection
while (it.hasNext()) {this.add((String)it.next());} // check then access

The mapping interfaces are Map and SortedMap. These are similar to 'associative arrays' in other languages. Map defines a table that is a one-to-one relationship between a key and an element. No duplicate keys are allowed. SortedMap maintains order within the mapping. HashMap and TreeMap are concrete mapping classes. TreeMap orders the mapping key while HashMap does not.

Note: All collection objects are unsynchronized. Place the collection in a synchronization wrapper when threaded programming is used.

Utilities and Algorithms

The utility interfaces include Comparator, Iterator and ListIterator. Their methods can be customized by overriding. Comparator defines how two objects are compared. It has two methods, compare(obj1,obj2) and equals(obj) Iterator and ListIterator enumerate objects within a list (similar to an array index). Iterator contains the methods next(), hasNext() and remove(). ListIterator has the additional methods of hasPrevious(), previous() and set().

Several algorithms are defined as static methods within the collections interface. They are binarySearch(), binarySort(), copy(), enumeration(), fill(), max(), min(), nCopies(), reverse(), reverseOrder(), shuffle(), singleton(), sort(), sychronizedCollection(), synchronizedList(), synchronizedMap(), synchronizedSet(), synchronizedSortedMap(), synchronizedSortedSet(), unmodifiableCollection(), unmodifiablelist(), unmodifiableMap(), unmodifiableset(), unmodifiableSortedMap() and unmodifiableSortedSet().

Note: Exceptions can be thrown such as ClassCastException (incompatible object types) and UnsupportedOperationException (an attempt was made to modify an unmodifiable collection).

Generic Type Parameters

Generics allow a type or method to operate on objects of various types while providing compile-time type safety. Objects can be type checked at compile time by using parameterized types to avoid casting errors at runtime.

LinkedList<Integer> myIntList=new LinkedList<Integer>();
myIntList.add(new Integer(0));
Integer x=myIntList.iterator().next();

The type declaration inside the angle bracket ensures checking at compile time. No casting is required! Types specified must be class types. Primitives must use their wrapper objects (eg. <String,Float>). Mappings such as HashMap and TreeMap specify objects by using an ordered list (eg. <ArrayList,LinkedList>).

Warning: Use wildcard typing <?> at your own peril!!!

Project: Convert Arrays to Lists

Static arrays are easily converted to dynamic lists. This can be appreciated when WordCount2 is converted into wcPlus allowing an unlimited number of unique words instead of a precompiled limit. A single list of word objects is used instead of parallel word and count arrays. Iterators are used instead of indexes when walking through the list.

Project: Concordance

A concordance produces an index of words and line numbers of occurrence within a document. This project uses the StringTokenizer class to provide the words/locations to be indexed and Java collections classes to add dynamic size (ArrayList) and sorting (TreeMap). The report should be in columns for readability. Both concordance.java (command line) and concord.java (GUI based) use file IO techniques. concord.java is also used as an example of how an application is deployed using Web Start.

Exception Handling [java.lang library]

Exceptions are objects that describe errors caused by unavailable external resources (such as missing files) or internal processing problems (such as illegal casts and array boundary issues). They are passed to exception handlers written by the programmer to enable graceful recovery. If the handler has not been written, the program terminates with a display of the exception class.

Java uses the try - catch - finally syntax to test (ie. try) a section of code and if an exception error occurs in that region, to trap (ie. catch) the error. Any number of catches can be set up for various exception types. finally can be used to provide a block of code that is performed regardless of whether an exception is signaled or not.

try
{
// tested statement(s);
}
catch(ExceptionName e1)
{
// trap handler statement(s);
}
catch(ExceptionName e2) // any number of catch statements
{
// display exception to screen
System.out.println("Exception: "+e2);
}
finally
{
// always executed block
}

The throws clause is used to pass a possible exception up the stack (processing chain). The Java compiler is aware of how some methods may cause specific exceptions and it forces one to deal with these immediately. If you choose not to write an exception handler then use the throws xxxException (where xxx is the appropriate exception) clause on the surrounding method to abdicate responsibility. For example System.in.read() gives a compile error for IOException. Add the throws clause to the surrounding method to pass the error up to the next level (or else write your own catch/try handler).

The throw keyword (note the singular form) is used to force an exception. It can also pass a custom message to the exception handling module. For example:

throw new FileNotFoundException("Not found: beatles.txt");

Exception classes are found in the java.io library. Examples are: CharConversionException, EOFException, FileNotFoundException, InterruptedIOException, InvalidClassException, InvalidObjectException, IOException, NotActiveException, NotSerializableException, ObjectStreamException, OptionalDataException, StreamInterruptedException, UnsupportedEncodingException and NumberFormatException.

Effective Exception Class Hierarchy

The exception classes are arranged in a hierarchy. Handlers (or catches) for specific exceptions should always be written prior to the generic handler. For example since FileNotFoundException is a child of IOException, a catch for FileNotFoundException should occur before the one for IOException. The latter handler catches those exceptions that are missed by individual child handlers. And a generic handler for Exception would cover any missing situation.

FileInputStream fis=null;  // declare in outer block
try
{
  fis=new FileInputStream(new File(args[0])); // use cmd line
  int ch;
  while (ch=fis.read()!=-1)
    {System.out.print((char) ch);}
  fis.close();
  System.out.println("");
}
catch (FileNotFoundException e)
{
  System.out.println("File not found!");
  try
    {fis.close();}
  catch(IOException ioe){} // disregard close failure
}
catch (IOException e)
{
  try
    {fis.close();}
  catch(IOException ioe){} // disregard close failure
  System.out.println("Unable to read file!");
}


JR's HomePage | Comments [jatutor7.htm:2016 01 17]