First Part

Learning objectives

  • Understanding the difference between checked and unchecked exception
  • Defining the use of the try, catch, finally, throw and throws keywords
  • Implementing your own exception

Exceptions:

Exceptions are “problems” that occurs during the execution of a program. When an exception occurs, the normal flow of the program is interrupted, and if the exception is unhandled, the program will terminate.

Some exception can be caused by user error, others by programming error or even by failure of some physical resource.

Some examples of sources of exceptions are:

  • A user enters an invalid data
  • A file that needs to be opened cannot be found

There are two categories of exceptions: Checked and Unchecked exceptions.

Checked exceptions:

A checked exception is an exception that cannot be ignored and needs to be explicitly handled by the programmer, we will see how later. These exceptions are checked at compile time.

A common example of a checked exception is the FileNotFoundException. When using a FileReader ,(We will explore FileReader further in another lab; they essentially allow you to read the content of a file) if the file specified in the constructor of the FileReader does not exist, then FileNotFoundException occurs.

import java.io.File;
import java.io.FileReader;

public class FilenotFound_Demo {

   public static void main(String args[]) {		
      readFile();
   }
   public static void readFile(){
      File file = new File("E://file.txt");
      FileReader fr = new FileReader(file); 

   }
}
  

If you try to compile this code, you will get this message:

FilenotFound_Demo.java:11: error: unreported exception FileNotFoundException; must be caught or declared to be thrown
      FileReader fr = new FileReader(file);
                      ^
1 error
  

Unchecked exceptions:

Unchecked exceptions are exceptions that do not need to be explicitly handled by programmers. They include bugs, logical error and improper use of an API.

Here is a hierarchy exception:

Hiarchy of exception calsses in Java Figure 1 : Hiarchy of exception calsses in Java

The Java exceptions under Error and RuntimeException are exceptions that are not checked at compile time.

An example of unchecked exception you might be familiar with is the ArrayIndexOutOfBoundsException that occurs when you try to access the index of an array that is not within the boundary of the array.

public class ArrayOutOfBound_Demo {

   public static void main(String args[]) {		
      createArray();
   }
   public static void createArray(){
      int[] myArray=new int[2];
      myArray[2]=1;

   }
}
  

If you try to compile this code it will do so without errors. However, when you try to run the code, you will get this message:

Exception in thread "main" java.lang.ArrayIndexOutOfBoundsException: 2
        at ArrayOutOfBound_Demo.createArray(ArrayOutOfBound_Demo.java:8)
        at ArrayOutOfBound_Demo.main(ArrayOutOfBound_Demo.java:4)
  

Throw and Throws:

If a method does not handle a checked exception, it needs to declare at the end of its definition that it throws that exception. You can also throw an exception, either by creating a new exception or by throwing an exception that was just caught, by using the throw keyword.

It is important that you remember:

  • Keyword throws: in the method declaration, indicates what checked exception can be thrown by that method, and, optionally, some or all of the unchecked exceptions that can be thrown by that method.
  • Keyword throw: use to throw an exception, whether checked or unchecked

Throwing an exception means that the exception is send to the caller of this method.

A method can have multiple throws; they need to be separated with comas like this:


public void myMethod() throws ExceptionA, ExceptionB{
//some code
}

Try, Catch and Finally:

Any code that is likely to cause an exception should be surrounded by a try block. A try block should be followed by a catch block. If an exception occurs during the execution of the try block and the exception is thrown, the exception may then be caught by a catch block associated to that exception.

A catch statement involves declaring the type of exception that we are trying to catch. If the exception that we are trying to catch is thrown, the code inside the catch block will be executed. Catch blocks always follow a try block, there can be one or multiple catch blocks but only one will be executed.

Important observation: only the first catch statement encountered that is valid will be executed, it is therefore important to always put the catch statements in order from the most specific to the least.

A finally statement is a block of code that will always be executed after a try-catch whether or not an exception was thrown and or caught.

In this example, we try to run the method throwingMethod, which throws IOException. When the exception is thrown, is it caught in the main method by the catch statement. Since the IOException is a checked exception, the method signature for throwingMethod has to finish with the keyword throws and the type of exception (IOException)

import java.io.IOException;
public class TryCatchThrow_Demo {

   public static void main(String args[]) {		
      try{
	System.out.println("start the try block");
	throwingMethod();
      }
      catch(IOException e){
	System.out.println("The exception is caught");
      }
   }

   public static void throwingMethod() throws IOException{
	//some code...
      System.out.println("Running the method throwingMethod");
      throw new IOException();
   }
}
  

When running this code you will see:

start the try block
Running the method throwingMethod
The exception is caught
  

