Java exceptions handling mechanism

October 18, 2016by Constantin

trycatch

“When used to best advantage, exceptions can improve a program’s readability,
reliability, and maintainability. When used improperly, they can have the opposite
effect.”


– Effective Java

Every good developer aims to write good code, that good, that the running system will not crash ever, everything will work smooth and quiet, and everyone will be happy. To make this close to reality, a lot of factors need to be taken in count, because imagine that the following Murphy’s law will occur: “Whenever you need a crucial file from disk, it will not be there”. So, what’s next? The system will crash and that’s it, you’re done! What I know for sure is that you can’t prevent this situation itself, but you must’ve expected this and handle somehow. There are thousands and thousands of situations like this, when you must think about what can go wrong. Is it a physical resource that could be missing? A user error? Who knows, but you must somehow treat these exceptional conditions.

Normally, when something goes wrong, under exceptional conditions, an exception is risen. Fortunately, Java provides us with a strong exceptions handling mechanism. Let’s quickly examine the following diagram, which shows us exception types and their hierarchy

exception

As you may notice, an exception is nothing more than a Java class, that derives from the Throwable class.
Straight to the point:

Error: these are abnormal conditions, that are beyond the programmer’s control, because there is nothing that you can do about an error that arise. So an important thing to remember, is that you should never try to treat an error in any way.

Exception: parent class for all existing exceptions in the world, which in it’s turn has 2 subclasses:

  • Checked Exceptions: these are typically used, when you want to force the programmer, that is using your API, to think how to handle them. These types of exceptions are checked at compile-time. Any subclass of Exception class, which is not a subclass of RuntimeException, is considered a checked exception.
  • Runtime Exceptions: also often called Unchecked Exceptions. They are used when your exceptional condition is unrecoverable, and you can’t do anything about this. Programmer is not forced to handle these types of exceptions.

Now let’s dig a bit deeper into technical details and examine Java exceptions handlers.

Exception Handling

We will focus now on Java exception handlers, and their possibilities. For runtime exceptions, it is not mandatory to write exception handlers, however, the programmer can do this. Basically there are several ways to deal with exceptions.

  • – Wrapping a piece of code into the try block and right after, specify the exception handler in a catch block. Optionally you can specify a finally block. Usually finally block is used to close all the resources that are no longer necessary.

    [code language=”java”]
    try{
    //some tough code
    } catch(SomeException e){
    //handle exception
    } finally {
    //close resources
    }
    [/code]

  • The execution flow is simple: try block is executed (also called the guarded block), if an exception is thrown from the try block, and there is an exception type match in any of catch clauses, the catch block will be executed right away. The finally block will always be executed, whether or not an exception was raised..
  • – Declare in method signature that it can throw an exception, and let the caller handle this somehow.

    [code language=”java”]
    public void doSomething() throws SomeException {
    //code that can throw SomeException
    }
    [/code]

  • This means an exception can be thrown from anywhere in the corresponding method body.

When to use try-catch-finally and when to declare a method as throwing exception one?

Usually, when writing some code that might throw an exception, ask yourself, is this your responsibility and can you do something with this, handle somehow? If there is even a slightly yes in you answer, then definitely you have to wrap it into a catch block and handle it, otherwise, just pass it down to the call stack. In fact nobody forces you to write the complete handler, you can take your part of responsibility, and rethrow the exception, like in the following example:

[code language=”java”]
private void createUser(User user) throws ValidationException {
try{
userService.create(user);
logger.info(“Create new user {}” , user.getUserName());
} catch (ValidationException e) {
logger.error(“Invalid data for creating new user {}, cause: {} ”, user.getUserName(), e.getMessage());
throw e;
}
}
[/code]

This is a common pattern named “handle and declare”. We want to do something with the exception, and handled it, but because we couldn’t handle it completely, we rethrow it and pass it to the caller.

Multicatch block

