mypages.valdosta.edumypages.valdosta.edu/dgibson/courses/cs1302/notes/ch…  · Web viewthat...

43
CS 1302 – Ch 12 – Exception Handling These notes cover Sections 12.1-12.11 Sections 12.1-12.2 – Exception Handling Overview 1. What is a run-time error? a. A run-time error occurs when your code tries to do something illegal: divide by zero, access an array element that is beyond the length of the array, call a method on an object reference that is null, an inappropriate cast, parsing an integer or double that is not a number, access a file that doesn’t exist, etc. b. When a run-time error occurs, the JVM throws an exception. An exception is an object. If the exception is not handled the program ends. That is what has happened in your code up to now. c. In this chapter we learn about exceptions and exception handling to do two separate (sometimes related) tasks: Use exception handling to recover from a run-time error and have the code continue to run. Design custom exceptions and learn to throw them when appropriate. 2. What exactly happens when a run-time error occurs in a Java Program? When a run-time error occurs, the JVM creates an Exception object and throws it. If this exception is not caught (handled) then the program terminates. For example, in the code below, an attempt to divide by zero causes a run-time error and an ArithmeticException is thrown and the code terminates. 1

Transcript of mypages.valdosta.edumypages.valdosta.edu/dgibson/courses/cs1302/notes/ch…  · Web viewthat...

CS 1302 – Ch 12 – Exception Handling

These notes cover Sections 12.1-12.11

Sections 12.1-12.2 – Exception Handling Overview

1. What is a run-time error?

a. A run-time error occurs when your code tries to do something illegal: divide by zero, access an array element that is beyond the length of the array, call a method on an object reference that is null, an inappropriate cast, parsing an integer or double that is not a number, access a file that doesn’t exist, etc.

b. When a run-time error occurs, the JVM throws an exception. An exception is an object. If the exception is not handled the program ends. That is what has happened in your code up to now.

c. In this chapter we learn about exceptions and exception handling to do two separate (sometimes related) tasks:

Use exception handling to recover from a run-time error and have the code continue to run. Design custom exceptions and learn to throw them when appropriate.

2. What exactly happens when a run-time error occurs in a Java Program? When a run-time error occurs, the JVM creates an Exception object and throws it. If this exception is not caught (handled) then the program terminates. For example, in the code below, an attempt to divide by zero causes a run-time error and an ArithmeticException is thrown and the code terminates.

1

3. Java allows us to use a try/catch block to catch a run-time exception, possibly correct or mitigate the situation (more on this later), and then continue running. The general syntax is:

try {// code that may fail (cause a run-time error)

}catch(Exception e) {

// Code to execute when an exception is thrown}

There are two cases:

a. Exception Thrown – When a run-time error occurs on a line of code in the try block, an Exception is thrown and control is immediately transferred to the catch block. The code in the catch block is executed and when complete, the code immediately after the catch block is executed (assuming no run-time error occurs in the catch block). Thus, any lines of code after the line that caused the run-time error in the try block are not excecuted.

b. No Exception Thrown – When the try block is complete (no run-time error), control is transferred to the first line immediately after the catch block. Thus, the catch block is not executed.

Note the following:

The catch block looks like a method, i.e. it defines a parameter, in the example above: Exception e.

A reference to the exception, e is available in the catch block; however, we do not use it here. Later, we will show how we can use it.

4. Example – Consider the pseudo-code below and assume that statement_3 is subject to run-time failure (or calls a method that is subject to run-time failure).

Code Statements that execute successfully when:

statement_1;try {

statement_2;statement_3;statement_4;

}catch( Exception e ) {

statement_5;}statement_6;

a. statement 3 fails: 1, 2, 5, 6b. statement 3 succeeds: 1, 2, 3, 4, 6

Exception

Output: 10No Exception

Output: 4 4

2

5. Java defines an Exception hierarchy a part of which is shown in the class diagram below. This hierarchy includes the RuntimeException subclass and then a number of common subclasses of RuntimeException. These exceptions correspond to specific types of errors that can occur in the program.

6. The parameter for the catch block can be Throwable or any subclass. A catch block will catch a thrown exception when its class is the same as the parameter or any subclass. Examples:

a. The block below will catch any exception.

try {// code that may fail}catch(Exception e) {// Code to execute when an exception is thrown}

b. The block below will only catch an ArithmeticException. If a NullPointerException is thrown it will not be caught. Later, we will consider this further.

try {// code that may fail}catch(ArithmeticException e) {// Code to execute when an exception is thrown}

7. The purpose of the the catch block is to: provide code to keep the code running, inform the user, send an error report, correct the error, etc. However, frequently, as we are learning about exception handling, we will simply print the exception in the catch block.

try {// code that may fail

}catch(ArithmeticException e) {

System.out.println(e);}

Which will simply print the class of the exception in the console. We will consider this in a little more detail later.

3

8. Example – The example on the right shows an exception being thrown in a method. This shows something important that we will look at in a bit more detail shortly. Note the following:

Line 8 is surrounded by a try/catch block and calls the inverse method.

Line 16 generates an ArithmeticException and since it is not surrounded by try/catch, the exception is thrown to the calling method (main).

9. Handling Errors – For robust software systems we must try to handle run-time errors so that the program does not stop unexpectedly. In general, there are two techniques:

1. Anticipate and trap sources of error before they result in a run-time error.2. Detecting and handling run-time errors after they occur.

10. Anticipating Errors – If we can anticipate an error we should usually try to write code to prevent it. For example, we have seen when we have a getter for an item in an ArrayList we usually check to make sure the index is valid before attempting to return the object, as shown below:

public class Company {private ArrayList<Employee> emps = new ArrayList<>();

public Employee getEmployee(int i) {if( i<0 || i>=emps.size() )

return null;return emps.get(i);

}...

}

11. It is hard to anticipate every single situation that could cause a run-time error. For example, the method below could fail because: (a) an array index is too big (or small), (b) the value of the denominator could be zero, (c) the vals array might not have been created.

public void divide4( int x, int y ) {int z = vals[x]/vals[y];

}

Hopefully it is clear, that even if we had an abundance of time, it would be nearly impossible to anticipate every possibly source of error. Thus, run-time errors are going to occur. In Java, we can use a try/catch block to detect run-time errors immediately after they occur and allow us to provide code to keep the program running, inform the user, send an error report, correct the error, etc.

4

12. Throwing Exceptions – Sometimes we have business rules that require that certain things be true. For example, we may have a business rule that states that an account must have a balance greater than 0 to be created. Java allows us to throw our own exceptions. In the example below we throw a RuntimeException if there is an attempt to create an Account with a balance that is zero or less. Then, the method (probably in another class) that is calling the Account constructor can choose to try/catch it it wants to. More on this later.

public class Account {...public Account(double balance) throws Exception {

if(balance<=0.0)throw new RuntimeException("low balance");

this.balance = balance;}...

}

13. The microscopic view of error handling, when writing code in a method that might throw an exception, is that we must ask ourselves if it is the responsibility of this method to handle the exception. If so, and if we know how to handle it, we do so. If it is not the responsibility or we don’t know how to handle the exception, we throw it for the calling method to handle or throw.

14. Designing robust error handling for a system is beyond the scope of this course. Here, we mostly focus on the techniques themselves. Some references on designing robust error handling:

http://www.onjava.com/pub/a/onjava/2003/11/19/exceptions.htmlhttp://codebuild.blogspot.com/2012/01/15-best-practices-about-exception.htmlhttps://stackoverflow.com/questions/4589750/exception-handling-patternhttps://stackoverflow.com/questions/425281/java-style-properly-handling-exceptions?rq=1

Some references on throwing and handling exceptions:

https://docs.oracle.com/javase/tutorial/essential/exceptions/handling.htmlhttps://docs.oracle.com/javase/tutorial/essential/exceptions/throwing.htmlhttp://mindprod.com/jgloss/exception.html

Homework: Questions 12.1, 12.5, 12.6 on pages 454, 455 of the text.

class Foo {public boolean eval(int y) {

if(Math.random()*5<y) {int[] vals = new int[1];vals[y]=10;return false;

}else

return true;}

}Homework

1. Consider the class shown on the right. Write a snippet of code to create a Foo instance and call the eval method such that the result of the method is printed if no exception is thrown and when an exception is

5

thrown, it is printed to the console.

6

zSection 12.3 – Exception Types

1. Exception Hierarchy – The Exception hierarchy is a bit larger than shown earlier:

********Needs to be incorporated

1. The Scanner constructor can throw a checked exception as shown by the “throws” clause in the signature of method:

https://docs.oracle.com/javase/9/docs/api/java/util/Scanner.html#Scanner-java.io.File-

This means that you must either try/catch when creating a Scanner, or add throws to the method you wrote that uses Scanner.

2. The Scanners, nextDouble (and lots of other next methods) can throw a number of exceptions

https://docs.oracle.com/javase/9/docs/api/java/util/Scanner.html#nextDouble--

Notice that there is NOT a throws in the signature, but below the description of method, there is a section labelled “Throws:”. These are unchecked exceptions. You can easily see this by clicking on one of the exceptions. For example click on the second one, “NoSuchElementException”,

https://docs.oracle.com/javase/9/docs/api/java/util/NoSuchElementException.html

and you can see that it is a subclass of RuntimeException (meaning that it is unchecked)

a. The Exception class describes errors caused by your program and external circumstances. These errors can be caught and handled by your program.

7

b. RuntimeException is caused by programming errors, such as bad casting, trying to access an array element that doesn’t exist, numeric errors, etc as we have discussed before.

c. The Error class describes internal system errors. Such errors rarely occur. If one does, there is little you can do beyond notifying the user and trying to terminate the program gracefully.

d. Unchecked Exceptions – RuntimeException, Error and their subclasses are known as unchecked exceptions. This means that these types of errors can and will occur, but you do not have to catch them, e.g try/catch is not required.

e. Checked Exceptions – Any exceptions other than RuntmeExceptions are known as checked exceptions. A checked exception that might occur in a method must be caught (with try/catch) or the method must declare the exception using the throws keyword. For example, when you attempt to read from a text file it is possible that a FileNotFoundException (subclass of IOException, a checked exception) will be thrown. Thus, one of these two approaches must be used:

try/catch throwspublic static void main(String[] args) {

try {// Read file

}catch( FileNotFoundException e )

{System.out.println(e);

}}

public static void main(String[] args) throws FileNotFoundException {

// Read File}

Section 12.4 – More on Exception Handling

Section 12.4.1 – Declaring Exceptions

Covered in the previous section.

Section 12.4.2 – Throwing Exceptions

1. There are two approaches to error handling:

a. Anticipate and trap sources of error before they result in a run-time error. There are two ways to handle this:

Fix the situation Throw a new exceptionif( detect error ) fix it, etc

if( detect error ) throw new Exception(“desc”);

b. Handling run-time errors after they occur. There are four ways to handle this:

Fix the situation Throw a new exceptiontry { something

try { something

8

}catch(Exception e) { fix it, etc}

}catch(Exception e) { throw new Exception(“desc”)}

Rethrow caught exception Throw a new exception, chaining caught exceptiontry { something}catch(Exception e) { throw e}

try { something}catch(Exception e) { throw new Exception(“desc”,e)}

Rethrowing and chaining are considered in a later section We can throw new Java Exceptions or we can create custom exception class and throw an instance of it.

This is considered in a later section.

2. Java defines the keyword throw which allows us to throw either a caught or new exception. The exception is thrown to the calling method which may in turn, handle it or throw it.

3. The Exception class and all its subclasses define a constructor that takes string argument which is a description of what caused the exception. Thus, we can create and throw Java exceptions with custom descriptions. For example:

throw new RuntimeException(“description of error”)

9

4. Example – Suppose a Circle class takes a radius in the constructor which is required to be greater than 0. If an attempt is made to pass a radius that is zero or less, then we can throw an IllegalArgumentException. Thus, this prevents a Circle from being created with an invalid radius.

Create and throw an Exception Use Classpublic class Circle {

private double radius;

public Circle(double radius) {if(radius <= 0.0) {

throw new IllegalArgumentException("Radius must be greater than zero.");

}this.radius = radius;

}...

}

Circle c;try{

c = new Circle(-5.5);}catch(IllegalArgumentException e) {

System.out.println(e);}

Notes:

IllegalArgumentException is a subclass of RuntimeException and this would be the natural, descriptive, choice of exception to throw for this example. However, we could have used RuntimeException or even Exception instead.

Probably in a real application we would do this error checking once the user entered a value for the radius in the GUI, before we attempted to create a Circle. Otherwise, our classes would be riddled with these throw statements and code using them would need to have try/catch anytime we use the classes. In general, it is better to do error checking outside a class like Circle. Nonetheless, this a useful technique, and is appropriate in some situations. In the examples that follow I’m not suggesting throwing an exception is the best way to handle things. Rather, we are just illustrating the mechanics of how to use this approach.

public class Account {private double balance;private String name;

public Account(double balance, String name) {

this.balance = balance;this.name = name;

}

public void mergeAccount(Account a) {this.balance += a.balance;

}}

Homework

2. Consider the class on the right. Modify the mergeAccount method so that it throws an IlleagalArgumentException if the account names are not the same and if they are the same, merges the accounts as shown. Write a snippet that creates a few accounts and tries to merge them handling any exception that is thrown by printing the exception.

10

11

Homework

3. Consider the class shown on the right. Write a static method to implement an algorithm that creates an Engine, and then calls, init, run, and then close if no exception is thrown in init. Thus, if no exception is thrown, the method would display:

init()run()close()

However, if init does throw an exception then run should not be called, but close should be. The desired output if an exception is thrown is:

java.lang.RuntimeExceptionclose()

4. Below are five attempts at writing the static method requested in the previous problem. For each attempt answer these questions:

1. Does the code compile? (Hint: only one does not)2. If the code compiles,

a. What output does it produce when no exception is thrown?b. What output does it produce when an exception is thrown?

Attempt 1 Attempt 2 Attempt 3Engine e = new Engine();

try {e.init();e.run();

}catch( RuntimeException ex ) {

System.out.println(ex);e.close();

}e.close();

Engine e = new Engine();

try {e.init();e.run();e.close();

}catch( RuntimeException ex ) {

System.out.println(ex);}

try {Engine e = new

Engine();e.init();e.run();

}catch( RuntimeException ex ) {

System.out.println(ex);}e.close();

Attempt 4 Attempt 5Engine e = new Engine();try {

e.init();e.run();

}catch( RuntimeException ex ) {

System.out.println(ex);}e.close();

Engine e = new Engine();try {

e.init();e.run();

}catch( RuntimeException ex ) {

System.out.println(ex);e.close();

}

class Engine {public void init() {

if( Math.random() < 0.5 )throw new

RuntimeException();else

System.out.println("init()");}public void run() {

System.out.println("run()");}public void close() {

System.out.println("close()");}

}

12

13

Section 12.4.3 – Catching Exceptions

5. Catching Multiple Exceptions – In general, you can catch multiple types of exceptions by supplying multiple catch blocks.

try { statements; // Statements that may throw exceptions}catch (Exception1 e1) { code to handle Exception1;}catch (Exception2 e2) { code to handle Exception2;}...catch (ExceptionN eN) { code to handle ExceptionN;}

Note the following:

The compiler forces you to arrange the catch blocks from most specific to most general. In other words, subclasses must be caught before superclasses. In the example below ArithmeticException is a subclass of Exception so it must be listed as the first catch block.

Valid Invalid (Doesn’t Compile)try {

...}catch ( ArithmeticException e ) {

...}catch ( Exception e ) {

...}

try {...

}catch ( Exception e ) {

...}catch ( ArithmeticException e ) {

...}

Only one catch block will activate, the first one that matches. In the example above on the left, an ArithmeticException would be caught in the first catch block even though it is also an Exception. An IndexOutOfBounds exception would be caught in the second catch block.

If no catch block is found that matches the argument type, then the exception is passed (thrown) to the calling method and this process repeats, i.e. searches for a matching catch block. If no catch block is found through the entire chain of method calls, the program terminates and a message is printed in the console.

6. If an exception is not caught in the current method, it is passed (thrown) to its caller. The process is repeated until the exception is caught or passed to main. If main doesn’t catch it, the program ends.

14

7. Example – In the example below, main calls the kee method passing an instance, g of the Grub class (not shown); however, g is null. Thus, a NullPointerException is thrown and since it is not an IllegalFormatException (see Figure on page 2 if necessary) it is thrown to main where it is caught because NullPointerException is a subclass of RuntimeException.

Homework

5. Suppose you are trying to call a method, foo() which can throw any of these types of exceptions: IlleagalArgumentException, IllegalFormatException, IllegalFormatCoversionException. Write a snippet of code that tries to call foo and catches any of these exceptions. Hint: see the class diagram on page 2.

15

Section 12.4.4 – Getting Information from Exceptions

8. Throwable – The java.lang package defines the Throwable class (see class diagram shown on page 2) which is the superclass of all exceptions. Two useful methods are:

a. getMessage – Returns the message that describes this exception object.

b. toString – The toString method gives the actual class of the Exception and the result of getMessage. Sometimes the message is a bit cryptic, for example:

java.lang.ArrayIndexOutOfBoundsException: 4

where the “4” is the index that was out of bounds.

c. printStackTrace –The printStackTrace method is much more useful because it displays the stack frames that exist when the error occurs. There is also a getStackTrace method that returns an array of StackTraceElement objects.

9. Example – Consider the Circle class from section 12.4.2. We will modify the catch block in main that calls it to illustrate the methods above.

public static void main(String[] args) {Circle c;try{

c = new Circle(-5.5);}catch(IllegalArgumentException e) {

System.out.println("getMessage()=\n " + e.getMessage());System.out.println("toString()=\n " + e.toString());System.out.println("printStackTrace()\n ");e.printStackTrace();

}}

Which produces the output:

getMessage()= Radius must be greater than zero.toString()= java.lang.IllegalArgumentException: Radius must be greater than zero.

printStackTrace() java.lang.IllegalArgumentException: Radius must be greater than zero.

at throwing_exceptions.Circle.<init>(Circle.java:8)at throwing_exceptions.CircleDriver.main(CircleDriver.java:8)

16

Section 12.5 – The finally Clause

1. try/catch/finally – You can add a finally block to a try/catch to make it try/catch/finally. The finally block of code is always executed no matter whether an exception was thrown or not.

try {// Statements

}catch( Exception e ) {

// Statements}finally {

// Statements}

2. Example – In the example below, suppose A, B, C, D, E are each a single statement of code and that A might throw an exception.

Codetry {

AB

}catch(Exception e) {

C}finally {

D}E

Scenario Statements Executed Successfully

A doesn’t throw exception A, B, D, EA throws exception C, D, EA & C throw exceptions D

3. Example – Consider the code below. What is the output?

No Exception Thrown Exception Thrown

Output: 1 2 4 5 Output: 1 3 4 5

17

Homework

6. Consider the following:

A and B are subclasses of RuntimeException. C is a subclass of B. Goo() is a method (not shown) that can throw an A, B, or C exception. Consider main and foo() shown below.:

What is the output when AnswerNo exception occurs? 1 4 5A B exception occurs? 3 4 5A C exception occurs? 2 4 6An A exception occurs? 4 7

public static void main(String[] args) {

try {foo();System.out.println("5");

}catch(C c) {

System.out.println("6");}catch(RuntimeException e) {

System.out.println("7");}

}

public static void foo() {try {

goo();System.out.println("1");

}catch(C c) {

System.out.println("2");throw(c);

}catch(B b) {

System.out.println("3");}finally {

System.out.println("4");}

}

Section 12.6 – When to Use Exceptions

1. When to throw an Exception?

Suppose an exception can occur in a method you have written. If you want the exception to be processed by its caller, you should create an exception object and throw it. If you can handle the exception in the method where it occurs, there is no need to throw it.

When should you use the try-catch block in the code? You should use it to deal with unexpected error conditions, and/or when complex error handling needs to take place. Do not use it to deal with simple, expected situations.

Section 12.7 – Rethrowing Exceptions

4. We can rethrow an exception that is caught in a catch block. We do this if we want the caller to handle the situation. For example:

try {...

}catch(RuntimeException e) {

throw(e);18

}5. Example – In the examples below, suppose A, B, C, D, E are each a single statement of code and that A might

throw an exception.

Codetry{

AB

}catch(Exception e) {

Cthrow(e) // or

return}finally{

D}E

Scenario Statements Executed Successfully

A doesn’t throw exception A, B, D, EA throws exception C, D, throw(e)

6. Consider the code shown on the right below which calls a method to divide to number. The explanation of the numbered steps is shown on the left.

Step Description1 divide is called on

line 72 Attempt to divide by

zero on line 16, throws an exception which is caught on line 19

3 Before the exception is thrown on line 20, the finally block is executed

4 Then, the catch block throws the exception which is caught by main on line 10.

19

7. Example – The two examples below are the same except that the one on the left does not have a finally block.

Output:myMethod(4,3): 1 2 4 5myMethod(4,0): 1 3 4 6

Output:myMethod(4,3): 1 2 5myMethod(4,0): 1 3 6

public class Problem3 {

public static void main(String[] args) {

int vals[] = new int[5];vals[0]=2; vals[1]=6; vals[2]=8;Too too = new Too();int sum = too.sum(vals, 7);System.out.println(sum);

}

}

class Too {public int sum(int[] vals, int numVals)

{int sum = 0;for(int i=0; i<numVals; i++) {

sum += vals[i];}return sum;

}}

Homework 20

7. Consider the classes shown on the right. The sum method sums the values in the input array in positons 0 through numVals-1. However, the method can cause a run-time error if numVals is too big or small. You should modify this method to try the computation and if an exception is thrown, it is caught and rethrown to main. You should also modify main to catch this exception should it be thrown and print it.

8. Example – These are two methods from a real system. The first method is called to open a connection to a server and establish input and output communication (socket) channels.

final public void openConnection() throws IOException {// Do not do anything if the connection is already openif(isConnected())

return;

//Create the sockets and the data streamstry {

clientSocket= new Socket(host, port);output = new ObjectOutputStream(clientSocket.getOutputStream());input = new ObjectInputStream(clientSocket.getInputStream());

}catch (IOException ex) {

// All three of the above must be closed when there is a failure// to create any of themtry {

closeAll();}catch (Exception exc) { }

throw ex; // Rethrow the exception.}

clientReader = new Thread(this); //Create the data reader threadreadyToStop = false;clientReader.start(); //Start the thread

}

private void closeAll() throws IOException {try {

//Close the socketif (clientSocket != null)

clientSocket.close();

//Close the output streamif (output != null)

output.close();

//Close the input streamif (input != null)

input.close();}catch (Exception exc) {

throw exc;finally {

// Set the streams and the sockets to NULL no matter what

21

// Doing so allows, but does not require, any finalizers// of these objects to reclaim system resources if and// when they are garbage collected.output = null;input = null;clientSocket = null;

}}

22

Section 12.8 – Chained Exceptions

1. Chaining Exceptions – Sometimes, we want to chain exceptions together. Here is how this works:

a. Catch an exceptionb. Create a new exceptionc. Link the original (caught) exception to the new oned. Throw the new one.

We call this exception chaining. The Exception class has another constructor that takes two arguments: (1) a string description and (2) a reference to another exception. It also provides the getCause method which returns a chained exception.

2. Example – Chained exceptions

public class ChainedTester1 {public static void main(String[] args) {

try {A a = new A();a.m1();

}catch( Exception e ) {

System.out.println( e + "\n" + e.getCause() + "\n" );}

}}

class A {public void m1() throws Exception {

try {B b = new B();b.m2();

}catch (Exception e) {

throw new Exception("A.m1() caused an exception", e);}

}}

class B {public void m2() throws Exception {

throw new Exception("B.m2() caused an exception");}

}

Output: java.lang.Exception: A.m1() caused an exceptionjava.lang.Exception: B.m2() caused an exception

public class Problem4 {

public static void main(String[] args) {

int vals[] = new int[5];

23

vals[0]=2; vals[1]=6; vals[2]=8;Roo roo = new Roo();int sum = roo.sum(vals, 7);System.out.println(sum);

}

}

class Roo {public int sum(int[] vals, int numVals)

{int sum = 0;for(int i=0; i<numVals; i++) {

sum += vals[i];}return sum;

}}

Homework

8. Consider the classes shown on the right. The sum method sums the values in the input array in positons 0 through numVals-1. However, the method can cause a run-time error if numVals is too big or small. You should modify this method to try the computation and if an exception is thrown create a new exception (with a description) chaining the original exception to it, and rethrow it to main. You should also modify main to catch this exception should it be thrown and print it, and the chained exception.

Section 12.9 – Custom Exceptions

1. Custom Exceptions – In some situations, it is useful to write our own customized exception classes. These are classes just like any other class except that they extend Exception or its subclasses). Thus, we can provide properties and methods that contain information about the error that might be useful to code that catches the exception.

2. Example – Consider a method in a class that divides two numbers which obviously can throw an exception if the value of y is 0:

class A { public int m1( int x, int y ) { return x/y; }}

a. We would like to detect this situation and if it occurs, throw a custom exception, MyMathException that contains a description of the error and the values of x and y.

class A { public int m1( int x, int y ) throws MyMathException { if( y==0 ) throw new MyMathException( "Can't divide by zero", x, y ); return x/y; }

24

}

25

b. Thus, we define a MyMathException class that extends RuntimeException. The constructor accepts a description of the error and two integers. We also provide getters so the code that calls m1 above and catches an exception can obtain the values of x and y.

class MyMathException extends RuntimeException {private int x; private int y; public MyMathException( String msg, int x, int y ) {

super(msg); this.x = x; this.y = y;

}public int getX() { return x; }public int getY() { return y; }

}

c. Finally, we can call the method and catch the exception, displaying the values of x and y.

public class ExceptionTester9 { public static void main(String[] args) throws Exception { A a = new A(); try { System.out.println(a.m1(4,0)); } catch( MyMathException me ) { System.out.println(me); System.out.println("x=" + me.getX() + ", y=" + me.getY() ); } catch( Exception e ) { System.out.println(e); } }

Output: MyMathException: Can't divide by zerox=4, y=0

26

public class Blob {private int power;private int health;

public Blob(int power, int health) {this.power = power;this.health = health;

}

public int getPower() {return power;

}

public int getHealth() {return health;

}

public void merge(Blob blob) {this.health += blob.health;

}

public String toString(){return String.format("power=%d,

health=%d", power, health);}

public static void main(String[] args) {

Blob b1 = new Blob(5,10);Blob b2 = new Blob(4,8);b1.merge(b2);System.out.println(b1);

}}

Homework

9. Consider the class shown on the right. We want to modify the merge method so that it only merges Blobs if their power is the same. If their power is not the same, then you should throw a custom BlobMergeException. This exception should contain a description of the error and the power value for each of the two Blobs.

a. Write the BlobMergeExceptionb. Modify the merge method to utilize the exception as described above.c. Modify main to catch any BlobMergeException that may be thrown, displaying the description and the two

power values.

27

Section 12.10 – The File Class

1. The File class in Java is used as an abstraction for files and folders that deals with the machine-dependent intricacies of files, folders and paths. Some of the methods are shown on the right. Others are found in the API. A File object is not the actual file, it is just metadata about the actual file.

2. To read (or write) data we first create an instance of the File class which contains the location of the file. For example:

File inFile = new File( "employees1.txt" );

If you are using Eclipse, the default path to look for the file is in the project folder. For homework assignments, I will ask you to place your file(s) in the package folder where your code is. To specify the path your will:

File inFile = new File( "src\\package_name\\employees1.txt" );

A “\” is used to separate folders and the file in the path; however, an additional “\” is needed to delimit the single, required “\” in the path.

3. Example – Illustrates some of the methods in the File class.

public static void main(String[] args) {File file = new File("src\\file_example\\data.txt");System.out.println("Does it exist? " + file.exists());System.out.println("The file has " + file.length() + " bytes");System.out.println("Can it be read? " + file.canRead());System.out.println("Can it be written? " + file.canWrite());System.out.println("Is it a directory? " + file.isDirectory());System.out.println("Is it a file? " + file.isFile());System.out.println("Is it hidden? " + file.isHidden());System.out.println("Absolute path is " + file.getAbsolutePath());System.out.println("path is " + file.getPath());System.out.println("parent is " + file.getParent());System.out.println("Last modified on " + new java.util.Date(file.lastModified()));

}

Output:

Does it exist? trueThe file has 40 bytesCan it be read? trueCan it be written? trueIs it a directory? falseIs it a file? trueIs it hidden? false

Absolute path is E:\Data-Classes\CS 1302 - Programming 2\notes\06_ch12_Exceptions\code\Ch12_Exceptions_Files\src\file_example\data.txt

path is src\file_example\data.txt

parent is src\file_example

Last modified on Wed Sep 24 10:43:54 EDT 201428

Section 12.11 – Text File Input & Output

1. Background information about text files:

a. A text file is actually a file filled with binary digits, 1’s and 0’s (which itself is an abstraction). However, the software (Word, Eclipse, etc.) that accesses a text file uses character decoding. For example:

Binary stream: Decoded Stream:

010010100110000101110110011000018-bit Blocks 01001010 0110000

101110110 01100001

Decoded ASCII Text J a v a

b. The encoding/decoding scheme shown above is ASCII. For example the (partial) table above on the right shows how text is encoded/decoded. For example, the ASCII letter “a” is represented in binary as: 01100001. ASCII was the standard on the internet until 2007. Now, UTF-8 is the standard. UTF-8 was designed to be backwards compatible with ASCII, so they are the same. Be default, Java reads and writes using ASCII, however you can set a parameter to use UTF-8.

c. The information above is not directly needed for this course but is useful for a general understanding. Usually (and always for this course) when we read/write information to/from a text file the decoding/encoding is done automatically.

2. The File class does not provide methods for reading and writing files. We can use the Scanner class to read text files and the PrintWriter class to write text files.

Section 12.11a – Writing Text Files

3. One way to write data to a text file is to use the PrintWriter class as shown in the class diagram on the right.

a. The constructor accepts a File as an argument:

File outFile = new File("src\\write_examples\\numbers.txt");PrintWriter writer = new PrintWriter( outFile );

b. Probably the three most useful (at least for our class) methods of the PrintWriter class are print(…), println(…), and printf(…) which work identically to the System.out.print(…) methods. For example, to loop over an array of integers (nums) and write them space-delimited to a text file:

for( int i=0; i<nums.length; i++ ) {writer.print( nums[i] + " " );

}

c. When we are done writing, we must close the writer: writer.close();

ASCII Dec Hex Binary0 48 30 0011 00001 49 31 0011 00012 50 32 0011 0010… … … …A 65 41 0100 0001B 66 42 0100 0010C 67 43 0100 0011… … … …a 97 61 0110 0001b 98 62 0110 0010c 99 63 0110 0011… … … …

29

d. The PrintWriter class can throw a checked exception so this means that we must either try/catch file operations or declare that it throws an exception.

30

4. Example –

a. try/catch

public static void main(String[] args) {File outFile = new File("src\\write_examples\\output.txt");

int[] nums = {33, 44, 55, 66, 12, 33, 55, 66, 77, 22};

try {PrintWriter writer = new PrintWriter( outFile );

for( int i=0; i<nums.length; i++ ) {writer.print( nums[i] + " " );

}writer.close();

}catch (IOException ioe) {

System.out.println("Problem creating file or writing");}

}

b. throws

public static void main(String[] args) throws FileNotFoundException {File outFile = new File("src\\write_examples\\output.txt");

int[] nums = {33, 44, 55, 66, 12, 33, 55, 66, 77, 22};

PrintWriter writer = new PrintWriter( outFile );

for( int i=0; i<nums.length; i++ ) {writer.print( nums[i] + " " );

}writer.close();

}

31

Section 12.11b – Reading Text Files

4. Java provides a number of classes1 for reading text files but we will consider only the Scanner class. Of course you have used the Scanner class before. We will only use the methods shown on the right, however there are many more that would be useful in practice.

5. How does a scanner work?

“A Scanner breaks its input into tokens using a delimiter pattern, which by default matches whitespace. The resulting tokens may then be converted into values of different types using the various next methods.”2

We will only be using the default delimiter. However, it is easy use other delimiters as the Scanner class defines the useDelimiter(String pattern) and useDelimiter(Pattern pattern) methods.

6. Example – Consider a text file with the data shown on the right. The line numbers (1-15) are shown on the left and are not a part of the file. Each three lines represents an employee: name, salary, age. A snippet of code to read these values in, create Employee objects and add them to an ArrayList.

ArrayList<Employee> employees = new ArrayList<>();

File inFile = new File( "src\\examples1\\employees.txt" );

try {Scanner input = new Scanner( inFile );while( input.hasNext() ) {

String name = input.next();double salary = input.nextDouble();int age = input.nextInt();employees.add(new Employee( name, salary, age ));

}input.close();

}catch( FileNotFoundException e ) {

System.out.println(e);}

1 https://docs.oracle.com/javase/7/docs/api/java/util/Scanner.html

2 https://docs.oracle.com/javase/7/docs/api/java/util/Scanner.html

32

7. As you saw in the lab, the code above can also read any one of the text files below.

8. A few notes on the Scanner methods:

a. close() – Closes the scanner. You should always do this.b. hasNext():boolean – Returns true if the scanner has another token. Note: there are a bunch of specialized

methods: hasNextInteger(), hasNextDouble(), etc.c. next():String – Returns the next token as a string.d. nextBoolean():boolean – Returns the next token as a boolean. This method will throw

InputMismatchException if the token is not a boolean.e. nextDouble():double – Returns the next token as a double. This method will throw InputMismatchException

if the token is not a double.f. nextInt():int – Returns the next token as an integer. This method will throw InputMismatchException if the

token is not a integer. g. nextLine() – Returns everything from the current position of the cursor to the end of the line and the cursor

is moved to the beginning of the next line.

9. As also shown in the lab, parsing data is often necessary. For example, suppose we have a file as shown on the right. A person (Dave) is shown on line 1 and the number of dogs he has (2). The next two lines show the two dogs. We would like to read the entire file of people where each person can have a different number of dogs. One way to do this is to read a person’s name:

File inFile = new File( "src\\examples1\\peopleAndDogs.txt" );Scanner input = new Scanner( inFile );...String name = input.next();

and then read their number of dogs

int numDogs = input.nextInt();

33

and then loop over the number of dogs reading each dog’s name:

for(int i=0; i<numDogs; i++){String dogName = input.next();...

}

Now, suppose we have Person and Dog classes as shown in the class diagram on the right. Then, we can build an ArrayList<Person> with code like this:

ArrayList<Person> people = new ArrayList<>();...

while( input.hasNext() ) {String name = input.next();Person p = new Person(name);int numDogs = input.nextInt();for(int i=0; i<numDogs; i++){

String dogName = input.next();Dog dog = new Dog(dogName);p.addDog(dog);

}people.add(p);

}

Section 12.11c – Appending Text Files

This information is not covered in the text.

10. Sometimes it is useful to add information onto then end of an existing file. This is called appending a file. We must use the FileWriter class to create an interface that allows us to append a text file. The constructor for FileWriter accepts a File object and has a second parameter that when set to true indicates that we want to append the file. Finally, the PrintWriter class has a constructor that accepts a FileWriter object.

int[] nums = {33, 44, 55, 66 };

File outFile = new File( "src\\textfile_examples\\output3.txt" );

// Create a FileWriterFileWriter fw = new FileWriter( outFile, true );

// Create a PrintWriter. PrintWriter writer = new PrintWriter( fw );

// Loop over the array of numbers.for( int i=0; i<nums.length; i++ ) {

writer.println( nums[i] );}

// Close the PrintWriter.writer.close();

Homework

10. No problem available presently! 34

35