C1: Exception Handling

CPSC 210

Learning Goals

  • To determine whether or not a method’s specification is robust
  • To design robust method specifications using exception handling
  • To determine the flow-of-control when a method throws an exception

Why Exceptions?

// REQUIRES: numItems > 0
// MODIFIES: this
// EFFECTS: adds numItems to quantity of
//  items purchased on this line item
public void addQuantity(int numItems) {
  this.quantity += numItems;
}

Let's break this!!

lineItem.addQuantity(-1);

What do we want instead?

My Dear Caller - I see you passed in a 
negative number to our addQuantity method. 
This is not supported. We kindly ask you to 
enter a positive number.

Method is not robust:
REQUIRES clause excludes values

Why Exceptions? (2)

  • Especially for public methods, we usually cannot rely on values adhering to what we require!
  • We need to be prepared for exceptional cases!
// MODIFIES: this
// EFFECTS: adds numItems to quantity of
//  items purchased on this line item
//  IF numItems < 1
//	  throws IllegalNumberException
public void addQuantity(int numItems) 
	throws IllegalNumberException {   
    
  if (numItems < 1) {
    throw new IllegalNumberException();
  }
  this.quantity += numItems;
}

Method is robust: specifies behaviour for ALL inputs

Exceptions

public class IllegalNumberException extends Exception {
	
}
  • Exceptions are thrown when a problem occurs
  • Exception class is part of the Java library
    • Any exception is an instance of that class or a subclass
  • The caller will have the choice to:
    • catch  the exception and address the problem
    • propagate (= throw) the exception further to its caller

Exceptions (2)

  • There are two kinds of exceptions:
    • checked
    • unchecked
  • Today we focus only on checked exceptions (don’t worry about the difference for now)

Call Stack & Throwing Exceptions

catch?

catch?

catch?

LineItem
addQuantity

GroceryBill
addPurchase

GroceryApp

main

Catching Exceptions

catch?

catch?

public void addPurchase(GroceryItem item, int quantity) {
  // ...
  try {
    entry.addQuantity(quantity);
  } catch (IllegalNumberException e) {
    System.err.println("Quantity could not be added: " + quantity);
  }
  // ...	
}

LineItem
addQuantity

GroceryBill
addPurchase

GroceryApp

main

The Finally Keyword

  • Sometimes we want to execute code no matter if there was an exception caught or not
public void addPurchase(GroceryItem item, int quantity) {
  // ...
  try {
    entry.addQuantity(quantity);
  } catch (IllegalNumberException e) {
    System.err.println("Quantity could not be added: " + quantity);
  } finally {
    System.out.println("Your quantity might have been added. Not sure.");
  }
  // ...	
}

The Finally Keyword (2)

  • A more real-life example
public void writeStringToFile(String string) {
  FileWriter fw = new FileWriter("OutputFile.txt")
  PrintWriter pw = new PrintWriter(fw);
  try {
    pw.println(string);
  } catch (IOException e) {
    System.out.println("Could not write to file");
  } finally {
    pw.close();
  }
}
  • We want to close our PrintWriter object no matter if the write process was successful or not

Lecture Ticket Review

Extra: Git Branching

Branch: main

Branch: mybranch

Create
Branch

Merge
Branch

Commits

Lecture Ticket

Lecture Lab

C1: Exception Handling

The End - Thank You!

Extra Slides...

a try/catch/finally statement...

  • normally: executes its try block and then finishes normally
  • must have at least one clause besides try (a catch or finally)
  • may have any number of catches and up to one finally
  • at the end of its normal execution, continues to the next statement (like almost any statement except throw/return)
  • catches exceptions under some circumstances:
    • if its try block ends abnormally with an exception object e 
      • and it has a catch block like: catch (ExcType e2)
      • where e is a subtype of ExcType
    • then it finds the first such block
      • and makes e the value of e2 
      • and executes that catch block
      • and then finishes the whole try/catch normally
  • just before the ending execution (normally or abnormally) executes its finally block (if any) and then resumes ending execution

Throwing Multiple Exceptions

public void addPurchase(GroceryItem item, int quantity)
	throws CouldNotAddPurchaseException {
  // ...
  try {
    entry.addQuantity(quantity);
  } catch (IllegalNumberException e) {
    System.err.println("Quantity could not be added: " + quantity);
    throw new CouldNotAddPurchaseException();
  } // POSSIBLY MORE CATCH CLAUSES TO CATCH OTHER EXCEPTIONS
  // ...	
}
  • We can catch one exception and throw another...
  • ...this way, different methods in the call stack can treat errors in their own way...
GroceryBill bill = new GroceryBill();
try {
  bill.addPurchase(milk, 2);
} catch (CouldNotAddPurchaseException e) {
  System.err.println("At least one purchase could not be added");
}
Made with Slides.com