Second Summer 2002


Lecture Notes Thirty: Exceptions and basic I/O (including serialized objects)
So far we know how to generate data for the user, graphically or textually. We are also able to get input from the user from the command line, as a sequence of Strings, or from the mouse in a graphical, or a graphical user interface, context.

Now we want to be able to read text from a file, and from the terminal, and also to write text to a file.

If you want to be able to make phone calls you need to buy a telephone and use it according to the manufacturer's instructions. Same thing with I/O in Java: we just need to know what type of objects we need to work with (and how) in order to read from or write to a file, and read from the terminal.

Purpose Input Output
Connection java.io.FileInputStream java.io.FileOutputStream
Text Files java.io.InputStreamReader
java.io.BufferedReader
java.io.StreamTokenizer
java.io.PrintWriter
Data Files java.io.DataInputStream java.io.DataOutputStream
Object Files java.io.ObjectInputStream java.io.ObjectOutputStream

The URLs are:

http://java.sun.com/j2se/1.4/docs/api/java/io/FileInputStream.html
http://java.sun.com/j2se/1.4/docs/api/java/io/FileOutputStream.html
http://java.sun.com/j2se/1.4/docs/api/java/io/InputStreamReader.html
http://java.sun.com/j2se/1.4/docs/api/java/io/BufferedReader.html
http://java.sun.com/j2se/1.4/docs/api/java/io/StreamTokenizer.html
http://java.sun.com/j2se/1.4/docs/api/java/io/PrintWriter.html
http://java.sun.com/j2se/1.4/docs/api/java/io/DataInputStream.html
http://java.sun.com/j2se/1.4/docs/api/java/io/DataOutputStream.html
http://java.sun.com/j2se/1.4/docs/api/java/io/ObjectInputStream.html
http://java.sun.com/j2se/1.4/docs/api/java/io/ObjectOutputStream.html

Let's try to learn how to use these classes one by one.

  1. FileInputStream

  2. InputStreamReader

  3. BufferedReader

  4. StreamTokenizer

  5. System.out

  6. System.in

  7. FileOutputStream

  8. PrintWriter

Once we have these things under control, we can look at Here are the programs, step by step.

1. FileInputStream

Find the documentation for it here.

http://java.sun.com/j2se/1.4/docs/api/java/io/FileInputStream.html
oldschool.cs.indiana.edu%vi Example.java
oldschool.cs.indiana.edu%vi file
oldschool.cs.indiana.edu%ls -l
total 2
-rw-------   1 dgerman       289 Jul 19 12:49 Example.java
-rw-------   1 dgerman        59 Jul 19 12:45 file
oldschool.cs.indiana.edu%cat file
This is a sample
file that has three
lines of text in it. 
oldschool.cs.indiana.edu%cat Example.java
import java.io.*;
 
class Example {
  public static void main(String[] args) {
    try {
      FileInputStream stream = new FileInputStream(args[0]); 
    
      stream.close(); 
    } catch (Exception e) {
      System.out.println("Something went wrong: " + e.toString()); 
    } 
  } 
} 
oldschool.cs.indiana.edu%javac Example.java
oldschool.cs.indiana.edu%ls -l
total 3
-rw-------   1 dgerman       793 Jul 19 12:50 Example.class
-rw-------   1 dgerman       289 Jul 19 12:50 Example.java
-rw-------   1 dgerman        59 Jul 19 12:50 file
oldschool.cs.indiana.edu%java Example file
oldschool.cs.indiana.edu%java Example A.java
Something went wrong: java.io.FileNotFoundException: A.java
oldschool.cs.indiana.edu%java Example
Something went wrong: java.lang.ArrayIndexOutOfBoundsException: 0
oldschool.cs.indiana.edu%
Here's a different version, can you see what's different?
import java.io.*;