Since java 7 has been released we are encouraged to use multi-catch statement in order to avoid code duplication. But this statement has a limitation, you cannot catch 2 exceptions if there is inheritance relationship between them.

[code language=”java”]
try{
//some code
} catch (NumberFormatException | IllegalArgumentException e){ // won’t compile
}

[/code]

Try-with-resources

Another important feature that was introduced since Java 7, called automatic resource management. Let’s examine the following code, for a standard reading from a file:

[code language=”java”]
BufferedReader br = null;
try{
br = new BufferedReader(new FileReader(path));
//read from file
} catch (IOException e){
e.printStackTrace();
} finally {
try {
if (br != null) {
br.close();
}
} catch (IOException ex) {
ex.printStackTrace();
}
}
[/code]

Looks a bit ugly, especially the finally block, but perfectly legal, and also necessary because you need to close the resources you are no longer using, in our case, close the buffered reader. Using try-with-resources, will transform the above code into something like this:

[code language=”java”]
try (BufferedReader br = new BufferedReader(new FileReader(path))){
//read from file
} catch (IOException e) {
e.printStackTrace();
}
[/code]

I’d say, this looks a lot better. To use this syntax, any class that participates in the try-with-resources statement should implement interface AutoCloseable, which looks like this :

[code language=”java”]
public interface AutoCloseable {
void close() throws Exception;
}
[/code]

It is recommended that all classes, that implement this interface, declare more specific exception types in their close() method signature, than their parent class does, or not declare anything if invoking their close() method will not throw any exception.

Inappropriate use of exceptions

First of all, remember, there is a reason why they are called exceptions, because they happen only under exceptional conditions. Often programmers are using exceptions just to alter normal execution flow, which is incorrect. If you can add a check, or just return a boolean value instead of using exceptions, then do so! In any case do not use them just because you want to, like in the following example:

[code language=”java”]
//some complex code
User user = userDao.getById(userId);
try {
user.getUserName();
} catch (NullPointerException e) {
logger.info(“No user found with ID {} ”, userId);
}
[/code]

That’s really, really bad code. You shouldn’t catch a NullPointerException, which is a subclass of RuntimeException, instead of this you could add a simple check to null object reference, something like this:

[code language=”java”]
User user = userDao.getById(userId);
If (user == null) {
logger.info(“No user found with ID {} ”, userId”);
}
[/code]

Plus, usage of exception handlers slows down the execution of the program, because when an exception is thrown, the following happens:

  1. 1. The normal execution flow of the program is suspended
  2. 2. JVM searches for appropriate exception handler in this class, by looking at catch clauses from top down
  3. 3. If no matching catch clause is found for the exception type, then it will search for supertype of the exception
  4. 4. If no appropriate handler is found, the exception is passed down the call stack

As you can understand, this will end in one of two options, either someone from the callers on the call stack will have the right exception handler, either the propagation of uncaught exception will get to the main entry point of each Java application, in main function, were it will terminate the execution of you program.
Uncaught exception in a specific thread, when using multithreading, will be described later in this article.

Ignoring exceptions

Often, instead of dealing with exceptions and handle them , many programmers temp to ignore them.

[code language=”java”]
try{
//code
} catch( SomeSpecificException e) {
//ignoring
}
[/code]

This is a bad practice, because something exceptional happened, but you didn’t handle it, and this can end up with really serious bugs, system failures etc. There are a few cases, when there really is nothing to do with the caught exception, but at least, you can add a log line explaining why you ignored the exception and log the stack trace.

All in one catch

Another often mistake, is catching the parent type of all exceptions in the (Java) world: the Exception class.

[code language=”java”]
try{
//really complex code here
} catch(Exception e) {
}
[/code]

This is not a correct approach. Imagine that you have a complex code written in try block, where , different types of exceptions could be raised. Now, the code above will catch every single exception that will ever be thrown from the try block, and handle them in the same way, doesn’t matter is it’s a checked exception or a runtime one. It is always advised to catch specific exceptions that can be thrown from corresponding try body. This offers you the possibility to handle each exception type, in a different way.