Now let's update the ArrayOutOfBound_Demo shown before, this new version has been modified to handle the exception.You can see that we do not need to use the throws keyword because it is an unchecked exception. We also have 2 catch statements, one to handle a specific exception ArrayIndexOutOfBoundsException and the other to catch and react in a default manner to any other exceptions that might be thrown. catch(Exception e) will catch every exception as they are all child of Exception. We also have a finally statement that will always be executed.

Note: the most specific exception has to be placed first

public class ArrayOutOfBound2_Demo {

   public static void main(String args[]) {		
      try{
	System.out.println("start the try block");
	createArray();
      }
      catch(ArrayIndexOutOfBoundsException e){
	System.out.println("The specific exception is caught");
      }
      catch(Exception e){
	System.out.println("the generic Exception is caught");
      }     
      finally{
	System.out.println("Executing the finally block");
      }
   }
   public static void createArray(){
      int[] myArray=new int[2];
      myArray[2]=1;
      
   }
}
  

When running this code you will see:

start the try block
The specific exception is caught
Executing the finally block
  

Try to inverse the order of the catch statements to see what happens!

Exercise 1

Files to submit:

Complete the following code so that it compiles and that you catch each type of exception thrown by the method throwException and print out the type of exception as well as the exceptionNumber that was randomly generated and then return the name of the exception. The default value to be returned is "NoException" (if none of the specified exceptions have been thrown).

You can use the starter code from Exercise1.java. This file will be part of your submission.

import java.io.IOException;

public class Exercise1 {

    public static void throwException(int exceptionNumber) throws Exception{
        if(exceptionNumber==1){
            throw new Exception();
        }
        if(exceptionNumber==2){
            throw new ArrayIndexOutOfBoundsException();
        }
        if(exceptionNumber==3){
            throw new IOException();
        }
        if(exceptionNumber==4){
            throw new IllegalArgumentException();
        }
        if(exceptionNumber==5){
            throw new NullPointerException();
        }
    }

    /*
        Returns the name of the exception thrown by the method throwException.
        Method that handles the exceptions thrown by the throwException method.
        
        @param exceptionNumber
        @return The exception name or "NoException" if no exception was caught.
     */
    public static String catchException(int exceptionNumber){
        try{
            throwException(exceptionNumber);
        }
        // YOUR CODE HERE
        return "NoException";
    }

    public static void main(String[] args) {
        int exceptionNumber=(int)(Math.random()*5) + 1;
        String exceptionName = catchException(exceptionNumber);
        System.out.println("Exception number: " + exceptionNumber);
        System.out.println("Exception name: " + exceptionName);
    }

}
  

Running the code a few times should give a result similar to this:

>java Exercise1
The exception type is: ArrayIndexOutOfBoundsException, the exceptionNumber is: 2
Exception number: 2
Exception name: ArrayIndexOutOfBoundsException

>java Exercise1
The exception type is: NullPointerException, the exceptionNumber is: 5
Exception number: 5
Exception name: NullPointerException

>java Exercise1
The exception type is: ArrayIndexOutOfBoundsException, the exceptionNumber is: 2
Exception number: 2
Exception name: ArrayIndexOutOfBoundsException

>java Exercise1
The exception type is: Exception, the exceptionNumber is: 1
Exception number: 1
Exception name: Exception
 

Creating exceptions:

Exceptions are classes; they contain methods and fields just like any other class. All exception needs to be a child of Exception. To create a checked exception you need to extend the class Exception, for unchecked exception you need to extend the class RuntimeException.

For example, we might want to throw an exception if a given number is negative. We would then create the class NegativeNumberException.

public class NegativeNumberException extends IllegalArgumentException{
	private int number;
	public NegativeNumberException(int number){
		super("Cannot us a negative number: "+ number);
        this.number=number;
	}
	public int getNumber(){
		return number;
	}   
}
  

Note : The call to the super constructor will allow the default method getMethod to return the String given as parameter. There are many other method inherited from the class Exception including toString

That new exception we created can now be used like a regular exception:

public class NegativeNumberException_Demo{
   

   public static void main(String args[]) {		
      try{
	printSquareRoot(4);
	printSquareRoot(-1);
      }
      catch(NegativeNumberException e){
      System.out.println(e.getMessage());
	  System.out.println("the number " + e.getNumber() + " is invalid");
      }
      
   }
   public static void printSquareRoot(int x) throws NegativeNumberException{
	if(x<0){
	   throw new NegativeNumberException(x);
	}      

	System.out.println("the square root of " + x + " is "+Math.sqrt(x));
      
   }
}
  

When running this code you will see:

