CS 2511 Fall 2014. Exception = an event that occurs during the execution of a program that disrupts...

27
CS 2511 Fall 2014

Transcript of CS 2511 Fall 2014. Exception = an event that occurs during the execution of a program that disrupts...

CS 2511Fall 2014

Exception = an event that occurs during the execution of a program that disrupts the normal flow of instructions: Examples: Out of bounds array access; Divide

by zero, etc. When an exception occurs, the executing

method creates an Exception object and hands it to the runtime system--"throwing an exception"

The runtime system searches the runtime call stack for a method with an appropriate handler, which "catches the exception"

Java is fussy about (some) exceptions, requiring that the programmer either: deal with the exceptions when they occur, using try and catch, or

explicitly hand off the exception to the method that calls the method in which the exception occurs, effectively "passing the buck" to the calling method.

The exceptions Java is fussy about are called "checked" exceptions, because the compiler will check that one of the above options is satisfied

1. Separating Error Handling Code from "Regular" Code

2. Propagating Errors Up the Call Stack3. Grouping Error Types and Error

Differentiation

readFile { open the file; determine its size; allocate that much memory; read the file into memory; close the file;}

Example: Here is pseudocode for reading a file into memory:

What happens if the file can't be opened?

What happens if the length of the file can't be determined?

What happens if enough memory can't be allocated?

What happens if the read fails? What happens if the file can't be

closed?

errorCodeType readFile { initialize errorCode = 0; open the file; if (theFileIsOpen) { determine the length of the file; if (gotTheFileLength) { allocate that much memory; if (gotEnoughMemory) { read the file into memory; if (readFailed) { errorCode = -1; } } else { errorCode = -2; } } else { errorCode = -3; } close the file; if (theFileDidntClose && errorCode == 0) { errorCode = -4; } else { errorCode = errorCode and -4; } } else { errorCode = -5; } return errorCode;}

readFile { try { open the file; determine its size; allocate that much memory; read the file into memory; close the file; } catch (fileOpenFailed) { doSomething; } catch (sizeDeterminationFailed) { doSomething; } catch (memoryAllocationFailed) { doSomething; } catch (readFailed) { doSomething; } catch (fileCloseFailed) { doSomething; }}

Note that the error handling code and "regular" code areseparate

method1 { call method2;}method2 { call method3;}method3 { call readFile;}

method1

method2

method3

readFile

Call Stack

Suppose also that method1 is the only method interested in the errors that occur within readFile.

How does the error code get propogated up the stack?

call

call

call

method1 { errorCodeType error; error = call method2; if (error) doErrorProcessing; else proceed;}errorCodeType method2 { errorCodeType error; error = call method3; if (error) return error; else proceed;}errorCodeType method3 { errorCodeType error; error = call readFile; if (error) return error; else proceed;}

method1

method2

method3

readFile

Call Stack

call

call

callreturn

return

return

method1 { try { call method2; } catch (exception) { doErrorProcessing; }}method2 throws exception { call method3;}method3 throws exception { call readFile;}

method1

method2

method3

readFile

Call Stack

call

call

call

throw

Java exceptions are first class Java objects, and so theyare grouped into a class hierarchy. For example:

Exception

RunTimeException

ArithmeticException

NullPointerException

IOException

FileNotFoundException

MalformedURLException

import java.io.*;

public class FileCopy {

public static void main(String[] args) throws IOException { BufferedReader br = new BufferedReader(new InputStreamReader(System.in)); FileReader r; FileWriter w;

System.out.print("Source file name: "); String inFileName = br.readLine(); r = new FileReader(inFileName);

System.out.print("Destination file name: "); String outFileName = br.readLine(); w = new FileWriter(outFileName);

int c;

while ((c = r.read()) != -1) w.write(c); w.flush(); }}

4% java FileCopySource file name: fooException in thread "main" java.io.FileNotFoundException: foo (No such file or directory)

at java.io.FileInputStream.open(Native Method)at java.io.FileInputStream.<init>(FileInputStream.java:103)at java.io.FileInputStream.<init>(FileInputStream.java:66)at java.io.FileReader.<init>(FileReader.java:39)at FileCopy.main(FileCopy.java:12)

5%