class Example {
  public static void main(String[] args) throws Exception {
    FileInputStream stream = new FileInputStream(args[0]); 	
    stream.close(); 	
  } 
} 
So now you know how you can get a connection, and what happens if you're asking for an inconsistent or incorrect kind of connection. Let's now read the character one by one and put parens around them when we print them back to the user to see if we can get inside the contents of the file.

2. InputStreamReader

Find documentation for this kind of objects here.

http://java.sun.com/j2se/1.4/docs/api/java/io/InputStreamReader.html
oldschool.cs.indiana.edu%vi Example.java
oldschool.cs.indiana.edu%cat Example.java
import java.io.*;
 
class Example {
  public static void main(String[] args) {
    try {
      FileInputStream stream = new FileInputStream(args[0]); 
      InputStreamReader reader = new InputStreamReader(stream);
      int data = reader.read(); 
      while (data != -1) {
        System.out.print("(" + data + ")"); 
        data = reader.read(); 
      }     
      stream.close(); 
    } catch (Exception e) {
      System.out.println("Something went wrong: " + e.toString()); 
    } 
  } 
} 
oldschool.cs.indiana.edu%javac Example.java
oldschool.cs.indiana.edu%java Example file
(84)(104)(105)(115)(32)(105)(115)(32)(97)(32)(115)(97)(109)(112)(108)(101)(10\
)(102)(105)(108)(101)(32)(116)(104)(97)(116)(32)(104)(97)(115)(32)(116)(104)(\
114)(101)(101)(10)(108)(105)(110)(101)(115)(32)(111)(102)(32)(116)(101)(120)(\
116)(32)(105)(110)(32)(105)(116)(46)(32)(10)
oldschool.cs.indiana.edu%vi Example.java
oldschool.cs.indiana.edu%cat Example.java
import java.io.*;
 
class Example {
  public static void main(String[] args) {
    try {
      FileInputStream stream = new FileInputStream(args[0]); 
      InputStreamReader reader = new InputStreamReader(stream);
      int data = reader.read(); 
      while (data != -1) {
        System.out.print("(" + (char)data + ")"); 
        data = reader.read(); 
      }     
      stream.close(); 
    } catch (Exception e) {
      System.out.println("Something went wrong: " + e.toString()); 
    } 
  } 
} 
oldschool.cs.indiana.edu%javac Example.java
oldschool.cs.indiana.edu%java Example file
(T)(h)(i)(s)( )(i)(s)( )(a)( )(s)(a)(m)(p)(l)(e)(
)(f)(i)(l)(e)( )(t)(h)(a)(t)( )(h)(a)(s)( )(t)(h)(r)(e)(e)(
)(l)(i)(n)(e)(s)( )(o)(f)( )(t)(e)(x)(t)( )(i)(n)( )(i)(t)(.)( )(
)oldschool.cs.indiana.edu%
So you see how you can get to the characters, by first getting their integer codes and then converting them into char data. Now let's see how we can get a whole line of characters at a time.

3. BufferedReader

Find documentation about this kind of objects here.

http://java.sun.com/j2se/1.4/docs/api/java/io/BufferedReader.html
oldschool.cs.indiana.edu%ls -l
total 2
-rw-------   1 dgerman       408 Jul 19 13:12 Example.java
-rw-------   1 dgerman        59 Jul 19 12:50 file
oldschool.cs.indiana.edu%vi Example.java
oldschool.cs.indiana.edu%cat Example.java
import java.io.*;
 
class Example {
  public static void main(String[] args) {
    try {
      FileInputStream stream = new FileInputStream(args[0]); 
      InputStreamReader reader = new InputStreamReader(stream);
      BufferedReader b = new BufferedReader(reader); 
      String line = b.readLine();
      while (line != null) {
        System.out.println("(" + line + ")"); 
        line = b.readLine(); 
      }      
      stream.close(); 
    } catch (Exception e) {
      System.out.println("Something went wrong: " + e.toString()); 
    } 
  } 
} 
oldschool.cs.indiana.edu%javac Example.java
oldschool.cs.indiana.edu%java Example file
(This is a sample)
(file that has three)
(lines of text in it. )
oldschool.cs.indiana.edu%
This was easy and you knew all about it already.

