exception handling 9-6-2013 - clarkson universityjsearlem/cs242/fa13/lectures/07.exceptions.pdfan...

Post on 15-Jul-2020

1 Views

Category:

Documents

0 Downloads

Preview:

Click to see full reader

TRANSCRIPT

Exception Handling

9-6-2013

Exception Handling Types of exceptions

Standard exceptions

Propagating vs. handling exceptions

HW#2 posted; due 9/23/2013

Reading assignment: EJ2, Chapter 9, Exceptions

Java allows every method an alternative exit path if it is unable to complete its task in the normal way.

In this situation, the method does NOT return a value; instead it creates & “throws” an exception object that encapsulates the error information and it exits immediately

Java’s exception handling system will search the call stack for an “exception handler” that can deal with this error

An exception is an object it contains information about the problem methods exist which retrieves this information

There are checked exceptions and unchecked exceptions

There are 2 ways of dealing with exceptions:

1.throwing exceptions (propagation):

the applications programmer decides what to do about the problem

2.handling exceptions (try/catch):

the class designer handles it internally

public class Magic {

public String castSpell(int n) { … }

} // end Magic

public class Lamp {

public void init() {

Magic m = new Magic();

String arg = m.castSpell(42);

}

} // end Lamp

public class Test {

public static void main(…) {

Lamp t = new Lamp();

t.init();

}

} // end Test 1. main() calls Lamp.init()

2.1 Lamp.init() calls Magic.castSpell()

3. Magic.castSpell() currently executing

0. main() calls constructor

2.0 calls constructor

main() Lamp.init() Magic.castSpell()

case 1: normal operation.

1. castSpell() returns a string to the point of call

case 2: exception occurs.

1. execution of castSpell() immediately terminates, a string is not returned, do not return to point of call;

2. search backwards through call stack until an appropriate exception handler is found; if none found, program terminates

currently executing

checked (meaning the compiler can check)

most application exceptions are checked

if you call a method which throws a checked exception, you MUST specify to the compiler how this will be handled:

either (1) propagate (or throw) it, or (2) handle the error at once (try/catch)

unchecked

subclasses of java.lang.RuntimeException or java.lang.Error (i.e. programming errors or system errors)

Object

Throwable

Exception Error

IOException RuntimeException

FileNotFoundException ArithmeticException

AssertionError

Standard

Exceptions

RuntimeException

ArithmeticException

NullPointerException

ClassCastException

Exception Standard

Exceptions

java.io.IOException

EOFException

FileNotFoundException

MalformedURLException

java.lang.Exception

Standard

Exceptions

/* Example: Want to write a method, readLine(), that reads in a line of text. Algorithm: have a loop that calls System.in.read() which reads in one character. */

public int read() throws IOException

Returns: the next byte of data, or -1 if the

end of the stream is reached.

Throws: IOException - if an I/O error occurs.

This is a checked exception, so the method readLine() must either handle the exception internally or “propagate” it externally

// Alternative 1: propagate the error // (let someone else in the call stack handle it)

public static String readLine() throws IOException

{ /* code to read in a line of text */ }

// Alternative 2: handle the error internally

public static String readLine() {

try {

/* code to read in a line of text */

} catch(IOException e) {

/* do something sensible about an I/O error */

} }

// Version 1: if error occurs, propagate the error // (loses partial line)

public static String readLine() throws IOException {

int ch; String r = ""; boolean done = false;

while(!done) {

ch = System.in.read();

if ((ch < 0) || (ch == '\n'))

done = true;

else

r = r + (char)ch;

}

return r;

}

if an error occurs in read(), the code for read will create a new exception object and throw it here; then readLine() will propagate (throw) the error to where it was called

// Test Version 1 of readLine()

import java.io.*;

public class TestVersion1 {

// Version 1: if error occurs, propagate the error

public static String readLine()

throws IOException

{ … }

public static void main(String[] args) {

System.out.print("Enter a line:");

System.out.println(readLine());

}

} compile error! why? unreported exception

// Test Version 1 of readLine(), take 2

import java.io.*;

public class TestVersion1 {

// Version 1: if error occurs, propagate the error

public static String readLine() throws IOException

{ … }

public static void main(String[] args) {

System.out.print("Enter a line:");

try {

System.out.println(readLine());

} catch(IOException e) {

System.err.println(e.getMessage()); }

}

}

// Version 2: if read() fails, return partial line

public static String readLine() {

int ch; String r = ""; boolean done = false;

while(!done) {

try {

ch = System.in.read();

if (ch < 0) || (char)ch == '\n')

done = true;

else

r = r + (char)ch;

} catch(IOException e) { done = true; }

}

return r;

}

// Test Version 2 of readLine()

import java.io.*;

public class TestVersion2 {

// Version 2: if error occurs, return partial line

public static String readLine()

{ … }

public static void main(String[] args) {

System.out.print("Enter a line:");

System.out.println(readLine());

}

} no compile error! why not?

throws not here

try/catch must be here

Method propagates an error, i.e. throws an exception

public static String readLine() throws Exception {

… }

Calling code somewhere in the call stack must have a try/catch for that exception

Method handles the error, so must contain a try/catch

public static String readLine() {

try {…} catch (Exception exc1) { handle error}

}

Calling code doesn’t have a try/catch

Should readline propagate the exception or handle it internally?

Is there another alternative that is better?

try {

// stuff

} catch (SomeException e1 ) {

/* do something sensible about the error */

} What to do?

• if caused by user error, give the user a chance to correct it

• take a sensible default action

• print (or display) an error message – where?

• display pop-up dialog, etc.

All exceptions inherit the properties & methods of Throwable