In the example, the main method chooses to "passthe buck," but there is nowhere to pass it to.

Thus, the program will crash:

public class FileCopy {

public static void main(String[] args) throws IOException { BufferedReader br = new BufferedReader(new InputStreamReader(System.in)); FileReader r; FileWriter w;

System.out.print("Source file name: "); String inFileName = br.readLine(); try { r = new FileReader(inFileName); } catch(FileNotFoundException ex) { System.out.println(ex.getMessage()); System.out.print("Source file name: "); inFileName = br.readLine(); r = new FileReader(inFileName); }

... }}

This approach will catch the first instance of a FileNotFoundException, but only that instance:

5% java FileCopySource file name: foofoo (No such file or directory)Source file name: barException in thread "main" java.io.FileNotFoundException: bar (No such file or directory)

at java.io.FileInputStream.open(Native Method)at java.io.FileInputStream.<init>(FileInputStream.java:103)at java.io.FileInputStream.<init>(FileInputStream.java:66)at java.io.FileReader.<init>(FileReader.java:39)at FileCopy.main(FileCopy.java:19)

6%

Note that you can use the getMessage() method(inherited by the Exception class) in your handler.

public class FileCopy {

public static void main(String[] args) throws IOException { BufferedReader br = new BufferedReader(new InputStreamReader(System.in)); FileReader r = null; FileWriter w = null;

boolean fileFound; do { fileFound = true; System.out.print("Source file name: "); String inFileName = br.readLine(); try { r = new FileReader(inFileName); } catch(FileNotFoundException ex) { fileFound = false; System.out.println(ex.getMessage()); } } while ( !fileFound ); ... }}

226% java FileCopySource file name: foofoo (No such file or directory)Source file name: barbar (No such file or directory)Source file name: foofoo (No such file or directory)Source file name: barbar (No such file or directory)Source file name: X.javaDestination file name: Y.java227%

public static void main(String[] args) throws IOException { BufferedReader br = new BufferedReader(new InputStreamReader(System.in));

FileReader r = getFileReader(br); FileWriter w = getFileWriter(br);

int c;

while ((c = r.read()) != -1) w.write(c); w.flush();

}

private static FileReader getFileReader(BufferedReader br) {

System.out.print("Source file name: "); try { String inFileName = br.readLine(); return new FileReader(inFileName); } catch(IOException ex) { System.out.println(ex.getMessage()); return getFileReader(br); } }

Note: No looping code needed.

Since the exception is caught, no throws clause is necessary.

private static FileWriter getFileWriter(BufferedReader br) {

System.out.print("Destination file name: "); try { String outFileName = br.readLine(); return new FileWriter(outFileName); } catch(IOException ex) { System.out.println(ex.getMessage()); return getFileWriter(br); } }

Now the only calls in main that can throw an exceptionare read, write, and flush

public static void main(String[] args) { BufferedReader br = new BufferedReader(new InputStreamReader(System.in));

FileReader r = getFileReader(br); FileWriter w = getFileWriter(br);

int c;

try { while ((c = r.read()) != -1) w.write(c); w.flush(); } catch(IOException ex) { System.out.println(ex.getMessage()); } }

Now the program will not crash if/when an I/O erroroccurs.

A program that catches all I/O exceptions may still experience a different type of exception (say, a runtime exception)

I/O exceptions are "checked" by the compiler That is, you are required to either catch them or

mention them in a throws clause Unlike I/O exceptions, runtime exceptions

are "unchecked" That is, you can choose to ignore them at your

peril

IOException and any of its subclasses InterruptedException (thrown when

a thread is interrupted) Any exception you invent by

subclassing Exception

Subclasses of RuntimeException: ArithmeticException IllegalArgumentException NumberFormatException IndexOutOfBoundsException

ArrayIndexOutOfBoundsException StringIndexOutOfBoundsException

NullPointerException Those that you invent by subclassing RuntimeException

Exceptions are processing conditions that a program ought to be able to recover from if it is robust enough

Errors are conditions that are ordinarily not recoverable: Death of a thread Linking error Virtual machine error

Exceptions and Errors are both subclasses of the Throwable class:

Object

Throwable

ErrorException

LinkageError ThreadDeath VirtualMachineError