4. StreamTokenizer

Find documentation about these kind of objects here.

http://java.sun.com/j2se/1.4/docs/api/java/io/StreamTokenizer.html
oldschool.cs.indiana.edu%vi Example.java
oldschool.cs.indiana.edu%ls -l
total 2
-rw-------   1 dgerman       763 Jul 19 13:33 Example.java
-rw-------   1 dgerman        59 Jul 19 12:50 file
oldschool.cs.indiana.edu%cat Example.java
import java.io.*;
 
class Example {
  public static void main(String[] args) {
    try {
      FileInputStream stream = new FileInputStream(args[0]); 
      InputStreamReader reader = new InputStreamReader(stream);
      BufferedReader b = new BufferedReader(reader); 
      StreamTokenizer s = new StreamTokenizer(b); 
      s.nextToken(); 
      while (s.ttype != StreamTokenizer.TT_EOF) { 
        if (s.ttype == StreamTokenizer.TT_WORD)
          System.out.println("(" + s.sval + ")"); 
        else if (s.ttype == StreamTokenizer.TT_NUMBER) 
          System.out.println("(" + s.nval + ")");
        s.nextToken(); 
      }  
      stream.close(); 
    } catch (Exception e) {
      System.out.println("Something went wrong: " + e.toString()); 
    } 
  } 
} 
oldschool.cs.indiana.edu%javac Example.java
oldschool.cs.indiana.edu%java Example file
(This)
(is)
(a)
(sample)
(file)
(that)
(has)
(three)
(lines)
(of)
(text)
(in)
(it.)
oldschool.cs.indiana.edu%
EXERCISE 5. System.out

You can read about this kind of objects here. You have used this kind of objects a lot.

http://java.sun.com/j2se/1.4/docs/api/java/lang.System.html
6. System.in

You can read about this kind of objects here.

http://java.sun.com/j2se/1.4/docs/api/java/lang.System.html
oldschool.cs.indiana.edu%vi Example.java
oldschool.cs.indiana.edu%cat Example.java
import java.io.*;
 
class Example {
  public static void main(String[] args) {
    try {
      InputStreamReader reader = new InputStreamReader(System.in);
      BufferedReader b = new BufferedReader(reader); 
      System.out.println("Welcome to the Echo program!"); 
      System.out.print("Type: "); 
      String line = b.readLine(); 
      while (! line.equals("quit")) { 
        System.out.println("You typed: " + line);      
        System.out.print("Type: "); line = b.readLine(); 
      }
    } catch (Exception e) {
      System.out.println("Something went wrong: " + e.toString()); 
    } finally { 
      System.out.println("Good-bye."); 
    } 
  } 
} 
oldschool.cs.indiana.edu%javac Example.java
oldschool.cs.indiana.edu%java Example
Welcome to the Echo program!
Type: Test
You typed: Test
Type: Hello!
You typed: Hello!
Type: I am talking to you.
You typed: I am talking to you.
Type: Hi there.
You typed: Hi there.
Type: quit
Good-bye.
oldschool.cs.indiana.edu%
6. FileOutputStream

You can read the documentation about this kind of objects here.

http://java.sun.com/j2se/1.4/docs/api/java/io/FileOutputStream.html
oldschool.cs.indiana.edu%ls -l
total 2
-rw-------   1 dgerman       667 Jul 19 13:51 Example.java
-rw-------   1 dgerman        59 Jul 19 12:50 file
oldschool.cs.indiana.edu%vi Example.java
oldschool.cs.indiana.edu%pico Example.java
oldschool.cs.indiana.edu%vi Example.java
oldschool.cs.indiana.edu%ls -l
total 2
-rw-------   1 dgerman       350 Jul 19 14:00 Example.java
-rw-------   1 dgerman        59 Jul 19 12:50 file
oldschool.cs.indiana.edu%cat Example.java
import java.io.*;
 
