Exception

Advanced Programming

SUT • Spring 2019

Contents

  • Error handling mechanisms

  • Exception handling framework

  • Benefits of exception handling framework

  • Exception handling in Java

Exception Handling

Example

public class Main {
    public static Integer getYear(String day) {
        String yearString = day.substring(0, 4);
        int year = Integer.parseInt(yearString);
        return year;
    }


    public static void main(String[] args) {
        String day = "2010/11/29";
        Integer year = getYear(day);
        System.out.println(year);
    }
}

Exceptions

  • What is wrong with it?

  • What if day parameter is not a day representation?

    • day = “salam!”

  • What if day parameter is malformed?

    • Day = “29 Nov 2010”

  • What if day parameter is empty?

    • String s = "";

  • What if day parameter is null?

    • These occasions are called Exception

Handling Exceptions

  • What to do with exceptions?

  •  

  • Exit the program

  • Printing the error on console

  • Returning a special value

    • e.g. -1

Important Note

  • Sometimes the method can’t handle the exception effectively

  • What should a method do when an exception occurs?

  • Exit the program?

    • Suppose you are in a desktop application

      • Excel, Word, a game, …

  • Print on console?

    • edu site

    • A game

Returning a Special Value

  • We can return a special value to report an exception

  • E.g.

    • return null;

    • return -1;

    • return 0;

    • return “”;

  • Why not?

Why not?

  • There is no special value

  • There are many exceptions

  • Ambiguity

    • Need for documentation

  • Combination of program code and exception code

There is no special value

public class Main {
    public static int minimum(int[] nums) {
        int m = Integer.MAX_VALUE;
        for (int i : nums) {
            m = Math.min(m, i);
        }
        return m;
    }
}

int[] array = {1,2,-1};
int minimumFound = minimum(array);

Exception Handling

  • Exception Handling is a framework for handling exceptions

    • ;-)

  • It simplifies code

    • Separates business code and exception code

What is an Exception?

  • Exceptional event

  • Error that occurs during runtime

  • Cause normal program flow to be disrupted

  • Examples

    • Divide by zero errors

    • Accessing the elements of an array beyond its range

    • Invalid input

    • Hard disk crash

    • Opening a non-existent file

    • Heap memory exhausted

Default Exception Handling

  • Provided by Java runtime

  • Prints out exception description

  • Prints the stack trace

    • Hierarchy of methods where the exception occurred

  • Causes the program to terminate

Example

class DivByZero {
    public static void main(String a[]) {
	System.out.println(3/0);
    }
}

Exception in thread "main" java.lang.ArithmeticException: 
/ by zero
at exception.Test2.main(Test2.java:19)
  • Note: Exception is a runtime concept
  • This code has no syntax error (No compile-time error)

What Happens When an Exception Occurs?

  • When an exception occurs within a method

  • The method creates an exception object

  • And hands it off to the runtime system

    • This job is called “throwing an exception

  • Exception object contains

    • information about the error

    • its type

    • the state of the program when the error occurred

      • Exception line of code

What Happens When an Exception Occurs (2)?

  • The run time system searches the call stack for a method that contains an exception handler

  • When an appropriate handler is found

    • The runtime system passes the exception to the handler

    • The exception handler catches the exception

  • What if the runtime system can not find an exception handler?

    • Uses the default exception handler

Example

Example

Exception Handling in Java

import java.util.Scanner;

public class Year {
    public static Integer getYear(String day) {
        String yearString = day.substring(0, 4);
        return Integer.parseInt(yearString);
    }

    public static void main(String[] args) {
        Scanner scanner = new Scanner(System.in);
        System.out.print("Enter a well-formed date: ");
        String date = scanner.next();
        Integer year = getYear(date);
        System.out.println(year);
    }
}

Example

public class Year {
    public static Integer getYearWithException(String day) throws Exception {
        if (day == null)
            throw new Exception("null value");
        if (day.length() == 0)
            throw new Exception("empty value");
        if (!matchesDateFormat(day))
            throw new Exception("malformed value");
        String yearString = day.substring(0, 4);
        int year = Integer.parseInt(yearString);
        return year;
    }

    private static boolean matchesDateFormat(String input) {
        return input.matches("\\d\\d\\d\\d/\\d\\d/\\d\\d");
    }
}

main

public class Year {
    public static void main(String[] args) {
        Scanner scanner = new Scanner(System.in);
        boolean ok = false;
        while (ok == false) {
            System.out.print("Enter a well-formed date: ");
            String date = scanner.next();
            try {
                Integer year = getYear(date);
                System.out.println(year);
                ok = true;
            } catch (Exception e) {
                System.out.println(e.getMessage());
            }
        }
    }
}

