HTML Markup | JavaScript | Java | Home & Links

Tutorial 7 - Collections, Exceptions, IO

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.

Standard IO (input/output) operations stream data from keyboard, files, programs or devices into the program and from there to the screen, printer, files, programs or other devices.

Collections and Mappings

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. its 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.

Note: Collection classes are contained in the java.util package.

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) // emp can be of several types
      {Staff s=(Staff) emp.get(x);} }  // cast it 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: A ClassCastException error is generated at run-time if objects are incompatible such as adding an incompatible object to a collection.

Note: All collection objects are unsynchronized. If threaded programming is used, place the collection in a synchronization wrapper.

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().

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. Mappings such as HashMap and TreeMap specify objects by using an ordered list (eg. <String,Float>).

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

Exceptions are objects that describe any error caused by an external resource not being available or an internal processing problem. 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. There are many exception classes such as IOException and NumberFormatException.

Note: Exception handling classes are contained in the java.lang package.

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. The finally keyword can be used to provide a block of code that is performed regardless of whether an exception is signaled or not. The syntax is:

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 java.io.xxxException 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).

Note: xxxException properties are found in the java.io library.

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 java.io.FileNotFoundException("Not found: beatles.txt");

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])); // uses 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!");
}

Standard IO Streams

Modern program design uses a stream metaphor for information flow. Streams of data flow from sources (inputs) through applications (programs) into sinks (outputs). Storage reservoirs (files) are used when needed. The standard input and output devices are the user console by default but can be redirected by the operating system to files, printers or other devices using the symbols <, > and |. Filters are applications that assume standard io streams.

System.in and System.out objects read and write from the standard stream. System.err always refers to the console (no redirection allowed). The method read() returns an integer that is ASCII of the input character. It can also throw an IOException exception error. The methods print(string), println(string) and printf(format, object_list) [using c-like syntax formatting] output to the system stream.

public void main (String args[]) throws java.io.IOException
{ int ch;
  System.out.println("Enter text: ");
  while (ch=System.in.read()!='\n') {
  System.out.println(ch); \\ shows it reads ASCII
  System.out.println((char)ch); }

There are alternate ways for user interaction. Refer to scanner class for stdio streams, file io for basic file management or file choosers for visual file interfaces using Swing objects.



JR's HomePage | Comments [jatutor7.htm:2014 09 23]