class Example {
  public static void main(String[] args) {
    try {
      FileOutputStream stream = new FileOutputStream(args[0]); 
      
      stream.close(); 
    } catch (Exception e) {
      System.out.println("Something went wrong: " + e.toString()); 
    } finally { 
      System.out.println("Good-bye."); 
    } 
  } 
} 
oldschool.cs.indiana.edu%javac Example.java
oldschool.cs.indiana.edu%java Example
Something went wrong: java.lang.ArrayIndexOutOfBoundsException: 0
Good-bye.
oldschool.cs.indiana.edu%java Example file.out
Good-bye.
oldschool.cs.indiana.edu%ls -l
total 3
-rw-------   1 dgerman       850 Jul 19 14:00 Example.class
-rw-------   1 dgerman       350 Jul 19 14:00 Example.java
-rw-------   1 dgerman        59 Jul 19 12:50 file
-rw-------   1 dgerman         0 Jul 19 14:01 file.out
oldschool.cs.indiana.edu%
7. PrintWriter

Read the documentation about this kind of objects here.

http://java.sun.com/j2se/1.4/docs/api/java/io/PrintWriter.html
oldschool.cs.indiana.eduls -l
total 2
-rw-------   1 dgerman       701 Jul 19 14:09 Example.java
-rw-------   1 dgerman        59 Jul 19 12:50 file
oldschool.cs.indiana.edu%vi Example.java
oldschool.cs.indiana.edu%cat Example.java
import java.io.*;
 
class Example {
  public static void main(String[] args) {
    try {
      FileOutputStream stream = new FileOutputStream(args[0]); 
      PrintWriter p = new PrintWriter(stream, true);
      BufferedReader b = new BufferedReader(new InputStreamReader(System.in));
      System.out.print("Hello, please type: "); String line = b.readLine(); 
      while (! line.equals("quit")) {
        p.println(line); 
        System.out.print("Thanks, please go on: "); line = b.readLine();  
      }  
      stream.close(); 
    } catch (Exception e) {
      System.out.println("Something went wrong: " + e.toString()); 
    } finally { 
      System.out.println("Good-bye."); 
    } 
  } 
} 
oldschool.cs.indiana.edu%javac Example.java
oldschool.cs.indiana.edu%java Example file.out
Hello, please type: I am typing lines that   
Thanks, please go on: my program should write
Thanks, please go on: to the file that I have
Thanks, please go on: indicated on the command
Thanks, please go on: line, that is: file.out
Thanks, please go on: quit
Good-bye.
oldschool.cs.indiana.edu%ls -l
total 5
-rw-------   1 dgerman      1362 Jul 19 14:09 Example.class
-rw-------   1 dgerman       701 Jul 19 14:09 Example.java
-rw-------   1 dgerman        59 Jul 19 12:50 file
-rw-------   1 dgerman       120 Jul 19 14:10 file.out
oldschool.cs.indiana.edu%cat file.out
I am typing lines that
my program should write
to the file that I have
indicated on the command
line, that is: file.out
oldschool.cs.indiana.edu
That's basically it, as far as text goes.

We don't know it yet, but we have almost everything worked out.

Here now is a worm program. It keeps track of how many times it has been called and when. It then saves itself in a file. The blue code is the added level of complexity in the structure of the worm.

Note that the I/O is the same, regardless of the complexity of Worm objects (the blue code adds an instance variable of type Vector to their definition, but the I/O part does not care). This is not an example of a self-referential object. Its actual purpose is to point out the significant advantages that object serialization has to offer. You see how easy it is to write and read whole objects.

