Chapter:Exceptions - Rules and syntax

From Juneday education
Jump to: navigation, search

Meta information about this chapter (Short)

Expand using link to the right to see the full content.

Introduction

This chapter covers the rules and syntax not quite covered in the previous chapters on exceptions.

Purpose

The purpose of this chapter is to give the students a walk through of most of the rules concerning exceptions in Java and some more syntax.

Goal

After this chapter, the student shall understand:

  • That you can have more than one catch following a try
    • That this is preferred, since you typically want to treat different kinds of exceptions differently!
  • That you can group exceptions with a similar solution/measure in one single catch, separated with pipe
    • This is just syntactic sugar for the case where you actually have the same treatment for various exceptions
  • An overriding method must throw the same exceptions as the super class version, but may throw subtypes of the exception
    • But it is never allowed to throw superclasses of the exception in the method of the superclass
    • This rule is so that we can program to a supertype and still be able to handle the exceptions declared to be thrown by the superclass method, even if these methods are overridden
  • What try-with-resources is and basically how it works
    • This will be useful if the student takes another class for more advanced topics like JDBC, I/O etc

Instructions to the teacher

Common problems

Explaining inheritance is always a challenge. Spend some time to explain why an overriding method can't throw "more" than the method of the super class, and re-visit the concept of programming to a super type and show what the consequences would be if this were allowed in Java.

Exceptions: Some rules and syntax

Finally (no pun intended), we'll give you some additional rules and syntax for working with exceptions. There's a whole lot more to learn if you are really interested in the links section at the end of the page as usual.

You can have more than one catch-block, each catching a different family of exceptions. This is encouraged, because if there can be more than one unrelated exception in the try-block, there is probably different ways to handle them. So rather than catching a broad superclass type exception, you are encouraged to write a catch-block for each type of exception which might occur in the try-block (if more than one).

try{
  // some code which might throw IOException
  // some code which might throw NumberFormatException
}catch(IOException ioe){
  // Handle I/O problem
}catch(NumberFormatException nfe){
  // Handle the fact that some text couldn’t be converted to a number
}finally{
  // If you need to, you can always add a finally clause
}

A longer example could be:

public class Divider {
  public static void main(String[] args) {
    try {
      String firstNumber = args[0];
      String secondNumber = args[1];
      int a = Integer.parseInt(firstNumber);
      int b = Integer.parseInt(secondNumber);
      int q = a / b;
      System.out.println("Result: " + a + " / " + b + " = " + q);
    } catch (ArrayIndexOutOfBoundsException ai) {
      System.err.println("You need to give two arguments.");
    } catch (NumberFormatException nfe) {
      System.err.println("Not a number: " + nfe.getMessage());
    } catch (ArithmeticException ae) {
      System.err.println("Arithmetic exception: " + ae);
    }
  }
}

Example runs:

$ javac Divider.java && java Divider
You need to give two arguments.
$ javac Divider.java && java Divider 10 three
Not a number: For input string: "three"
$ javac Divider.java && java Divider 10 0
Arithmetic exception: java.lang.ArithmeticException: / by zero
$ javac Divider.java && java Divider 10 3
Result: 10 / 3 = 3

Sometimes, however, you have the same solution to more than one type of exception. Rather than repeating yourself, you can in such cases catch a list of exception types, separated by pipe (the vertical bar | ):

try{
  //Some code which can throw an SQLException
  //Some code which can throw an IOException
}catch(SQLException|IOException e){
  // Code which can handle both cases
  // (n.b. they should have the same solution if you do this!)
}

There are some rules when it comes to inheritance and overriding methods. If you extend a class and override a method from the superclass, then you cannot add exceptions to the method if none are declared to be thrown in the superclass version. And you cannot say that your overriding version of the method throws an exception which is broader than the exceptions that the superclass version throws. So you cannot declare that the overriding method throws an exception which is a superclass to the exception the superclass version throws.

The reason for this rule is quite simple and logical. Client code can have a reference to a superclass type and call some method. It must then know that the exceptions which are declared to be thrown by this superclass is all that it needs to write a handler for (or declare that it throws). It is quite common that the client code has a reference to some superclass and doesn't know what class the actual object the reference refers to is. So the compiler enforces that the object won't throw any broader exception than those of the method as declared in the superclass.

The last thing we'd like to tell you is a construct called try-with-resources. Please refer to the section above where we talked about the finally clause. One typical use for the finally clause is to close resources opened in the try-block. Closing a resource in the finally block, guarantees that it will be closed whether or not any exception was thrown.

The try-with-resources construct takes advantage of two interfaces, AutoCloseable and its subinterface Closeable. The AutoCloseable interface declares one single method, close(). Many of the classes dealing with resources (files, streams, connections) implement the AutoCloseable interface (or Closeable). Those who does, thus guarantees that they have a close() method which will close the resource.

The try-with-resources construct lets us skip the finally-block for such objects who have a close() method. The syntax is to put a pair of parentheses after the try and initialize the resource inside it. This will guarantee that the close() method is called, regardless of any exceptions (just like the case with the finally block). Here's a functioning program which uses this construct. The program reads the first line of text in its own source code and prints it to the standard out. It opens the source code file (the resource) and the try-with-resources construct guarantees that the file is closed, whether an exception happened or not.

import java.io.*;
public class Resources{
  public static void main(String[] args){
	String firstLine = getFirstLine();
	System.out.println("First line of this file: " + firstLine);
  }
  static String getFirstLine(){
	try( BufferedReader in = new BufferedReader
	      (new FileReader("Resources.java")) ){
	  return in.readLine(); // use the resource
	}catch(IOException e){
	  System.err.println("Couldn't open Resources.java");
	  return null;
	}
  }
}

Running the program will produce the following:

$ javac Resources.java && java Resources
First line of this file: import java.io.*;

Chapters on the topic of Exceptions

Here are the chapters on the topic of Exceptions, so that you can check your progress:

Videos

English videos

Swedish videos

Links

Source code

  • Code from presentations and solutions (github)

External links

Where to go next

The next page has exercises for this chapter (if any): Exceptions_-_Rules_and_syntax_-_Exercises

« PreviousBook TOCNext »