CSCI A202 - Introduction to Programming (II)

Lecture 18: Exceptions. File and Terminal I/O. Serialization (I)

We start with exceptions, then move to file input, which is a likely source of Exceptions.

Then (probably on Thursday) we will discuss file output, terminal I/O, and perhaps serialization (which is a nifty way of writing whole objects to files and reading them back in as if they were primitive types).

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

2. File Input

The basic flow of processing:

Textbook page 338:
public void buttonClicked(Button buttonObj) {
  String fileName = nameField.getText(); 
  try {
    FileInputStream stream = new FileInputStream(fileName); 
    readAndProcessData(stream); 
    stream.close(); 
  } catch (IOException e) {
    messageBox("Error in opening input file:\n" + e.toString()); 
  } 
  nameField.requestFocus(); 
  nameField.selectAll(); 
}
There will be four versions of readAndProcessData that we will look at.

One that simply confirms that the file has been opened successfully.

private void readAndProcessData(FileInputStream stream) {
  messageBox("Running readAndProcessData\nFile opened successfully"); 
}
Another one that reads data one character at a time.

private void readAndProcessData(FileInputStream stream) {
  InputStreamReader reader = new InputStreamReader(stream); 
  try {
    output.setText(""); 
    int data = reader.read(); 
    while (data != -1) {
      char ch = (char)data;
      ch = Character.toUpperCase(ch); 
      output.append(ch + ""); 
      data = reader.read(); 
    } 
  } catch (IOException e) {
    messageBox("Error in file input:\n" + e.toString()); 
  } 
}
Another one that reads data one line at a time.

private void readAndProcessData(FileInputStream stream) {
  BufferedReader reader = new BufferedReader(new InputStreamReader(stream)); 
  try {
    output.setText(""); 
    String data = reader.readLine(); 
    while (data != null) {
      data = data.toUpperCase(); 
      output.append(data + "\n"); 
      data = reader.readLine(); 
    } 
  } catch (IOException e) {
    messageBox("Error in file input:\n" + e.toString()); 
  } 
}
And the last one that reads data one word at a time.

private void readAndProcessData(FileInputStream stream) {
  StreamTokenizer reader = 
    new StreamTokenizer(
      new BufferedReader(
        new InputStreamReader(stream))); 
  try {
    String data = ""; 
    output.setText(data); 
    reader.nextToken(); 
    while (reader.ttype != StreamTokenizer.TT_EOF) { 
      if (reader.ttype == StreamTokenizer.TT_WORD) { 
        data = reader.sval; 
        data += "(" + data + ")"; // data.toUpperCase(); 
      } else if (reader.ttype == StreamTokenizer.TT_NUMBER) 
        data += "(" + reader.nval + ")"; 
      output.append(data + ""); 
      reader.nextToken(); 
    } 
  } catch (IOException e) {
    messageBox("Error in file input:\n" + e.toString()); 
  } 
}