Interface, Javadoc, Error Handling and Java I/O


Interface

Within the Java programming language, an interface is a device that unrelated objects use to interact with each other. An interface is probably most analogous to a protocol (an agreed on behavior). In fact, other object-oriented languages have the functionality of interfaces, but they call their interfaces protocols.

You use an interface to define a protocol of behavior that can be implemented by any class anywhere in the class hierarchy. Interfaces are useful for the following:

  • Capturing similarities among unrelated classes without artificially forcing a class relationship.
  • Declaring methods that one or more classes are expected to implement.
  • Revealing an object's programming interface without revealing its class.

    A Java(TM) programming language keyword used to define a collection of method definitions and constant values. It can later be implemented by classes that define this interface with the implements keyword.

    To define an interface class

    public interface Comparable{
    	int compareTo(Object x);
    }
    
    Implementation
    public class Compare implements Comparable{
    
    	String word;
    
    	public Compare(String x){
    		word = x;
    	}
    	public int compareTo(Object x){
    		return word.compareTo((String) x)
    	}
    }
    
    


    Java Documentation

    Java documentation begins with the character sequence /**. it ends with */. Documentation comments allow you to embed information about your program into the program itself. You can then use the javadoc utility program to extract the information and put it into an HTML file. You have seen documentation generated with javadoc, because that is the way the Java API library was documented by Sun.

    Tag Meaning
    @author Identifies the author of a class
    @deprecated Specifies that a class or member is deprecated.
    {@docRoot} Specifies the path to the root directory of the current documentation (added by Java2, version 1.3)
    @exception Identifies an exception thrown by a method.
    @param Documents a method's parameter.
    @return Documents a method's return value.
    @see Specifies a link to another topic.
    @serial Documents a default serializable field.
    @serialData Documents an ObjectStreamField component.
    @since States the release when a specific change was introduced.
    @throws Same as @exception.
    @version Specifies the version of a class.

    Lets take a look at this java documentation program.

    import java.io.*;
    
    /**
     * This class demonstrates documentation comments.
     * @author Hervert Schildt
     * @version 1.2
     */
    
    public class SquareNum{
        /**
         * This method returns the square of num.
         * This is a multiline description. You can use
         * as many lines as you like.
         * @param num The value to be squared.
         * @return num squared.
         */
        public double square(double num){
            return num * num;
        }
    
        /**
         * This method inputs a number from the user.
         * @return The value input as a double.
         * @exception IOException On input error.
         * @see IOException
         */
        public double getNumber() throws IOException{
            //create a BufferedReader using System.in
            InputStreamReader isr = new InputStreamReader(System.in);
    
            BufferedReader inData = new BufferedReader(isr);
            String str;
            str = inData.readLine();
            return (new Double(str)).doubleValue();
        }
    
    
        /**
         * This method demonstrates square();
         * @param args Unused.
         * @return Nothing.
         * @exception IOException On inut error.
         * @see IOException
         */
        public static void main(String args[])
            throws IOException
        {
            SquareNum ob = new SquareNum();
            double val;
    
            System.out.println("Enter value to be squared: ");
    
            val = ob.getNumber();
            val = ob.square(val);
    
            System.out.println("Squared value is " + val);
    
        }
    }
    
    To get java doc of this code
    Unix> javac SquareNum.java                                            
                           
    Unix> java SquareNum                                                  
                           
    Enter value to be squared: 
    7
    Squared value is 49.0
    Unix> javadoc SquareNum.java                                          
                           
    Loading source file SquareNum.java...
    Constructing Javadoc information...
    Standard Doclet version 1.4.2_04
    Generating constant-values.html...
    Building tree for all the packages and classes...
    Building index for all the packages and classes...
    Generating overview-tree.html...
    Generating index-all.html...
    Generating deprecated-list.html...
    Building index for all classes...
    Generating allclasses-frame.html...
    Generating allclasses-noframe.html...
    Generating index.html...
    Generating packages.html...
    Generating SquareNum.html...
    Generating package-list...
    Generating help-doc.html...
    Generating stylesheet.css...
    Unix>
    
    
    If you want to know more about java doc,
    click here. Or you can refer to your Java2 complete reference book Appendix A.


    Exception Handling

    An exception is an object generated during program execution to describe an error or problem that has occurred. When a piece of code encounters such a problem, an exception is said to be thrown. Exceptions are handled with try, catch, and finally blocks according to the following syntax.
      .
      .
      try{
        .
        .                   //This block has the code you want to monitor
        .
      }
      catch(exception_type1 param){
        .
        .
      }
      catch(exception_type2 param){
        .
        .
      }
      .
      .
      finally{
        .                   //This block is optional
        .
      }
    
    The try block contains the code that might throw an exception. During program execution, if an exception is thrown within the try block, the JVM halts and exits the try block. The subsequent catch blocks are checked to see if they can handle the type of exception thrown. If an exception handler is found for the exception thrown, that catch block is executed. If no handler is found, the program returns to the calling method (if any) and searches there for a catch block to handle the exception thrown. Control will pass through any previous stack frames until the main() method is reached. If the exception is still not handled, the program exits.

    The finally block always executes (unless you call System.exit() which stops the virtual machine). It will execute when the try block is complete, or, if an exception is thrown, after all the catch blocks have been checked and before control returns to the calling method.

    Java actually has a class called Throwable with two subclasses: Error and Exception. The Error class represents problems within the virtual machine. This includes memory exhaustion, stack overflow, illegal access, and other serious problems. Error classes are generally not caught and result in program termination. The Exception class has subclasses that describe problems encountered during execution. These subclasses include ClassNotFoundException, NoSuchFieldException, NoSuchMethodException, and RuntimeException. The RuntimeException class has additional subclasses like ArithmeticException, ArrayIndexOutOfBoundsException, NullPointerException, and NumberFormatException.

    The Throwable class defines two useful methods that can be used to handle exceptions. These are getMessage(), which returns the string assigned to the Exception when it was created, and printStackTrace(), which prints out the program stack at the time the problem occurred.

    Lets take a look at some exception generating code.

    class InsultingDemo{
      public static void main(String args[]){
        int i = 1;
        int j = 0;
        try{
          System.out.println(i/j);         //Exception thrown here
          System.out.println("This line is never reached");
        }
        catch(NullPointerException e)
        {
          System.out.println("NullPointerException (that's a seg fault).");
        }
        catch(ArithmeticException e)       //Exception caught here
        {
          System.out.println("You can't divide by zero you idiot");
        }
      }
    }
    
    
    UNIX>java InsultingDemo
    You can't divide by zero you idiot
    UNIX>
    
    This should be pretty straight-forward. When we try to divide 1 by 0, the virtual machine throws an ArithmeticException. The first catch block is checked, but it handles a NullPointerException so the JVM skips over it. The second catch block is for the ArithmeticException, so that block executes. The following code does much the same thing, but demonstrates how the JVM returns control to the calling method to find an exception handler.
    class AnotherInsultingDemo{
      public static void main(String args[]){
        try
    	{
          a();
        }
        catch(ArrayIndexOutOfBoundsException e)
        {
          System.out.println("This won't get printed.");
        }
        catch(ArithmeticException e)
        {
          System.out.println("This example is pathetic, think of a better one.");
          System.out.println("You're still an idiot.");
          e.printStackTrace();
        }
      }
      
      public static void a(){
        try{
          b();
        }
        catch(NumberFormatException e){
          System.out.println("Can't help you");
        }
      }
    
      public static void b(){
        int i = 1;
        int j = 0;
        try{
    	  System.out.println(i/j);
    	}
        catch(NullPointerException e){
    	  System.out.println("Segmentation fault");
        }
      }
    }
    
    UNIX>java AnotherInsultingDemo
    This example is pathetic, think of a better one.
    You're still an idiot.
    java.lang.ArithmeticException: / by zero
            at AnotherInsultingDemo.b(AnotherInsultingDemo.java:32)
            at AnotherInsultingDemo.a(AnotherInsultingDemo.java:21)
            at AnotherInsultingDemo.main(AnotherInsultingDemo.java:5)
    UNIX>
    
    In this example, the exception is thrown in the b() method and caught in main(). Notice how the printStackTrace method lists the location of where the exception occurred. This can be very useful for debugging purposes. The JVM automatically prints a stack trace when there is an unhandled exception before the program exits.

    A catch block can also throw an exception, even the same type of exception that it caught. This allows an exception handler in a previous calling method to handle the same exception. This can be done with throw keyword. Note - the throw keyword can be used at any point in the code to throw an exception. Take a look at the following code.

    class IntentionalThrow{
      public static void main(String args[]){
        try{
          a();
        }
        catch(ArrayIndexOutOfBoundsException e){
          System.out.println("main: caught " + e);
        }
      }
      
      public static void a(){
        try{
          int array[] = new int[5];
          array[6] = 1;
        }
        catch(ArrayIndexOutOfBoundsException e){
          System.out.println("a(): caught " + e);
          System.out.println("Throwing...");
          throw e;
        }
      }
    }
    
    UNIX>java IntentionalThrow
    a(): caught java.lang.ArrayIndexOutOfBoundsException: 6
    Throwing...
    main: caught java.lang.ArrayIndexOutOfBoundsException: 6
    UNIX>
    
    If you create a method that can throw a certain type of exception, it is useful (but not required) to include a throws clause when the method is defined. For example, suppose we create a public, instance method called ReadFile that can potentially throw a couple of exceptions. We can define the method as follows
    public void ReadFile() throws NumberFormatException, IOException{...}

    Note - the compiler requires you to catch any subclass of Exception that a method can throw unless it is a subclass of RuntimeException. So if we used the ReadFile() method above, we would have to include a catch block for the IOException somewhere in the body of the code. If we didn't include such a block, the program would not compile. We would not have to have a catch block for the NumberFormatException since that is a subclass of RuntimeException (though we would probably want to). The compiler will also complain if you have a catch block for an exception type that cannot be generated within a try block (again with excluding RuntimeException subclasses). Think of all this as the compiler's way of reminding you to handle problems gracefully.

    Back to top

    Generic Exception Handling

    Since Exception is a super class of all exceptions, you can include a generic exception handler within a program without having to specify all the types of exceptions and giving a particular catch block to each one. Consider the following code
    import java.util.*;
    
    class InsultingGenericHandler{
      public static void main(String args[]){
        try{
          Random gen = new Random();
          int i = random.nextInt();
          if(i % 2 == 0)
            System.out.println(1/0);                 //Arithmetic Exception
          else
            throw new NullPointerException();        //Null pointer exception
        }
        catch(Exception e){                          //Generic Exception Handler
          System.out.println("Caught exception " + e);
          System.out.println("Can't you do anything right.");
        }
      }
    }
    
    UNIX>java InsultingGenericHandler
    Caught exception java.lang.NullPointerException
    Can't you do anything right.
    UNIX>!j
    Caught exception java.lang.ArithmeticException: / by zero
    Can't you do anything right.
    UNIX>
    
    As you can see, this code generates one of two random exceptions, both of which are caught by our generic exception handler. Keep in mind that if you include a generic exception handler, you want it to be in the last catch block of the code. If it isn't, then it will catch the exception before any other catch block is searched. So if you have some specific exceptions you want to catch, put them in catch blocks before the generic catch block.

    Back to top

    Customized Exceptions

    You can create your own exception classes so that particular problems within your code can be handled. This is done by simply extending the Exception class with your own subclass and using the throw statement to throw the exception.

    Java I/O

    So far, we've managed to keep all our programs from relying on reading input from anything other than the command-line. Unfortunately, most programs rely on more than this to be useful. When using any kind of I/O, you must use the statement import java.io.*; at the beginning of the source file. This tells the compiler to include the classes Java uses for input and output (much like #include <stdio.h> in C).

    The I/O classes we will be using are stream-based. A stream is an abstraction that can refer to the any source or destination of data. This abstraction allows us to use the same methods and techniques regardless of the physical device at the other end of the stream (be it a disk, keyboard, screen, file, etc). In Java, the two fundamental types of streams are byte streams and character streams. Byte streams allow you to read or write binary data, while character streams read and write characters and strings. For the remainder of our discussion, we will focus on character streams. The fundamental classes for I/O are Writer and Reader. These are abstract classes that define methods that are actually implemented by subclasses. Note - nearly all the classes and methods within the I/O package can throw an IOException, and those involving files can throw a FileNotFoundException. It's probably a good idea to handle these exceptions if you want your program to exit gracefully.

    Writer and its Subclasses

    Writer defines the basic behavior of all character output streams. One important subclass of Writer is OutputStreamWriter which converts a stream of characters to a stream of bytes according to a specific encoding. The character encoding used is the default for the user's machine unless otherwise specified within the constructor. The standard constructor simply takes an OutputStream object as its argument. The more specific FileWriter class extends OutputStreamWriter and outputs characters to a file. The FileWriter class has three constructors.
            FileWriter(String filepath)
            FileWriter(String filepath, boolean append)
            FileWriter(File fileobject)
    
    The first takes a filename as its argument and will overwrite the contents of the file. The second also takes a filename, but if append is true, the output is added to the end of the file rather than overwriting the file. The third constructor takes an instance of a File object. Both OutputStreamWriter and FileWriter have the following methods inherited from Writer.

    void close() Closes the output stream.
    void write(int ch) Writes the lower 16 bits of ch.
    void write(String s) Writes s to the stream.
    void write(char buf[]) Writes the character contents of buf to the stream.

    The following code takes the name of an output file on the command line and writes ten lines to that file.

    import java.io.*;
                    
    class FileWriterDemo{
      public static void main(String args[]){
        try{ 
          FileWriter out = new FileWriter(args[0]);
       
          for(int i = 0; i < 10; i++){
            out.write("This is line " + i + "\n");
          }
          out.close();
        }           
        catch(Exception e){
          System.out.println("Caught exception: " + e);
        }    
      }
    }  
          
            
    UNIX>java FileWriterDemo output.txt
    UNIX>more output.txt
    This is line 0  
    This is line 1
    This is line 2
    This is line 3
    This is line 4
    This is line 5
    This is line 6
    This is line 7
    This is line 8
    This is line 9
    UNIX>
    

    Reader and its Subclasses

    The Reader class defines the functionality of all character input streams. An important subclass of Reader is InputStreamReader which converts a stream of bytes to a stream of characters. The InputStreamReader constructor takes an input stream (such as System.in) as its argument. InputStreamReader has a subclass called FileReader that reads a character stream from a file. It has two constructors, one that takes the filename of the file to be read as a string, and the other takes an instance of a File object. InputStreamReader and FileReader have the following methods inherited from Reader.

    void close() Closes the input stream.
    int read() Reads one character from the input stream. Blocks until data is available.
    int read(char buf[]) Tries to read up to buf.length characters into buf and returns the number of characters that were read. Blocks until data is available.

    The following code takes the name of a file to read as an argument on the command line and prints each character to the screen.

    import java.io.*;
    
    class JavaCat{
      public static void main(String args[]){
        try{ 
          FileReader in = new FileReader(args[0]);
       
          int ch;
          while((ch = in.read()) != -1){
           System.out.print((char) ch);
          }
          in.close();
        }
        catch(FileNotFoundException e){
          System.out.println(args[0] + ": No such file - maybe you deleted it.");
        }
        catch(Exception e){
          System.out.println("Caught Exception: " + e);
        }
      }
    }
    
         
    UNIX>java JavaCat output.txt
    This is line 0
    This is line 1
    This is line 2
    This is line 3
    This is line 4
    This is line 5
    This is line 6
    This is line 7
    This is line 8
    This is line 9
    UNIX>
    
    For the purposes of illustration, the input to our JavaCat program in the preceding example was the output file from the FileWriterDemo above.


    Buffered I/O Streams

    The OutputStreamWriter and InputStreamReader classes work for I/O, but the methods they use are analogous to the C read and write system calls. The basic read and write methods used by the Java language only act on one character at a time. This can be inefficient and we'd like a better way to perform I/O without reading or writing one character at a time. This is done with the BufferedWriter and BufferedReader classes. These classes perform reads and writes in large chunks and store the characters in a buffer to increase efficiency.

    BufferedWriter extends the Writer class. It implements the same methods the other Writer subclasses use and buffers output to a character stream. BufferedWriter also has a newLine() method that inserts a line separator. Buffered Writer uses the following constructors

            BufferedWriter(Writer out)
            BufferedWriter(Writer out, int bufsize)   
    
    The first creates a buffered stream that writes to the out Writer object. The second allows you to specify the size of the buffer with the bufsize argument. The following code demonstrates how we can rewrite the FileWriterDemo from the previous section using the BufferedWriter class.
    import java.io.*;
    
    class BetterWriterDemo{
      public static void main(String args[]){
        try{
          FileWriter f = new FileWriter(args[0]);
    
          BufferedWriter out = new BufferedWriter(f);
    
          for(int i = 0; i < 10; i ++){
            out.write("This is line " + i);
            out.newLine();
          }
          out.close();
        }   
        catch(Exception e){
          System.out.println("Caught Exception: " + e);
        }
      }
    }
            
    
    UNIX>java BetterWriterDemo output.txt
    UNIX>more output.txt
    This is line 0
    This is line 1
    This is line 2
    This is line 3
    This is line 4
    This is line 5
    This is line 6
    This is line 7
    This is line 8
    This is line 9
    UNIX>
    

    BufferedReader extends the Reader class and so implements the same methods defined by that superclass. It also has a readLine() method that reads newline-terminated strings from the character stream. This useful method returns a String object that you can parse into whatever substrings you need. The readLine() method discards the newline character at the end of the string. The BufferedReader class has the following constructors:

            BufferedReader(Reader in)
            BufferedReader(Reader in, int bufsize)
    
    The first creates a buffered stream the reads from the in object to a buffer with a default size. The second does the same, but allows you to specify the size of the buffer with the bufsize argument. The following code demonstrates the use of the BufferedReader class. It takes the name of a file on the command line and prints out every line of the file backward.
    import java.io.*;
            
    class BackwardCat{
      public static void main(String args[]){
        try{
          FileReader fr = new FileReader(args[0]);
    
          BufferedReader in = new BufferedReader(fr);
    
          String s;
          while((s = in.readLine()) != null){
            StringBuffer rev = new StringBuffer(s);
            System.out.println(rev.reverse());
      
            rev = null;               //Assign null so the garbage collector knows to reclaim
          }
          fr.close();
        }
        catch(Exception e){
          System.out.println("Caught Exception: " + e);
        }
      }
    } 
            
    
    UNIX>java BackwardCat output.txt
    0 enil si sihT   
    1 enil si sihT
    2 enil si sihT
    3 enil si sihT
    4 enil si sihT
    5 enil si sihT
    6 enil si sihT
    7 enil si sihT
    8 enil si sihT
    9 enil si sihT
    UNIX>
    
    The last example reads from standard input (i.e. the keyboard) using a buffered character stream. It uses the readLine() method, so every string must be newline terminated. The program executes an infinite loop to read in strings and displays the string followed by the number of characters the string contains.
    import java.io.*;
    
    class ConsoleReflect{
      public static void main(String args[]){
        try{
          InputStreamReader is = new InputStreamReader(System.in);
    
          BufferedReader in = new BufferedReader(is);
    
          String s;
          while((s = in.readLine()) != null){
            System.out.println(s + "  (" + s.length() + ")\n");
          }
          is.close();
        }   
        catch(Exception e){
          System.out.println("Caught Exception: " + e);
        }
      }
    }
          
    UNIX>java ConsoleReflect
    Hello, world
    Hello, world  (12)
            
    This is a test
    This is a test  (14)
         
    3241
    3241  (4)
          
    992.671
    992.671  (7)
    
    That's it, I'm done.
    That's it, I'm done.  (20)
    
    UNIX>
    

    String Tokenizer

    The string tokenizer class allows an application to break a string into tokens. The tokenization method is much simpler than the one used by the StreamTokenizer class. The StringTokenizer methods do not distinguish among identifiers, numbers, and quoted strings, nor do they recognize and skip comments.

    The set of delimiters (the characters that separate tokens) may be specified either at creation time or on a per-token basis.

    An instance of StringTokenizer behaves in one of two ways, depending on whether it was created with the returnDelims flag having the value true or false:

    If the flag is false, delimiter characters serve to separate tokens. A token is a maximal sequence of consecutive characters that are not delimiters. If the flag is true, delimiter characters are themselves considered to be tokens. A token is thus either one delimiter character, or a maximal sequence of consecutive characters that are not delimiters. A StringTokenizer object internally maintains a current position within the string to be tokenized. Some operations advance this current position past the characters processed.

    A token is returned by taking a substring of the string that was used to create the StringTokenizer object.

    The following is one example of the use of the tokenizer. The code:

    
         StringTokenizer st = new StringTokenizer("this is a test");
         while (st.hasMoreTokens()) {
             System.out.println(st.nextToken());
         }
    
    
    prints the following output:
         this
         is
         a
         test
    
    StringTokenizer is a legacy class that is retained for compatibility reasons although its use is discouraged in new code. It is recommended that anyone seeking this functionality use the split method of String or the java.util.regex package instead. The following example illustrates how the String.split method can be used to break up a string into its basic tokens:
         String[] result = "this is a test".split("\\s");
         for (int x=0; x < result.length; x++)
             System.out.println(result[x]);
    
    
    prints the following output:
         this
         is
         a
         test
    

    Exercises

    When is this lab due?

    The problem below is due on Monday at 11:59pm, Feb. 14.

    Grading Guidelines for Lab3:

    (Please refer to
    General Guidelines for general grading guidelines)

    1. Word processor total points: 100pts
    2. Error Checking: 10pts
    3. Correct output: 60pts
    4. Correct structure: 20pts
    5. Exception handling: 10pts

    Some Exceptions you might need to handle....

    ItemNotFound
    FileNotFoundException
    IOException


    Programming problem to be submitted:

    For this programming assignment you are to write a Java application which will interactively read a text file and report the number of different words in it, the word which occurs most often, and the most frequent beginning character in the file. The result of the file's analysis will then be displayed on the screen.

    You need to read each word and beginning char into two separate double link lists. I will provide the interface of this double link list. You need to implement all the methods in this interface.

    public interface listIterator{
        //if there is anything is in the list
        boolean isInList();
    
        /* advance()
         * moves current to the next node of the list
         */
        void advance();
    
        /* backup()
         * moves current to the previous node of the list
         */
        void backup();
    
        /* retrieve()
         * returns the data of the current ListNode.
         * throws ItemNotFound if the current listnode is NOT
         * a data-bearing node.
         */
        Object retrieve() throws ItemNotFound;
    
        /* zeroth()
         * moves current to the list's header node
         */
        void zeroth();
    
        /* first()
         * positions current on the first data-bearing node of
         * the list.
         * Throws ItemNotFound if there is no such node.
         */
        void first() throws ItemNotFound;
    
        /* find(Object x)
         * uses the ListNode's data element's isEqual() to locate
         * the list node containing the element corresponding to x
         */
        void find(Object x) throws ItemNotFound;
    
        /* removeCurrent()
         * removes the current node in the list
         * throws ItemNotFound if the current node is not in the
         * list.
         * positions current at the header node.
         */
        void removeCurrent() throws ItemNotFound;
    
        /* remove(Object x)
         * locates and removes the item.
         */
        void remove(Object x) throws ItemNotFound;
    
        /* insert(Object x)
         * inserts the new data AFTER the current node.
         */
        void insert(Object x);
    }
    
    

    At a minimum, you must define the following classes:

  • ItemNotFound.java This class is a subclass of Exception class.
  • listItr.java This class implements the listIterator interface.
  • A main class.
    Example run of WordProcessor:
    	UNIX> cat f1 
    	this is f1
    	is is the most frequent word.
    	and i is the most frequent beginning char.
    	Let's see if it is true. 
    	UNIX> java WordProcessor                            
    	Please enter a file name: f1
    
    	+----------------Word Processor--------------+
    	Number of words in the file     : 24
    	Most frequent word in the file  : is 5
    	Most frequent beginning char    : i 8
    


    Created by Ben Pack & Justin Giles 2001. Modified by Yuan Li 2005