useful methods include:

String getMessage(); // error message

String toString(); // short description

void printStackTrace(); // backtrace

void printStackTrace(PrintStream);

tip: print to standard error stream

System.err.println(“system malfunction”);

try {

// stuff

} catch (SomeException e1 ) {

}

System.err.println( e1.getMessage() );

System.err.println( e1.getClass().getName());

e1.printStackTrace( System.err );

note: use System.err.println() NOT System.out.println()

Consider the BigInteger class in java.math:

public class BigInteger /* arbitrary precision integers */

extends Number

implements Comparable<BigInteger>

/** Returns (this mod m) as a BigInteger

@param m, the modulus, which must be positive

@return this mod m (0, 1, …, m-1)

*/

public BigInteger mod(BigInteger m) {

/* compute and return (this modulo m) */

}

Example: BigInteger

/* application programmer writes the following */

public static void main(…) {

Random RNG = new Random();

BigInteger bi = new BigInteger(50, RNG);

BigInteger ms = new BigInteger(“0”);

System.out.println( bi.mod(ms));

} ERROR – division by zero

/** Returns a BigInteger whose value is (this mod m). @param m the modulus, which must be positive @return this mod m @throws ArithmeticException if m <= 0 */ public BigInteger mod(BigInteger m) throws ArithmeticException { if (m.signum() <= 0) throw new ArithmeticException( “Modulus not positive”); // … } an exception object is created & the call stack is

searched for code to handle the problem

/* application using BigInteger */

public static void main(…) {

Random RNG = new Random();

BigInteger bi = new BigInteger(50, RNG);

BigInteger ms = new BigInteger(“0”);

System.out.println( bi.mod(ms) );

} PROBLEM – where’s the code to handle the error?

Note that the compiler can determine that this is a problem. How? Because the header for BigInteger.mod() specifies that it “throws” an exception (specifically ArithmeticException)

public static void main(…) {

Random RNG = new Random();

BigInteger bi = new BigInteger(50, RNG);

BigInteger ms = new BigInteger(“0”);

try {

System.out.println( bi.mod(ms) );

} catch (ArithmeticException ex) {

System.out.println(ex.getMessage());

}

} Application programmer decides what to do: print an error message? let the user try again? whatever…

for public methods, use Javadoc @throws tag to document the exception that will be thrown

(typically IllegalArgumentException, IndexOutOfBoundsException, or NullPointerException)

nonpublic methods should generally check their parameters using assertions (will cover at a later date)

IllegalArgumentException

parameter value is inappropriate

IllegalStateException

object state is inappropriate

NullPointerException

parameter value is null where prohibited

IndexOutOfBoundsException

index parameter value is out of range

if an error is always the result of a programming error, make it a subclass of RuntimeException (unchecked)

if an error is something the application can recover from: use checked exception class (extends Exception)

the Error class is effectively reserved for the JVM, and is used to indicate resource deficiencies, invariant failures and other conditions that make it impossible to continue execution

String public String(byte[] bytes, int offset, int length)

Constructs a new String by decoding the specified subarray of bytes using the platform's default charset.

Parameters:

bytes - the bytes to be decoded into characters

offset - the index of the first byte to decode

length - the number of bytes to decode

Throws:

IndexOutOfBoundsException - if the offset and the length arguments index characters outside the bounds of the bytes array

try { // do stuff }

catch(IOException ioe) { // handle this case }

catch(UnknownHostException uhe) { // handle this case }

catch(Exception e) { // catch-all }

note that order is important

If any of the code inside the try block throws an exception of the specified types, then

1. the program skips the remainder of the code in the try block

2. the program executes the handler code inside the matching catch clause

If any of the code inside the try block throws a different kind of exception, the method exits immediately (presumably the calling code has a catch clause for that type)

The exception objects, ioe, uhe, contains information about the error that occurred. Can use this when handling the problem.

Item 58: Use checked exceptions for recoverable conditions and run-time exceptions for programming errors

checked – caller can be reasonably be expected to recover from this type of error

run-time – indicates programming errors, such as precondition violations, array out of bounds, etc.

Exception types:

main() Lamp.init() Magic.castSpell()

public class Magic {

public String castSpell( int n) {

char ch = System.in.read();

if (n < 0)

throw new FooException(“you idiot”);

line[-1] = ch;

}

suppose an error occurs

checked

thrown

unchecked (array bounds error)

system error

constructor for Circle throws exception

public Circle(float radius, int x, int y)

throws IllegalArgumentException;

main program contains:

{

Circle c1 = new Circle(9f, 9, 9);

Is there a problem?

}

constructor for Circle throws exception public Circle(float radius, int x, int y) throws

IllegalArgumentException;

main program contains:

try {

float z;

int x, y;

/* code to read values for z, x and y */

Circle c1 = new Circle(z, x, y);

} catch(IllegalArgumentException iae) {

System.err.println(“illegal value”);

}

System.out.println(c1.computeArea());

What’s the problem?

Should this exception even be caught?

import javax.sound.midi.*;

public class TheMusicMan {

public void play() {

Sequencer sequencer = MidiSystem.getSequencer();

System.out.println("We have a sequencer\n");

}

public static void main(String[] args) {

TheMusicMan mm = new TheMusicMan();

mm.play();

}

}

error: unreported exception

MidiUnavailableException; must be

caught or declared to be thrown

public static Sequencer getSequencer()

throws MidiUnavailableException

Returns:

the default sequencer

Throws:

MidiUnavailableException - if the sequencer is not available due to resource restrictions, or there is no Receiver available by any installed MidiDevice, or no sequencer is installed in the system.

top related