Exception Handling Keywords

  • throw

    • throws a new exception

  • throws

    • Declares exception throw

    • If a method may throw an exception, it should declare it

  • try

    • Start a block with exception handling

  • catch

    • Catch the exception

Benefits of Exception Handling Framework

  • Separating Error-Handling code from “regular” business logic code

  • Propagating errors up the call stack

  • Grouping and differentiating error types

Example

public class Test {
    public static void main(String[] args){
        try {
            Scanner scanner = new Scanner(System.in);
            int first = scanner.nextInt();
            int second = scanner.nextInt();
            int div = division(first, second);
            System.out.println(div);            
        } catch (Exception e) {
            System.out.println(e.getMessage());
        }
    }
    

    private static int division(int first, int second) throws Exception{
        if(second == 0)
            throw new Exception("OOPS! Makhraj Sefre!");
        return first/second;
    }
}

Separating Error-Handling Code

  • Consider pseudocode method

  • It reads an entire file into memory

readFile {
    open the file;
    determine its size;
    allocate that much memory;
    read the file into memory;
    close the file;
}
errorCodeType readFile {
    initialize errorCode = 0;
    
    open the file;
    if(theFileIsOpen) {
        determine the length of the file;
        if(gotTheFileLength) {
            allocate that much memory;
            if(gotEnoughMemory) {
                read file int memory;    
                if(readFailed) {
                    errorCode = -1;
                }
            } else {
                errorCode = -2;
            }
        } else {
            errorCode = -3;
        }
        close the file;
        if (theFileDidntClose && errorCode == 0) {
            errorCode = -4;
        } else {
            errorCode = errorCode and -4;
        }
    } else {
        errorCode = -5;
    }
    return errorCode;
}

With Exception
Handling Framework

readFile {
    try {
        open the file;
        determine its size;
        allocate that much memory;
        read the file into memory;
        close the file;
    } catch (fileOpenFailed) {
        doSomething;
    } catch (sizeDeterminationFailed) {
        doSomething;
    } catch (MemoryAllacationFailed) {
        doSomething;
    } catch (readFailed) {
        doSomething;
    } catch (fileCloseFailed) {
        doSomething;
    }
}

Note

  • You should still write code for detecting, reporting and handling exceptions

  • Exception handling framework is not responsible for these jobs!

  • It only helps you organize the work more effectively

Propagating Errors Up the Call Stack

  • Traditional approach

    • Each method should explicitly forward the exception

    • Use a special return code

    • Using return type for reporting exceptions

      • Smells bad!

  • New approach

    • Automatic

    • Beautiful!

Grouping and Differentiating Error Types

  • All exceptions thrown within a program are objects

  • The grouping or categorizing of exceptions is a natural outcome of the class hierarchy

public class Test {
    public static void main(String[] args){
        try {
            Scanner scanner = new Scanner(System.in);
            int first = scanner.nextInt();
            int second = scanner.nextInt();
            int div = division(first, second);
            System.out.println(div);            
        } catch (IOException e) {
            System.out.println(e.getMessage());
        } catch (ArithmeticException e) {
            System.out.println(e.getMessage());
        }
    }
    
    private static int readInt() throws IOException {
        String str = scanner.next();
        if(str.matches("[\\d]+")){
            return Integer.parseInt(str);
        }
        throw new IOException("Bad input");
    }


    private static int division(int first, int second) throws ArithmeticException{
        if(second == 0)
            throw new ArithmeticException("OOPS! Makhraj Sefre!");
        return first/second;
    }
}

Example

public class MultipleCatch {
    public static void main(String args[]) {
        try {
            int den = Integer.parseInt(args[0]);
            System.out.println(3 / den);
        } catch (ArithmeticException exc) {
            System.out.println("Divisor was 0.");
        } catch (ArrayIndexOutOfBoundsException exc2) {
            System.out.println("Missing argument.");
        }
        System.out.println("After exception.");
    }
}

Nested Tries

public class NestedTryDemo {
    public static void main(String args[]) {
        try {
            int a = Integer.parseInt(args[0]);
            try {
                int b = Integer.parseInt(args[1]);
                System.out.println(a / b);
            } catch (ArithmeticException e) {
                System.out.println("Div by zero error !");
            }
        } catch (ArrayIndexOutOfBoundsException e) {
            System.out.println("Need 2parameters !");
        }
    }
}

