Header javaperspective.com
JavaPerspective.com  >   Beginner Tutorials  >   4. Object-Oriented Concepts  >   4.11. Exceptions

4.11. Exceptions
Last updated: 27 January 2013.


4.11.1. What is an exception?

An exception is an object that is created by a method when an error occurs during its execution. For example, an attempt to convert the string value "123a" to an integer will cause an exception to be created. Every exception is a subclass of the class Throwable. When an exception is created, it is thrown to the Java virtual machine that terminates the program unless an exception handler is provided. An exception handler is a block of code whose purpose is to handle exceptions. Let's take a look at the class Converter shown below:

public final class Converter {

   
public int stringToInt(String value){

         
int result = 0;

          System.out.println
("The string value is now going to be converted to an integer");

          result = Integer.parseInt
(value);

          System.out.println
("The string value has been successfully converted to an integer");

         
return result;
   
}

}

The class Converter has a single method named stringToInt that converts a string value to an integer. The class App shown below contains a main method which creates an instance of the class Converter and calls the method stringToInt, passing in the string value "123a".

public final class App {

   
public static void main(String[] args) {

         
int myInteger = new Converter().stringToInt("123a");

          System.out.println
(myInteger);
   
}

}

If you run the class App, you will get this output:

The string value is now going to be converted to an integer
Exception in thread "main" java.lang.NumberFormatException: For input string: "123a"
   at java.lang.NumberFormatException.forInputString(NumberFormatException.java:65)
   at java.lang.Integer.parseInt(Integer.java:481)
   at java.lang.Integer.parseInt(Integer.java:514)
   at Converter.stringToInt(Converter.java:7)
   at App.main(App.java:5)

As you can see, only the two first statements of the method stringToInt are executed. The execution of the third statement (result = Integer.parseInt(value);) causes an exception to be created and thrown to the Java virtual machine that terminates the program since no exception handler is provided. Consequently, the statements following the statement where the error occurred are not executed.

The output shown above lists the method calls from the main method (at the bottom) to the method where the exception occurred (at the top), including the methods belonging to the Java API classes. That list of method calls is termed the call stack. For each method call, the line number of the executed statement is indicated.

Generally, when analyzing a call stack, you can ignore the methods of the Java API and only consider the classes that you have written in order to modify them appropriately to handle the exception or somehow fix the problem. Thus, the call stack of the above example can be illustrated as shown below:

picture illustrating the call stack

When the exception occurred in the class Converter, the Java virtual machine looked for an exception handler at the point where the exception occurred, that is in the method stringToInt. Since no exception handler was found, the Java virtual machine looked for an exception handler in the method that called the method stringToInt, that is the main method of the class App. Since no exception handler was found in the entire call stack, the program was terminated.


4.11.2. How to write an exception handler?

An exception handler allows you to avoid unexpected termination of a program. It can be written at any point within the call stack. Basically, an exception handler is a try-catch-finally block:

try{
   
// Here goes the code that is likely to throw exceptions
    //...
}
catch(Exception e){
   
// Here goes the code that will be executed if an exception is thrown by a statement in the try block
    //...
}
finally{
   
// Here goes the code that will be executed in all cases
    //...
}

Let's get back to the example and write an exception handler in the method stringToInt provided by the class Converter:

public final class Converter {

   
public int stringToInt(String value){

         
int result = 0;

         
try{
               
System.out.println("The string value is now going to be converted to an integer");

                result = Integer.parseInt
(value);

                System.out.println
("The string value has been successfully converted to an integer");
         
}
         
catch(NumberFormatException e){
               
System.out.println("A NumberFormatException has been thrown somewhere in the try block");
         
}
         
finally{
               
System.out.println("The finally block has been executed");
         
}

         
return result;
   
}

}

Code explanation:

Now if you run the class App, you will get this output:

The string value is now going to be converted to an integer
A NumberFormatException has been thrown somewhere in the try block
The finally block has been executed
0



4.11.3. How to throw exceptions?

In the example shown above, if an exception is thrown in the try block, it is swallowed in the catch block and the method stringToInt returns the value 0. Consequently, the caller is not aware that an exception has been thrown. If you want the caller to be aware of the exception that has been thrown by the callee, you can throw the exception explicitly in the catch block as shown below:

public final class Converter {

   
public int stringToInt(String value){

         
int result = 0;

         
try{
               
System.out.println("The string value is now going to be converted to an integer");

                result = Integer.parseInt
(value);

                System.out.println
("The string value has been successfully converted to an integer");
         
}
         
catch(NumberFormatException e){
               
System.out.println("A NumberFormatException has been thrown somewhere in the try block");
               
throw e;
         
}
         
finally{
               
System.out.println("The finally block has been executed");
         
}

         
return result;
   
}

}

The keyword throw allows you to throw explicitly the exception to the caller of the method stringToInt, that is the main method of the class App. If you run the class App, you will get this output:

The string value is now going to be converted to an integer
A NumberFormatException has been thrown somewhere in the try block
The finally block has been executed
Exception in thread "main" java.lang.NumberFormatException: For input string: "123a"
   at java.lang.NumberFormatException.forInputString(NumberFormatException.java:65)
   at java.lang.Integer.parseInt(Integer.java:481)
   at java.lang.Integer.parseInt(Integer.java:514)
   at Converter.stringToInt(Converter.java:10)
   at App.main(App.java:5)

Since no exception handler was found in the main method, the program was terminated when the exception was thrown by the method stringToInt. As a result, the last statement of the main method was not executed. If you want the main method to terminate gracefully when an exception is thrown, you can write an exception handler as shown below:

public final class App {

   
public static void main(String[] args) {

         
int myInteger = 0;

         
try{
               
myInteger = new Converter().stringToInt("123a");
                System.out.println
(myInteger);
         
}
         
catch(NumberFormatException e){
               
System.out.println("A NumberFormatException has been thrown by the method stringToInt()");
         
}
    }

}

Generally, an exception handler is written only at one point in the call stack unless there is a good reason to have multiple handlers. Consequently, in the examples shown above, since you have written a handler in the main method of the class App, you can remove the handler previously written in the method stringToInt. Note that when an exception is thrown to a caller, that caller can in turn throw it up to a higher level caller (if any) and so on.

In case you have a series of numerous methods in the call stack, and if an error is likely to occur in a low level method, you may be tempted to provide an exception handler at that point instead of throwing the exception up higher in the call stack. If you do so, the high level methods will not be aware that an exception was thrown and your application may continue running but incoherently. In contrast, if you throw the exception up too high in the call stack, it may terminate your application. It is up to you to determine the best exception handling strategy, depending on your application's requirements.

On the one hand, you can choose not to tolerate errors in certain critical code areas of your application (you don't provide exception handlers in those areas or, you terminate the application explicitly in certain catch blocks by calling the method System.exit). Consequently, if exceptions occur in those areas, the application terminates.

On the other hand, you can write exception handlers in less critical code sections, allowing the application to survive to exceptions that may occur in those code sections. The worst thing you can do is to silently swallow exceptions (with empty catch blocks). In that case, your application is likely to run incoherently when exceptions occur without you even realizing. For this reason, in a catch block, you should at least print the exception's stack trace to the standard output by calling the method printStackTrace provided by the class Throwable or take appropriate action (or do both), unless you really want to ignore the exception.

Typically, for a large application, exception handling is a tradeoff between guaranteeing the application's survival and preserving its coherence.


4.11.4. What are checked and unchecked exceptions?

Unchecked exceptions:
Checked exceptions:

4.11.5. How to handle multiple exception types?

If a try block is likely to throw multiple exception types, you can have multiple catch blocks and handle each exception type separately. In that case, each catch block must handle a different type of exception. Furthermore, if an exception is thrown, the Java virtual machine executes the first catch block whose type matches the type of the exception that has been thrown.

For example, if in the same try block, you convert a string to an integer and also open a database connection, the try block is likely to throw a NumberFormatException and an SQLException. You can handle each exception in a separate catch block as shown below:

try{
   
// the try block converts a string to an integer and opens a database connection.
    // ...
}
catch(NumberFormatException e){
   
// do something
    // ...
}
catch(SQLException e){
   
// do something else
    // ...
}

If you handle both types of exceptions in exactly the same way, the catch blocks will contain the same code. To avoid code duplication, you can handle multiple types of exceptions in a single catch block if you are running Java SE 7 or a later version of the JDK:

try{
   
// the try block converts a string to an integer and opens a database connection.
    // ...
}
catch(NumberFormatException | SQLException e){
   
e.printStackTrace();
}



4.11.6. How to define your own exception types?

Instead of using the predefined exceptions of the Java API, you can extend a predefined exception and thereby create a user-defined exception that has additional features. For example, you can create a custom exception called ConversionException that extends the class Exception:

public final class ConversionException extends Exception {

   
// You can declare fields, methods and constructors as needed.

}

Such a custom exception can be thrown as shown below:

try{
   
// the try block is likely to throw a NumberFormatException.
    // ...
}
catch(NumberFormatException e){
   
throw new ConversionException(); // throws a custom exception to the caller.
}

It can be handled in a catch block the same way a predefined exception is handled:

try{
   
// the try block is likely to throw a ConversionException.
    // ...
}
catch(ConversionException e){
   
e.printStackTrace();
}

Custom exceptions may come in handy when you want to add specific features to a predefined exception or if no predefined exception meets your needs at all. For example, if you have a class in your application whose purpose is to validate the users names and passwords, you may want to limit the number of attempts to 3. To that end, you can create a custom exception called TooManyAttemptsException and throw it if the same user tries to sign in for more than 3 times.


You are here :  JavaPerspective.com  >   Beginner Tutorials  >   4. Object-Oriented Concepts  >   4.11. Exceptions
Next tutorial :  JavaPerspective.com  >   Beginner Tutorials  >   4. Object-Oriented Concepts  >   4.12. Anonymous classes

Copyright © 2013. JavaPerspective.com. All rights reserved.  ( Terms | Contact | About ) 
Java is a trademark of Oracle Corporation
Image 1 Image 2 Image 3 Image 4 Image 5 Image 6 Image 7