An exception is an error event that can happen during the execution of a program and disrupts its normal flow. Java provides a robust and object-oriented way to handle exception scenarios known as Java Exception Handling.
Exceptions in Java can arise from different kinds of situations such as wrong data entered by the user, hardware failure, network connection failure, or a database server that is down. The code that specifies what to do in specific exception scenarios is called exception handling.
Java creates an exception object when an error occurs while executing a statement. The exception object contains a lot of debugging information such as method hierarchy, line number where the exception occurred, and type of exception.
If an exception occurs in a method, the process of creating the exception object and handing it over to the runtime environment is called “throwing the exception”. The normal flow of the program halts and the Java Runtime Environment (JRE) tries to find the handler for the exception. Exception Handler is the block of code that can process the exception object.
So if the method’s call stack is A->B->C
and an exception is raised in method C
, then the search for the appropriate handler will move from C->B->A
.
If an appropriate exception handler is found, the exception object is passed to the handler to process it. The handler is said to be “catching the exception”. If there is no appropriate exception handler, found then the program terminates and prints information about the exception to the console.
Java Exception handling framework is used to handle runtime errors only. The compile-time errors have to be fixed by the developer writing the code else the program won’t execute.
Java provides specific keywords for exception handling purposes.
null
. The throw
keyword is used to throw exceptions to the runtime to handle it.throws
keyword in the method signature to let the caller program know the exceptions that might be thrown by the method. The caller method might handle these exceptions or propagate them to its caller method using the throws
keyword. We can provide multiple exceptions in the throws
clause, and it can be used with the main()
method also.try-catch
block for exception handling in our code. try
is the start of the block and catch
is at the end of the try
block to handle the exceptions. We can have multiple catch
blocks with a try
block. The try-catch
block can be nested too. The catch
block requires a parameter that should be of type Exception
.finally
block is optional and can be used only with a try-catch
block. Since exception halts the process of execution, we might have some resources open that will not get closed, so we can use the finally
block. The finally
block always gets executed, whether an exception occurred or not.package com.journaldev.exceptions;
import java.io.FileNotFoundException;
import java.io.IOException;
public class ExceptionHandling {
public static void main(String[] args) throws FileNotFoundException, IOException {
try {
testException(-5);
testException(-10);
} catch(FileNotFoundException e) {
e.printStackTrace();
} catch(IOException e) {
e.printStackTrace();
} finally {
System.out.println("Releasing resources");
}
testException(15);
}
public static void testException(int i) throws FileNotFoundException, IOException {
if (i < 0) {
FileNotFoundException myException = new FileNotFoundException("Negative Integer " + i);
throw myException;
} else if (i > 10) {
throw new IOException("Only supported for index 0 to 10");
}
}
}
testException()
method is throwing exceptions using the throw
keyword. The method signature uses the throws
keyword to let the caller know the type of exceptions it might throw.main()
method, I am handling exceptions using the try-catch
block in the main()
method. When I am not handling it, I am propagating it to runtime with the throws
clause in the main()
method.testException(-10)
never gets executed because of the exception and then the finally
block is executed.The printStackTrace()
is one of the useful methods in the Exception
class for debugging purposes.
This code will output the following:
Outputjava.io.FileNotFoundException: Negative Integer -5
at com.journaldev.exceptions.ExceptionHandling.testException(ExceptionHandling.java:24)
at com.journaldev.exceptions.ExceptionHandling.main(ExceptionHandling.java:10)
Releasing resources
Exception in thread "main" java.io.IOException: Only supported for index 0 to 10
at com.journaldev.exceptions.ExceptionHandling.testException(ExceptionHandling.java:27)
at com.journaldev.exceptions.ExceptionHandling.main(ExceptionHandling.java:19)
Some important points to note:
catch
or finally
clause without a try
statement.try
statement should have either catch
block or finally
block, it can have both blocks.try-catch-finally
blocks.catch
blocks with a single try
statement.try-catch
blocks can be nested similar to if-else
statements.finally
block with a try-catch
statement.As stated earlier, when an exception is raised an exception object is getting created. Java Exceptions are hierarchical and inheritance is used to categorize different types of exceptions. Throwable
is the parent class of Java Exceptions Hierarchy and it has two child objects – Error
and Exception
. Exception
s are further divided into Checked Exception
s and Runtime Exception
s.
Error
s are exceptional scenarios that are out of the scope of application, and it’s not possible to anticipate and recover from them. For example, hardware failure, Java virtual machine (JVM) crash, or out-of-memory error. That’s why we have a separate hierarchy of Error
s and we should not try to handle these situations. Some of the common Error
s are OutOfMemoryError
and StackOverflowError
.Exception
s are exceptional scenarios that we can anticipate in a program and try to recover from it. For example, FileNotFoundException
. We should catch this exception and provide a useful message to the user and log it properly for debugging purposes. The Exception
is the parent class of all Checked Exception
s. If we are throwing a Checked Exception
, we must catch
it in the same method, or we have to propagate it to the caller using the throws
keyword.Exception
s are caused by bad programming. For example, trying to retrieve an element from an array. We should check the length of the array first before trying to retrieve the element otherwise it might throw ArrayIndexOutOfBoundException
at runtime. RuntimeException
is the parent class of all Runtime Exception
s. If we are throw
ing any Runtime Exception
in a method, it’s not required to specify them in the method signature throws
clause. Runtime exceptions can be avoided with better programming.Java Exception
and all of its subclasses don’t provide any specific methods, and all of the methods are defined in the base class - Throwable
. The Exception
classes are created to specify different kinds of Exception
scenarios so that we can easily identify the root cause and handle the Exception
according to its type. The Throwable
class implements the Serializable
interface for interoperability.
Some of the useful methods of the Throwable
class are:
String
of Throwable
and the message can be provided while creating the exception through its constructor.Throwable
class implementation of this method uses the getMessage()
method to return the exception message.null
if the cause is unknown.Throwable
in String
format, the returned String
contains the name of the Throwable
class and localized message.PrintStream
or PrintWriter
as an argument to write the stack trace information to the file or stream.If you are catch
ing a lot of exceptions in a single try
block, you will notice that the catch
block code mostly consists of redundant code to log the error. In Java 7, one of the features was an improved catch
block where we can catch multiple exceptions in a single catch
block. Here is an example of the catch
block with this feature:
catch (IOException | SQLException ex) {
logger.error(ex);
throw new MyException(ex.getMessage());
}
There are some constraints such as the exception object is final and we can’t modify it inside the catch
block, read the full analysis at Java 7 Catch Block Improvements.
Most of the time, we use the finally
block just to close the resources. Sometimes we forget to close them and get runtime exceptions when the resources are exhausted. These exceptions are hard to debug, and we might need to look into each place where we are using that resource to make sure we are closing it. In Java 7, one of the improvements was try-with-resources
where we can create a resource in the try
statement itself and use it inside the try-catch
block. When the execution comes out of the try-catch
block, the runtime environment automatically closes these resources. Here is an example of the try-catch
block with this improvement:
try (MyResource mr = new MyResource()) {
System.out.println("MyResource created in try-with-resources");
} catch (Exception e) {
e.printStackTrace();
}
Java provides a lot of exception classes for us to use, but sometimes we may need to create our own custom exception classes. For example, to notify the caller about a specific type of exception with the appropriate message. We can have custom fields for tracking, such as error codes. For example, let’s say we write a method to process only text files, so we can provide the caller with the appropriate error code when some other type of file is sent as input.
First, create MyException
:
package com.journaldev.exceptions;
public class MyException extends Exception {
private static final long serialVersionUID = 4664456874499611218L;
private String errorCode = "Unknown_Exception";
public MyException(String message, String errorCode) {
super(message);
this.errorCode=errorCode;
}
public String getErrorCode() {
return this.errorCode;
}
}
Then, create a CustomExceptionExample
:
package com.journaldev.exceptions;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStream;
public class CustomExceptionExample {
public static void main(String[] args) throws MyException {
try {
processFile("file.txt");
} catch (MyException e) {
processErrorCodes(e);
}
}
private static void processErrorCodes(MyException e) throws MyException {
switch (e.getErrorCode()) {
case "BAD_FILE_TYPE":
System.out.println("Bad File Type, notify user");
throw e;
case "FILE_NOT_FOUND_EXCEPTION":
System.out.println("File Not Found, notify user");
throw e;
case "FILE_CLOSE_EXCEPTION":
System.out.println("File Close failed, just log it.");
break;
default:
System.out.println("Unknown exception occured, lets log it for further debugging." + e.getMessage());
e.printStackTrace();
}
}
private static void processFile(String file) throws MyException {
InputStream fis = null;
try {
fis = new FileInputStream(file);
} catch (FileNotFoundException e) {
throw new MyException(e.getMessage(), "FILE_NOT_FOUND_EXCEPTION");
} finally {
try {
if (fis != null) fis.close();
} catch (IOException e) {
throw new MyException(e.getMessage(), "FILE_CLOSE_EXCEPTION");
}
}
}
}
We can have a separate method to process different types of error codes that we get from different methods. Some of them get consumed because we might not want to notify the user of that, or some of them we will throwback to notify the user of the problem.
Here I am extending Exception
so that whenever this exception is being produced, it has to be handled in the method or returned to the caller program. If we extend RuntimeException
, there is no need to specify it in the throws
clause.
This was a design decision. Using Checked Exception
s has the advantage of assisting developers with understanding which exceptions you can expect and take appropriate action to handle them.
IOException
with further sub-classes as FileNotFoundException
, EOFException
, etc. We should always throw
and catch
specific exception classes so that caller will know the root cause of the exception easily and process them. This makes debugging easier and helps client applications handle exceptions appropriately.throw
exceptions as early as possible. Consider the above processFile()
method, if we pass the null
argument to this method, we will get the following exception:OutputException in thread "main" java.lang.NullPointerException
at java.io.FileInputStream.<init>(FileInputStream.java:134)
at java.io.FileInputStream.<init>(FileInputStream.java:97)
at com.journaldev.exceptions.CustomExceptionExample.processFile(CustomExceptionExample.java:42)
at com.journaldev.exceptions.CustomExceptionExample.main(CustomExceptionExample.java:12)
While debugging we will have to look out at the stack trace carefully to identify the actual location of exception. If we change our implementation logic to check for these exceptions early as below:
private static void processFile(String file) throws MyException {
if (file == null) throw new MyException("File name can't be null", "NULL_FILE_NAME");
// ... further processing
}
Then the exception stack trace will be indicate where the exception has occurred with clear message:
Outputcom.journaldev.exceptions.MyException: File name can't be null
at com.journaldev.exceptions.CustomExceptionExample.processFile(CustomExceptionExample.java:37)
at com.journaldev.exceptions.CustomExceptionExample.main(CustomExceptionExample.java:12)
catch
the exception and log the error. But this practice is harmful because the caller program doesn’t get any notification for the exception. We should catch
exceptions only when we can handle them appropriately. For example, in the above method, I am throw
ing exceptions back to the caller method to handle it. The same method could be used by other applications that might want to process the exception in a different manner. While implementing any feature, we should always throw
exceptions back to the caller and let them decide how to handle it.try-with-resources
enhancement to let java runtime close it for you.throw
ing exceptions provide a clear message so that caller will know easily why the exception occurred. We should always avoid an empty catch
block that just consumes the exception and doesn’t provide any meaningful details of the exception for debugging.catch
block. This approach will reduce our code size, and it will look cleaner too.throw
ing and catch
ing multiple exceptions, we can create a custom exception with an error code, and the caller program can handle these error codes. It’s also a good idea to create a utility method to process different error codes and use them.Exception
so that it will be clear from the name itself that it’s an exception class. Also, make sure to package them like it’s done in the Java Development Kit (JDK). For example, IOException
is the base exception for all IO operations.@throws
to clearly specify the exceptions thrown by the method. It’s very helpful when you are providing an interface for other applications to use.In this article, you learned about exception handling in Java. You learned about throw
and throws
. You also learned about try
(and try-with-resources
), catch
, and finally
blocks.
Thanks for learning with the DigitalOcean Community. Check out our offerings for compute, storage, networking, and managed databases.
Really great article. It would be better if you could mention the term chain of responsibility which used in exception handling.
- Subhash C
Thanks! Gives a great overview of exception handling.
- ushak
p.s.v.m(String args[]) { int a=10; int b=0;//if this value we are taking as user input,the user should be prompted of that it should not enter 0. try { int c=a/b; S.o.p©; } catch(Exception e) { } S.o.p(“hii”); } my question is if c variable answer i want but as its throwing the exception.i am not able to use the value of c. How to handle the exception.
- Ayesha
sir, let me know while we are doing de-serialize the objects from any file we must know what is the order of serialize objects in the respected file but unfortunate if we don’t know what is the order then we can de-serialize using instanceof … if we use instanceof we should check every object so that we are going to do some conditions like if or while or loop … for doing this my length of code going to high but i don’t like increase my length of code …please let me know how to do that ?? Just imagine in the file bulk of serializable objects are there then I dont know which order is there but i know how to deserialize them but i dont know how make a loop for that … FileInputStream fis = new FileInputStream(“abc.txt”); ObjectInputStream ois=new ObjectInputStream(fis); Object o=readObject(); if(o instanceof Dog ) { Dog d = (Dog)o; after retrieve the object i can do whatever i want but for one object or two objects i can follow this way but if is there any number objects then how i can retrieve those objects with in small amount of code }
- Peer
Hello sir thank you so much for giving me detailed knowledge about Exception Handling . this article is very nice and clear.and example is also very nice.please keep posting thank you once again.
- Anurag Singh
Hello. You have an error here, this code wont compile: catch(IOException | SQLException | Exception ex){ logger.error(ex); throw new MyException(ex.getMessage()); } You should remove Exception, because multicatch block only for exceptions with different inheritance hierarchy. Also thanks for your work. Awesome website.
- mrgnstrn
can you explain me Singleton pattern in java
- kavya
Thanks a lot. This is really useful for me!
- Mohammed
It’s good to understand sir, but can you please provide me simple examples sir. Thank you sir.
- Suresh Yadam
Wow, your post is so easy to understand. Even for a someone like me who’s only starting to learn Java. Bookmarked!!
- Jayson