the square root of 4 is 2.0
Cannot us a negative number: -1
the number -1 is invalid
  

Exercise 2:

Files to submit:
  • Account.java
  • NotEnoughMoneyException.java

For this exercise, you will need to create a class named Account, this class represents a bank account. This class has a constructor that sets the variable balance to 0. It also has the methods: deposit that takes a double and add that number to the balance, withdraw that takes a double and removes that amount from the balance (both method should print the new balance), and getBalance (the getter method for balance). However, if the amount to withdraw is higher than the balance, you need to throw the NotEnoughMoneyException. You will need to create the NotEnoughMoneyException, it extends IllegalStateException. It has a method getAmount that returns the amount that was requested, getBalance that returns the balance at the time the exception was created and getMissingAmount that returns the amount of money needed to withdraw the requested amount. The exception should also invoke it’s super constructor so that the method getMessage indicates that the amount cannot be withdrawn.

For this exercise, you have to submit the files: Account.java and NotEnoughMoneyException.java.

public class Exercise2{
   

   public static void main(String args[]) {
	try{
	   Account myAccount=new Account();
	   myAccount.deposit(600);
	   myAccount.witdraw(300);
	   myAccount.witdraw(400);
	}
	catch(NotEnoughMoneyException e){
	   System.out.println(e.getMessage());
	   System.out.println("You are missing " + e.getMissingAmount() + "$");
	}
   }

}	
  

When running the code in Exercise2.java you should get an output similar to this:

new balance=600.0$
new balance=300.0$
you have not enought money to witdraw 400.0$
You are missing 100.0$
  

 

Second Part

Learning objectives

  • Throwing and catching Java exceptions
  • Extending the stack and dictionary implementations with Exception Handling.

Exercises

Files to submit:

ArrayStack

Add to the implementations of ArrayStack from the previous laboratory, Exception Handling for the following cases:
  • EmptyStackException (from java.util) for the methods peek and pop when the stack is empty;
  • FullStackException (create a new custom checked exception) for the method push when the stack is full.

DynamicArrayStack

Add to the implementations of DynamicArrayStack from the previous laboratory, Exception Handling for the methods peek and pop (using EmptyStackException from java.util).

Note: You can use as starter code the implementation from the previous laboratory for ArrayStack.java, DynamicArrayStack.java, and Stack.java.

Dictionary

Edit the Dictionary class to include exceptions so that when you run the class TestL7Dictionary, all tests pass. For example, the method put in the class Dictionary should include the following exception handling:

public void put(String key, Token value) {

	if (key == null || value == null) {
		throw new NullPointerException("key or value is null");
	}

	if (count == elems.length) {
		increaseCapacity();
	}

	// Similarly to the array-based implementation
	// of a stack, I am adding elements at the end
	elems[count] = new Pair(key, value);
	count++;
}

 

Table of Contents

Third Part

Create and submit a zip folder (1 point)

Instructions

  • Create a directory lab7_123456, where 123456 is replaced by your student number.
  • Inside this directory, place the 11 .java files for this lab. Include only your source code. Do not include any class files or any other files; only Java files.
  • In this directory, also create a file README.txt which is a text file containing your name, student number and a brief description of the content of the directory:
    
    Student name: Jane Doe
    Student number: 123456
    Course code: ITI1121
    Lab section: B-2
    
    This archive contains the 11 files of lab 7, that is, this file (README.txt),
    plus Exercise1.java, Account.java, NotEnoughMoneyException.java, Stack.java, ArrayStack.java, DynamicArrayStack.java, FullStackException.java, Map.java, Dictionary.java, Pair.java.
    
                        
  • Create a zip file lab7_123456.zip containing the directory lab7_123456 and all of the java files.
  • Verify that your archive is correct by uncompressing it somewhere and making sure that all the files and the directory structure are there.
  • Submit the archive using https://uottawa.brightspace.com/

Important remarks!

We are using automated scripts to test and grade your lab submission. Therefore, you must follow these instructions exactly. In particular:
  • Your naming of all the files and methods must be exact. Copy/paste the starter code provided during the lab to avoid problems.
  • You MUST submit a .zip; not individual files; not a .rar, not a .7z, or anything else.
  • All the required java files must be present and must compile (that is, running javac *.java must not produce any errors), even if you were unable to complete an exercise.
  • Even if you could not solve an exercise's solution completely, you have to hand in a file with the methods that compiles (you can put "return 0" if you gave up).
  • Your submission is due by Tuesday 11:59PM the week after the lab. You can submit as often as you want before then, but not after. Only your last submission will be considered.

JUnits

To help you making sure that your code is correct, we have prepared some JUnit tests.

Resources

Table of Contents