chapter 9 exception handling• in chapter 7 we created a module class –a course holds a reference...
TRANSCRIPT
Chapter 9Exception Handling
Foundational JavaKey Elements and Practical Programming
Foundational Java 2nd edition by David Parsons © 2020
Exceptions
• Deal with unusual program flow
– technical issues
– business processes
• Cover a range of issues
– major programming errors
• dividing an integer by zero
• trying to invoke methods on a null reference
– minor business process exceptions
• invalid area code in an address
Foundational Java 2nd edition by David Parsons © 2020
Java Exceptions
• When an unusual condition arises in Java code it can throw an exception
• If nothing is done, the program will terminate
– We need to write code that is able to detect and handle any exceptions that may arise
• Compiler requires us to handle some exceptions
• Others we may anticipate ourselves
• Can also create exceptions explicitly
– Where business rule has been violated
Foundational Java 2nd edition by David Parsons © 2020
The Exception Handling Hierarchy
Foundational Java 2nd edition by David Parsons © 2020
checked exceptions
unchecked errors
unchecked exceptions
Throwable
Error Exception
RuntimeException All Other Subclasses
Subclasses
Exception and Error Classes
• At the top of the hierarchy is ‘Throwable’
– any kinds of errors and exceptions that might occur in a Java program.
• Created by the JVM at run time or explicitly created using the ‘throw’ keyword
• Programmers need not try to deal with Errors
• Exceptions indicates conditions that a reasonable application might want to catch
Foundational Java 2nd edition by David Parsons © 2020
Checked and Unchecked Exceptions
• RuntimeExceptions can be thrown during the normal operation of the Java Virtual Machine
– ‘unchecked’ exceptions
– not required by the compiler to handle hem
• Exceptions that are direct subclasses of Exception are ‘checked’ exceptions
– the compiler will ensure that we do something in our application code to handle them
Foundational Java 2nd edition by David Parsons © 2020
Java Exception Handling Keywords
Keyword Usage
throws indicates that a method may throw an exception
try encloses a block of code that may throw an exception
catch follows ‘try’ - encloses a block of code that is invoked if a specified exception is thrown
finally follows ‘try’ or ‘catch’ - encloses a block of code that executes regardless of whether any exceptions are thrown
throw allows the programmer to explicitly throw an exception
Foundational Java 2nd edition by David Parsons © 2020
Checked Exceptions
• A checked exception must be handled, or the code will not compile
• This piece of code attempts to do some very crude keyboard input
• It will not compile, because the ‘read’ method of System.in throws a java.io.IOException
Foundational Java 2nd edition by David Parsons © 2020
int myChar = System.in.read(); // will not compile
System.out.println((char)myChar);
public int read(byte[] b) throws IOException
Handling Checked Exceptions
• Java will check, at compile-time, whether a program contains the code necessary to handle such an exception
• The exceptions that can be thrown by a method are stated in the method declaration
– Also in the Javadoc
Foundational Java 2nd edition by David Parsons © 2020
public abstract int read() throws IOException{
. . .}
Console Input
• In Eclipse, when we run a program that uses “System.in.read”, the output console is also used for input
• You terminate the input by pressing the Enter key. Only the first character typed will be captured by the “read” method.
• Here, the character “a” has been typed in and then echoed back to the same console.
Foundational Java 2nd edition by David Parsons © 2020
‘throws’
• We can re-throw the exception to make the code compile
• Use the throws keyword
• Simply re-throwing a checked exception is not a particularly good way of dealing with it
• Ignoring exceptions will not lead to very robust applications.
Foundational Java 2nd edition by David Parsons © 2020
public static void main(String[] args) throws java.io.IOException
Catching Exceptions - ‘try’ and ‘catch’
• ‘anException’ must be one of the predefined exception classes
• Or an object of an Exception subclass we have written ourselves
• It must also be an exception that may actually be thrown by the code in the ‘try’ block
Foundational Java 2nd edition by David Parsons © 2020
try
{
// do this
}
catch(anException e)
{
// if it all went horribly wrong, do this
}
Handling A Checked Exception
• Must do something in the catch block
• printStackTrace displays exception information
Foundational Java 2nd edition by David Parsons © 2020
byte[] buffer = new byte[10];
String inputString= null;
try
{
System.in.read(buffer);
inputString = new String(buffer).trim();
}
catch(java.io.IOException e)
{
e.printStackTrace();
}
System.out.println(inputString);
Handling Unchecked Exceptions
• You can choose to handle unchecked exceptions
• This piece of code will compile, but would throw an ArrayIndexOutOfBoundsException at run time
Foundational Java 2nd edition by David Parsons © 2020
int[] intArray = new int[3];
for(int i = 0; i < 5; i++)
{
intArray[i] = i;
}
ArrayIndexOutOfBoundsException
• This version catches the unchecked ArrayIndexOutOfBoundsException
Foundational Java 2nd edition by David Parsons © 2020
int[] intArray = new int[3];
for(int i = 0; i < 5; i++)
{
try
{
intArray[i] = i;
}
catch(ArrayIndexOutOfBoundsException e)
{
e.printStackTrace();
}
}
Exiting
• A ‘catch’ block is an opportunity to either ignore an exception and carry on, or do something to fix the problem at run time.
• Sometimes the program cannot reasonably recover
• We can explicitly exit the program using ‘System.exit’
– non-zero value indicates an abnormal exit
Foundational Java 2nd edition by David Parsons © 2020
catch(Exception e)
{
e.printStackTrace();
System.exit(1);
}
Catching Multiple Exceptions
• A try block can have multiple catch blocks
– Better than lots of ‘try-catch’ blocks
Foundational Java 2nd edition by David Parsons © 2020
byte[] buffer = new byte[10];
int inputInt = 0;
try
{
System.in.read(buffer);
String inputString = new String(buffer).trim();
inputInt = Integer.parseInt(inputString);
}
catch(java.io.IOException e)
{ … }
catch(NumberFormatException e)
{ … }
System.out.println(inputInt);
Ordering Multiple ‘catch’ Blocks
• If you use subclass and superclass exceptions, then you must order the handlers from the bottom to the top of the hierarchy
– Otherwise some catch blocks never get used
Foundational Java 2nd edition by David Parsons © 2020
try {
…
} catch (IOException e) {
…
} catch (Exception e) {
…
}
Exercise 9.1
• Create a reusable Keyboard class that includes static methods to read a single character, a String or an integer from the keyboard
• Include the required exception handling
• Add a static method to input a floating-point number, using the ‘parseDouble’ method of the Double class to implement the method
• Test your Keyboard class in a ‘main’ method
Foundational Java 2nd edition by David Parsons © 2020
Throwing an Exception with ‘throw’
• To explicitly throw an exception you create an exception object, and use the throw keyword
– If a business rule has been violated
Foundational Java 2nd edition by David Parsons © 2020
/**
* @param numberOfDays
* @throws IllegalArgumentException
*/
public void setNumberOfDays(int numberOfDays) throws IllegalArgumentException
{
if (numberOfDays < 1 || numberOfDays > 10)
{
throw new IllegalArgumentException(numberOfDays +
" is outside the valid range of 1 - 10");
}
Delegating Responsibility
• A method can delegate the responsibility for an exception– Whether this is appropriate depends on your application and the type of exception!
• Any code that calls the readChar method must now handle the IOException
Foundational Java 2nd edition by David Parsons © 2020
public char readChar() throws IOException
{
return (char)System.in.read();
}
Handling and Forwarding Exceptions
• You can handle an exception and then re-throw it
– The sender can then also be notified of the exception
Foundational Java 2nd edition by David Parsons © 2020
public char readChar() throws IOException
{
try
{
return (char)System.in.read();
}
catch (IOException e)
{
e.printStackTrace();
throw e;
}
}
Exercise 9.2
• Modify the ‘setName’ method from the Course class so that it throws a NullPointerException if the parameter passed to it is null
• The ‘throws’ keyword on a method signature may be followed by more than one exception type, in a comma separated list, for example:
• Modify the signature of the parameterized constructor of the Course class so that it throws both IllegalArgumentException and NullPointerException
• Modify your ‘main’ method so it can catch both types of exception. Use different constructors in separate ‘try…catch’ blocks
Foundational Java 2nd edition by David Parsons © 2020
public char readCharFromKeyboard() throws IOException, Exception
{ … }
Writing and Using Custom Exceptions
• You can create your own exception class by subclassing java.lang.Exception
• The new subclass of Exception typically has at least two constructors:
– a zero-arguments constructor
– a constructor that takes a String parameter
• The second constructor allows you to include a message when creating an instance of your Exception class
Foundational Java 2nd edition by David Parsons © 2020
public class TransactionException extends Exception
{
. . .
}
Constructors from Superclass
• Eclipse gives some assistance with overriding constructors
• In the “New Java Class” dialog, if the “Constructors from superclass” check box is checked, then stubs of all the inherited constructors will be added to the newly created class.
Foundational Java 2nd edition by David Parsons © 2020
Throwing a Custom Exception
• Throwing a custom exception is just like throwing one from a Java Exception class
• In this example the ‘debit’ method throws a TransactionException
Foundational Java 2nd edition by David Parsons © 2020
public void debit(double amount) throws TransactionException
{
if(this.getBalance() < amount)
{
throw new TransactionException("insufficient funds");
}
// if OK then carry on
}
‘finally’ Blocks
• The finally block can follow ‘try’ or ‘catch’
• The finally block is optional, but when present, its code is always executed.
Foundational Java 2nd edition by David Parsons © 2020
try
{
// some code that we try to execute
}
catch (Exception ex)
{
// some code that will only be executed if the exception is thrown
}
finally
{
// some code that will always be executed,
// whatever happens in the ‘try’ and ‘catch’ blocks
}
try-with-resources
• “try-with-resources” can be used where resources have been opened and need to be closed regardless of whether an exception has been thrown
• A “try” block followed by code that opens some kind of resource such as a file or a database connection
• The resource that is opened can be any object that implements java.lang.AutoCloseable
• “try-with-resources” will automatically try to close the resource if an exception is thrown
Foundational Java 2nd edition by David Parsons © 2020
try(code to open resource here) {
//…
}
// no requirement for “catch” or “finally” – these are optional
Exercise 9.3
• Create a BankAccount class with a ‘balance’ field and associated ‘getters’ and ‘setters’
• Implement the ‘debit’ method to either debit the balance or throw a TransactionException
• Write a ‘main’ method to test your debit method. In a ‘try’ block, set the original balance of the account, then make a number of debits until the exception is thrown
• Add a ‘finally’ block after your ‘try-catch’ block that simply displays a message on the console, demonstrating that the ‘finally’ block will be executed even if an exception has been thrown
Foundational Java 2nd edition by David Parsons © 2020
Re-throwing Custom Exceptions
• We can throw a different exception to the original one
Foundational Java 2nd edition by David Parsons © 2020
try {
courses[courseCount] = new Course(name, days, cost);
courseCount++;
}
catch(IllegalArgumentException e) {
throw new CourseConstructorException("Duration must be 1-10 days", e);
}
catch(NullPointerException e) {
throw new CourseConstructorException("Course name cannot be null", e);
}
catch(ArrayIndexOutOfBoundsException e) {
throw new CourseConstructorException("Cannot add any more courses", e);
}
Exercise 9.4
• In Chapter 7 we created a Module class
– A Course holds a reference to an array of Module objects
• Potentially, this could lead to an ArrayIndexOutOf-BoundsException
• Add some exception handling code to the Course class so that attempting to add too many modules to a course will not cause the program to crash.
• Write a test “main” method to test out your exception handling code.
Foundational Java 2nd edition by David Parsons © 2020
Exercise 9.5
• Create an Exception class called “ModuleException” as a subclass of Exception.
• Integrate this into your answer to Exercise 9.4 so that the ArrayIndexOutOf-BoundsException gets re-thrown as a ModuleException.
Foundational Java 2nd edition by David Parsons © 2020
Optional: An Alternative To “null”
• Dealing with NullPointerExceptions can lead to complex coding
• For example, this code checks the names of employees in a department
• If the first middle name of an employee is null, a NullPointerException will propagate up through the layers of objects
• Using the java.util.Optional class makes the code simpler because it removes the need for the conditional statement that checks for a null reference
Foundational Java 2nd edition by David Parsons © 2020
String nextMiddleName = getDepartment(dept).getEmployees().next().getMiddleNames().getFirst();
“Employee” Class with “Optional” Field
• Here is part of a simple Employee class
• “MiddleName” is an “Optional” object
• “Optional<String>” means that this Optional object is of type String.
Foundational Java 2nd edition by David Parsons © 2020
public class Employee
{
private Optional<String> middleName;
“Optional” Methods
• The “getMiddleName” method uses the “orElse” method to set up an alternate value if “middleName” is “null”. In this case it returns a String containing a space.
• The “setMiddleName” method sets the value of the Optional to be “ofNullable”. This method allows the value of the Optional to be “null”.
Foundational Java 2nd edition by David Parsons © 2020
public String getMiddleName()
{
return middleName.orElse(" ");
}
public void setMiddleName(String middleName)
{
this.middleName = Optional.ofNullable(middleName);
}
Code Example
• In this example, no exception is thrown
• The middle name for the second employee will be replaced with a space by the Optional object
• All we will see in the consoled is the “L”, the first letter of the first employee’s middle name.
Foundational Java 2nd edition by David Parsons © 2020
Department dept = new Department();
dept.addEmployee(new Employee("Martin","Luther","King"));
dept.addEmployee(new Employee("Malcolm",null,"X"));
for(Employee e1 : dept.getEmployees())
{
char midInitial = e1.getMiddleName().charAt(0);
System.out.println(midInitial);
}
Summary
• This chapter has explored various aspects of exception handling in Java, including the keywords “throws,” “try,” “catch,” “finally,” and “throw”
• The exception hierarchy divides exception types into checked exceptions, which are checked by the compiler, and unchecked exceptions.
• The Java runtime includes many exception types, but we can also create our own subclasses of Exception to represent custom exceptions
• “try-with-resources” can be used when opening resources such as files or database connections
• The “Optional” class can limit the likelihood of NullPointerExceptions being thrown by an application.
Foundational Java 2nd edition by David Parsons © 2020