Bad Use of Exceptions

  • Don’t Use Exception instead of If-else

  • Use exceptions for exceptions!

Writing Your Own Exceptions

  • Your class should extend Exception class

  • Exception subclasses could be thrown and caught

  • Steps to follow

    • Create a class that extends Exception class

    • Customize the class

      • Members and constructors may be added to the class

  • Exception classes are usually simple classes

    • With no (or few) methods and properties

Example

public class HateStringExp extends Exception {
        /* some code */

    public static void main(String[] args) {
        String input = "invalid input";
        try {
            if (input.equals("invalid input")) {
                throw new HateStringExp();
            }
            System.out.println("Accept string.");
        } catch (HateStringExp e) {
            System.out.println("Hate string!");
        }
    }
}

getYear(), revisited

public class Year {
    public static Integer getYear(String day)
            throws Exception {
        if (day == null)
            throw new NullPointerException();
        if (day.length() == 0)
            throw new EmptyValueException();
        if (!matchesDateFormat(day))
            throw new MalformedValueException();
        String yearString = day.substring(0, 4);
        int year = Integer.parseInt(yearString);
        return year;
    }

    private static boolean matchesDateFormat(String input) {
        return input.matches("\\d\\d\\d\\d/\\d\\d/\\d\\d");
    }
}

Finally

try {
    //..
} catch (ExceptionType e) {
   //…
} ...
} finally {
	<code to be executed before the try block ends>
}
  • Contains the code for cleaning up after a try or a catch

Finally (2)

  • Block of code is always executed

  • Despite of different scenarios:

    • Normal completion

    • Forced exit occurs using a return, a continue or a break statement

    • Caught exception thrown

    • Exception was thrown and caught in the method

    • Uncaught exception thrown

    • Exception thrown was not specified in any catch block in the method

What is the output of:

public class Main {
    static void myMethod(int n) throws Exception {
        try {
            switch(n) {
                case 1:
                    System.out.println("1 case");
                    return;
                case 3: 
                    System.out.println("3 case");
                    throw new RuntimeException("3!");
                case 4: 
                    System.out.println("4 case");
                    throw new Exception("4!");
                case 2:
                    System.out.println("2nd case");
                // continued ...
            }
        } catch (RuntimeException e) {
            System.out.println("RuntimeException: ");
            System.out.println(e.getMessage());
        } finally {
            System.out.println("try-block entered.");
        }
    }
}

What is the output of:

class MyException extends Exception {}

public class Main {
    public static int myMethod(int n) {
       try {  
          switch (n) {
          case 1:
             System.out.println("One");
             return 1;
          case 2:
             System.out.println("Two");
             throw new MyException();
          case 3:
             System.out.println("Three");
       }
       return 4;
    } catch (Exception e) {
       System.out.println("catch");
       return 5;
    } finally {
       System.out.println("finally");
       return 6;
    }
}
int a = myMethod(1);
System.out.println("myMethod(1)=" + a);
a = myMethod(2);
System.out.println("myMethod(2)=" + a);
a = myMethod(3);
System.out.println("myMethod(3)=" + a);

Unchecked Exceptions

private static void function(String[] args) {
    int den = Integer.parseInt(args[0]);
    System.out.println(3 / den);
}

public static void main(String[] args) {
    function(args);
}
  • The method function() may throw exceptions

  • But it has not declared it with throws keyword

  • Why?

    • Because some exceptions are unchecked

    • such as ArithmeticException and ArrayIndexOutOfBoundsException

Checked and Unchecked Exceptions

  • Checked exception

    • Java compiler checks

    • the program should catch or list the occurring exception

    • If not, compiler error will occur

  • Unchecked exceptions

    • Not subject to compile-time checking for exception handling

Checked and Unchecked Exceptions

  • Built-in unchecked exception classes

    • Error

    • RuntimeException

    • Their subclasses

  • Unchecked exceptions only relax compiler

    • The runtime behavior is the same

Exception Class Hierarchy

Exception Classes and Hierarchy

  • Multiple catches should be ordered from subclass to superclass

  • Or else, Compile error: Unreachable catch block…

class MultipleCatchError {
    public static void main(String args[]){
	try {
	    int a = Integer.parseInt(args [0]);
	    int b = Integer.parseInt(args [1]);
	    System.out.println(a/b);
	} catch (ArrayIndexOutOfBoundsException e) {
	    //..
	} catch (Exception ex) {
	    //..
	}
    }
}

Exceptions & Inheritance