frilled.cs.indiana.edu%cat Worm.java
import java.util.*; 
import java.io.*; 
class Worm implements Serializable {
    int calls; Vector v = new Vector();  
    public static void main(String[] args) {
	Worm w; 
	try {
	    FileInputStream fis = new FileInputStream("Worm"); 
	    ObjectInputStream ois = new ObjectInputStream(fis); 
	    w = (Worm)ois.readObject(); 
	    ois.close();  
	} catch (Exception e) {
	    w = new Worm(); 
	} 
	System.out.println(
			   "I have been called " + w.calls + " times."
			   ); 
	w.calls += 1; 
	w.v.addElement(new Date()); 
	for (int i = 0; i < w.v.size(); i++) 
	    System.out.println(
			       "***(" + w.v.elementAt(i).toString() + ")***"
			       );  
	try {
	    FileOutputStream fos = new FileOutputStream("Worm"); 
	    ObjectOutputStream oos = new ObjectOutputStream(fos); 
	    oos.writeObject(w); 
	    oos.close(); 
	} catch (Exception e) {
	    System.out.println("Something went wrong when writing."); 
	} 
    }  
} 
frilled.cs.indiana.edu%javac Worm.java
frilled.cs.indiana.edu%java Worm
I have been called 0 times.
***(Wed Jul 31 02:30:11 EST 2002)***
frilled.cs.indiana.edu%ls -ld Worm*
-rw-------   1 dgerman       265 Jul 31 02:30 Worm
-rw-------   1 dgerman      1586 Jul 31 02:30 Worm.class
-rw-------   1 dgerman       938 Jul 31 02:29 Worm.java
frilled.cs.indiana.edu%java Worm
I have been called 1 times.
***(Wed Jul 31 02:30:11 EST 2002)***
***(Wed Jul 31 02:30:36 EST 2002)***
frilled.cs.indiana.edu%java Worm
I have been called 2 times.
***(Wed Jul 31 02:30:11 EST 2002)***
***(Wed Jul 31 02:30:36 EST 2002)***
***(Wed Jul 31 02:30:42 EST 2002)***
frilled.cs.indiana.edu%
So the code is here:
import java.util.*; 
import java.io.*; 
class Worm implements Serializable {
  int calls; Vector v = new Vector();  
  public static void main(String[] args) {
    Worm w; 
    try {
      FileInputStream fis = new FileInputStream("Worm"); 
      ObjectInputStream ois = new ObjectInputStream(fis); 
      w = (Worm)ois.readObject(); 
      ois.close();  
    } catch (Exception e) {
      w = new Worm(); 
    } 
    System.out.println(
      "I have been called " + w.calls + " times."
    ); 
    w.calls += 1; 
    w.v.addElement(new Date()); 
    for (int i = 0; i < w.v.size(); i++) 
      System.out.println(
        "***(" + w.v.elementAt(i).toString() + ")***"
      );  
    try {
      FileOutputStream fos = new FileOutputStream("Worm"); 
      ObjectOutputStream oos = new ObjectOutputStream(fos); 
      oos.writeObject(w); 
      oos.close(); 
    } catch (Exception e) {
      System.out.println("Something went wrong when writing."); 
    } 
  }  
} 
We now need to talk about Exceptions. (In fact, we should have started with exceptions, then move to file input, which is a likely source of Exceptions).

Exceptions provide

Exceptions make the error conditions that a method can signal an explicit part of the method's contract. The list of exceptions can be seen by the programmer, checked by the compiler, and preserved by extended classes that override the method.

Exceptions in Java are objects. All exception types must extend the Java language class Throwable or one of its subclasses. (By convention, new exception types extend Exception rather than Throwable). All exceptions you create should extend Exception, making them checked exceptions.

Java exceptions are primarily

Standard runtime exceptions and errors extend the classes RuntimeException and Error, thereby creating Here's what happens when we divide by zero:
tucotuco.cs.indiana.edu% vi One.java