Tricky examples

  • 1. Finally is not executed if System.exit method is called inside a try block. This is good to know in order to avoid locking some external resources.
  • [code language=”java”]
    public class ExceptionHandling1{
    public static void main(String[] args){
    try{
    System.out.println("Hello from try block");
    System.exit(0);
    } finally {
    System.out.println("Hello from finally block");
    }
    }
    }

    [/code]

    output:
    Hello from try block

  • 2. Finally is executed even if a return statement is used inside a try block. In this cases we can rely on such implementation and be sure that the used resources are closed.
  • [code language=”java”]
    public class ExceptionHandling2{
    public static void main(String[] args){
    try{
    System.out.println("Hello from try block");
    return;
    } finally {
    System.out.println("Hello from finally block");
    }
    }
    }
    [/code]

    output:
    Hello from try block
    Hello from finally block

  • 3. Any exception thrown in a static init block is wrapped into ExceptionInInitializerError. An ExceptionInInitializerError is thrown to indicate that an exception occurred during evaluation of a static initializer or the initializer for a static variable.”
  • [code language=”java”]
    public class ExceptionHandling3{
    static{
    throwRuntimeException();
    }

    private static void throwRuntimeException() {
    throw new NullPointerException();
    }

    public static void main(String[] args) {
    System.out.println("Hello World");
    }
    }
    [/code]

    output:

    java.lang.ExceptionInInitializerError
    Caused by: java.lang.NullPointerException
    at exception.test.ExceptionHandling3.throwRuntimeException(ExceptionHandling3.java:13)
    at exception.test.ExceptionHandling3.(ExceptionHandling3.java:8)

  • 4. When using multithreading, could happen that one of the threads will throw an exception which will not be handled anywhere. Let’s assume we have the following code:
  • [code language=”java”]
    public class ExceptionHandling4
    {
    public static void main(String[] args) throws InterruptedException
    {

    Thread t = new Thread() {
    @Override
    public void run()
    {
    throw new RuntimeException("Testing unhandled exception processing.");
    }
    };
    t.start();
    }
    }
    [/code]

    output:

    Exception in thread “Thread-0” java.lang.RuntimeException: Testing unhandled exception processing.
    at exception.test. ExceptionHandling4$1.run(ExceptionHandling4.java:27)

    For this purposes, for each thread you can set an uncaughtExceptionHandler, which will handle the exception if it gets propagated out of thread’s scope:

    [code language=”java”]
    t.setUncaughtExceptionHandler(new Thread.UncaughtExceptionHandler() {
    public void uncaughtException(Thread t, Throwable e) {
    System.out.println("Handled uncaught exception in thread :" + t + " Exception : " + e);
    }
    });
    [/code]

    output:

    Handled uncaught exception in thread :Thread[Thread-0,5,main] Exception : java.lang.RuntimeException: Testing unhandled exception processing.

    This is important to know, because throwing an exception from a thread can terminate your entire application if this was the only non-daemon thread that just terminated.

    Remember, as another Murphy’s law states:“If something can go wrong, it will”. Do not hesitate to handle exceptions, (if it’s the case of course), do not ignore them and don’t use them where you can avoid them. Their meaning is to improve reliability of your system, by handling and treating exceptional conditions that can appear during the execution of the program.

    Upscale Your

    Business TODAY
    Connect with us
    Bulgara Street 33/1, Chisinau MD-2001, Moldova
    + 373 22 996 170
    info@isd-soft.com
    De Amfoor 15, 5807 GW Venray-Oostrum, The Netherlands
    +31 6 212 94 116

    Subscribe to our newsletter today to receive updates on the latest news, releases and special offers.

    Copyright ©2024, ISD. All rights reserved | Cookies Policy | Privacy Policy

    De Nederlandse pagina’s zijn vertaald met behulp van een AI-applicatie.