  • Suppose method f() overrides parent’s method

  • f() in child class can not throw more exceptions than those of f() in Parent class

    • Less or equal exceptions in throws declaration

  • These mistakes bring compiler error

  • Why?

    • Polymorphic method invocations may cause failure in catching some exceptions

Example (1)

class Parent{
    void f() {}
}

class Child extends Parent{
    void f() throws Exception {}
}
  • Result?       

    • Compiler Error

Example (2)

class Parent{
    void f() throws ArithmeticException {}
}

class Child extends Parent{
    void f() throws ArithmeticException, IOException {}
}
  • Result?       

    • Compiler Error

Example (3)

class Parent{
    void f() throws ArithmeticException {}
}

class Child extends Parent{
    void f() throws Exception {}
}
  • Result?       

    • Compiler Error

Example (4)

class Parent{
    void f() throws Exception{}
}

class Child extends Parent{
    void f() throws ArithmeticException{}
}
  • Result?       

    • No Error

Conclusion

  • f() in child class can not throw more exceptions

  • Less or equal exceptions in throws declaration

  • f() in child class can not throw more general exceptions

  • f() in child class can throw more specific exceptions

  • Reason:

    • Prevent uncaught exceptions in polymorphic invocations

class MyException extends Exception {
    public MyException(String string) {
        super(string);
    }
}

class YourException extends RuntimeException {
    public YourException(String string) {
        super(string);
    }
}

public class Sample {
    public static void main(String[] args) {
        try {
            f();
            System.out.println("After f()");
            throw new YourException("Your Exception");
        } catch (MyException e) {
            System.out.println("My Exception");
        } catch (Exception e) {
            System.out.println("Exception");
        } finally {
            System.out.println("Finally");
        }
    }

    private static void f() throws Exception {
        System.out.println("f() method");
        throw new MyException("Exception");
    }
}

Example

interface A {
    void a(Object o);
}

interface B {
    void b(String s);
}

class C implements A {
    public void a(Object o) {
        System.out.println("a() in C");
    }

    public void b(String s) {
        System.out.println("b() in C");
    }
}

class D extends C implements A, B {
    public void a(Object o) {
        System.out.println("a() in D");
        super.a(o);
    }

    public void b(String s) {
        System.out.println("b() in D");
        try {
            int parseInt = Integer.parseInt(s);
        } catch (Exception e) {
            //NumberFormatException
            throw new BadFormatException();
        }
    }
}

class BadFormatException extends 
RuntimeException {
}
public class Test {
    public static void main(String[] args) {
        A a1 = new C();
        B b1 = new D();
        C c1 = new C();
        C c2 = new D();
        Object o = new String("Twenty Two");
        try {
            f(c2);
            a1.a(o);
            c1.a((String) o);
            b1.b((String) o);
            c2.a(o);
        } catch (NumberFormatException e) {
            System.out.println("NumberFormatException");
        } catch (BadFormatException e) {
            System.out.println("BadFormatException");
        } catch (Exception e) {
            System.out.println("Exception");
        } finally {
            System.out.println("Good Bye!");
        }
    }

    public static void f(A a) {
        a.a(a);
    }
}

Accessing the Stack Trace

  • e.printStackTrace();

  • e.getStackTrace();

for(StackTraceElement methodCall : e.getStackTrace())
	System.out.println(methodCall);

Multiple Catch Blocks

  • When providing multiple catch handlers:

  • handle specific exceptions before handling general exceptions.

  • Multi-Catch Blocks (Java7):

catch(IOException | IllegalStateException multie) {…}

Try-with-Resources (Java7)

try(Scanner sc = new Scanner(System.in)) {
    System.out.println("You Typed the integer value: " + sc.nextInt());
} catch (Exception e){
    // catch all other exceptions here ...
    System.out.println("Error: Encountered an exception and could not read
    an integer from the console ...");
    System.out.println("Exciting the program - 
    restart and try the program again!");
}
  • java.lang.AutoCloseable interface

Assertions

  • The assert statement

  • used to check your assumptions about the programs

  • E.g.

    • assert (i >= 0) : "impossible: i is negative!";

  • AssertionError

  • java -ea MyClassName

Assert or Exception?

  • The key to understanding assertions

  • they are useful for debugging and testing

  • Assertions are meant to be disabled when the application is deployed to end users

Title Text

Exception

By Behnam Hatami

Exception

Exception / Advanced Programming Course @ SUT, Spring 2019

  • 967