tucotuco.cs.indiana.edu% cat One.java
class One { public static void main(String[] args) { One one = new One(); one.run(); } void run() { int a = 10, b = 0, c; c = a / b; // oops! System.out.println(a + " / " + b + " = " + c); } }
tucotuco.cs.indiana.edu% javac One.java
tucotuco.cs.indiana.edu% java One
java.lang.ArithmeticException: / by zero at One.run(Compiled Code) at One.main(Compiled Code)
tucotuco.cs.indiana.edu%
Here's what's being thrown:
java.lang.Object
   |
   +----java.lang.Throwable
           |
           +----java.lang.Exception
                   |
                   +----java.lang.RuntimeException
                           |
                           +----java.lang.ArithmeticException
(I am sure you can look this up by now).

Here's a longer and session in which we create and throw our own BadArgumentException:

tucotuco.cs.indiana.edu% vi Two.java

tucotuco.cs.indiana.edu% cat Two.java
class Two { public static void main(String[] args) { System.out.println("The main method started..."); Two two = new Two(); for (int i = -3; i <= 3; i++) { try { int result = two.factorial(i); System.out.println(" Factorial of " + i + " is: " + result); } catch (BadArgumentException e) { System.out.println(" Factorial was called with negative input: " + e.toString()); } } System.out.println("... main method ends."); } int factorial(int n) throws BadArgumentException { if (n < 0) throw new BadArgumentException(n); if (n == 0) return 1; return n * factorial(n - 1); } } class BadArgumentException extends Exception { int arg; BadArgumentException (int arg) { this.arg = arg; } public String toString() { return " " + arg; } }
tucotuco.cs.indiana.edu% ls -l
total 4 -rw-r--r-- 1 dgerman students 220 Mar 20 19:20 One.java -rw-r--r-- 1 dgerman students 848 Mar 20 20:05 Two.java
tucotuco.cs.indiana.edu% javac Two.java
tucotuco.cs.indiana.edu% ls -l
total 10 -rw-r--r-- 1 dgerman students 515 Mar 20 20:07 BadArgumentException.class -rw-r--r-- 1 dgerman students 220 Mar 20 19:20 One.java -rw-r--r-- 1 dgerman students 1087 Mar 20 20:07 Two.class -rw-r--r-- 1 dgerman students 848 Mar 20 20:05 Two.java
tucotuco.cs.indiana.edu% java Two
The main method started... Factorial was called with negative input: -3 Factorial was called with negative input: -2 Factorial was called with negative input: -1 Factorial of 0 is: 1 Factorial of 1 is: 1 Factorial of 2 is: 2 Factorial of 3 is: 6 ... main method ends.
tucotuco.cs.indiana.edu% vi Two.java
tucotuco.cs.indiana.edu% cat Two.java
class Two { public static void main(String[] args) { System.out.println("The main method started..."); Two two = new Two(); for (int i = -3; i <= 3; i++) { try { int result = two.factorial(i); System.out.println(" Factorial of " + i + " is: " + result); } catch (BadArgumentException e) { System.out.println(" Factorial was called with negative input: " + e.toString()); } } System.out.println("... main method ends."); } int factorial(int n) throws BadArgumentException { if (n < 0) throw new BadArgumentException(n); // if (n == 0) return 1; return n * factorial(n - 1); } } class BadArgumentException extends Exception { int arg; BadArgumentException (int arg) { this.arg = arg; } public String toString() { return " " + arg; } }
tucotuco.cs.indiana.edu% javac Two.java
tucotuco.cs.indiana.edu% java Two
The main method started... Factorial was called with negative input: -3 Factorial was called with negative input: -2 Factorial was called with negative input: -1 Factorial was called with negative input: -1 Factorial was called with negative input: -1 Factorial was called with negative input: -1 Factorial was called with negative input: -1 ... main method ends.
tucotuco.cs.indiana.edu%
The lines marked in red are exceptions thrown when our contrived bug kicks in.


Last updated: Jul 31, 2002 by Adrian German for A201