Java error example

Error is an illegal operation performed by the user which results in the abnormal working of the program. Programming errors often remain undetected until the program is compiled or executed. Some of the errors inhibit the program from getting compiled or executed. Thus errors should be removed before compiling and

Error is an illegal operation performed by the user which results in the abnormal working of the program. Programming errors often remain undetected until the program is compiled or executed. Some of the errors inhibit the program from getting compiled or executed. Thus errors should be removed before compiling and executing. 

The most common errors can be broadly classified as follows:

1. Run Time Error: 

Run Time errors occur or we can say, are detected during the execution of the program. Sometimes these are discovered when the user enters an invalid data or data which is not relevant. Runtime errors occur when a program does not contain any syntax errors but asks the computer to do something that the computer is unable to reliably do. During compilation, the compiler has no technique to detect these kinds of errors. It is the JVM (Java Virtual Machine) that detects it while the program is running. To handle the error during the run time we can put our error code inside the try block and catch the error inside the catch block. 

For example: if the user inputs a data of string format when the computer is expecting an integer, there will be a runtime error. Example 1: Runtime Error caused by dividing by zero 

Java

class DivByZero {

    public static void main(String args[])

    {

        int var1 = 15;

        int var2 = 5;

        int var3 = 0;

        int ans1 = var1 / var2;

        int ans2 = var1 / var3;

        System.out.println(

            "Division of va1"

            + " by var2 is: "

            + ans1);

        System.out.println(

            "Division of va1"

            + " by var3 is: "

            + ans2);

    }

}

Runtime Error in java code:

Exception in thread "main" java.lang.ArithmeticException: / by zero
    at DivByZero.main(File.java:14)

Example 2: Runtime Error caused by Assigning/Retrieving Value from an array using an index which is greater than the size of the array 

Java

class RTErrorDemo {

    public static void main(String args[])

    {

        int arr[] = new int[5];

        arr[9] = 250;

        System.out.println("Value assigned! ");

    }

}

RunTime Error in java code:

Exception in thread "main" java.lang.ArrayIndexOutOfBoundsException: 9
    at RTErrorDemo.main(File.java:10)

2. Compile Time Error: 

Compile Time Errors are those errors which prevent the code from running because of an incorrect syntax such as a missing semicolon at the end of a statement or a missing bracket, class not found, etc. These errors are detected by the java compiler and an error message is displayed on the screen while compiling. Compile Time Errors are sometimes also referred to as Syntax errors. These kind of errors are easy to spot and rectify because the java compiler finds them for you. The compiler will tell you which piece of code in the program got in trouble and its best guess as to what you did wrong. Usually, the compiler indicates the exact line where the error is, or sometimes the line just before it, however, if the problem is with incorrectly nested braces, the actual error may be at the beginning of the block. In effect, syntax errors represent grammatical errors in the use of the programming language. 

Example 1: Misspelled variable name or method names 

Java

class MisspelledVar {

    public static void main(String args[])

    {

        int a = 40, b = 60;

        int Sum = a + b;

        System.out.println(

            "Sum of variables is "

            + sum);

    }

}

Compilation Error in java code:

prog.java:14: error: cannot find symbol
            + sum);
              ^
  symbol:   variable sum
  location: class MisspelledVar
1 error

Example 2: Missing semicolons 

Java

class PrintingSentence {

    public static void main(String args[])

    {

        String s = "GeeksforGeeks";

        System.out.println("Welcome to " + s)

    }

}

Compilation Error in java code:

prog.java:8: error: ';' expected
        System.out.println("Welcome to " + s)
                                             ^
1 error

Example: Missing parenthesis, square brackets, or curly braces 

Java

class MissingParenthesis {

    public static void main(String args[])

    {

        System.out.println("Printing 1 to 5 n");

        int i;

        for (i = 1; i <= 5; i++ {

            System.out.println(i + "n");

        }

    }

}

Compilation Error in java code:

prog.java:10: error: ')' expected
        for (i = 1; i <= 5; i++ {
                               ^
1 error

Example: Incorrect format of selection statements or loops 

Java

class IncorrectLoop {

    public static void main(String args[])

    {

        System.out.println("Multiplication Table of 7");

        int a = 7, ans;

        int i;

        for (i = 1, i <= 10; i++) {

            ans = a * i;

            System.out.println(ans + "n");

        }

    }

}

Compilation Error in java code:

prog.java:12: error: not a statement
        for (i = 1, i <= 10; i++) {
                      ^
prog.java:12: error: ';' expected
        for (i = 1, i <= 10; i++) {
                                ^
2 errors

Logical Error: A logic error is when your program compiles and executes, but does the wrong thing or returns an incorrect result or no output when it should be returning an output. These errors are detected neither by the compiler nor by JVM. The Java system has no idea what your program is supposed to do, so it provides no additional information to help you find the error. Logical errors are also called Semantic Errors. These errors are caused due to an incorrect idea or concept used by a programmer while coding. Syntax errors are grammatical errors whereas, logical errors are errors arising out of an incorrect meaning. For example, if a programmer accidentally adds two variables when he or she meant to divide them, the program will give no error and will execute successfully but with an incorrect result. 

Example: Accidentally using an incorrect operator on the variables to perform an operation (Using ‘/’ operator to get the modulus instead using ‘%’) 

Java

public class LErrorDemo {

    public static void main(String[] args)

    {

        int num = 789;

        int reversednum = 0;

        int remainder;

        while (num != 0) {

            remainder = num / 10;

            reversednum

                = reversednum * 10

                  + remainder;

            num /= 10;

        }

        System.out.println("Reversed number is "

                           + reversednum);

    }

}

Output:

Reversed number is 7870

Example: Displaying the wrong message 

Java

class IncorrectMessage {

    public static void main(String args[])

    {

        int a = 2, b = 8, c = 6;

        System.out.println(

            "Finding the largest number n");

        if (a > b && a > c)

            System.out.println(

                a + " is the largest Number");

        else if (b > a && b > c)

            System.out.println(

                b + " is the smallest Number");

        else

            System.out.println(

                c + " is the largest Number");

    }

}

Output:

Finding the largest number 

8 is the smallest Number

Syntax Error:

Syntax and Logical errors are faced by Programmers.

Spelling or grammatical mistakes are syntax errors, for example, using an uninitialized variable, using an undefined variable, etc., missing a semicolon, etc.

int x, y;
x = 10 // missing semicolon (;)
z = x + y; // z is undefined, y in uninitialized.

Syntax errors can be removed with the help of the compiler.


Errors

tutorial
java


  • Compiler Errors
  • Runtime Errors
    • Stack Traces
  • Catching Exceptions
    • Checked Exceptions
  • Logic Errors
  • Debugging
  • General Tips
  • Homework

By now, you’ve probably seen a few errors, either when compiling or running your code. They can be frustrating, but they can also give you a lot of information about exactly how you can fix the problems in your code. This tutorial covers the types of errors you’ll see when programming in Java, and how to fix them.

Compiler Errors

Remember that the compiler converts from Java code (which humans can read) to Java byte code (which computers can read). The Java compiler is a lot like a translater. Now imagine that you told a translator to translate “flibberflabby” from English to Spanish. The translator would tell you that “flibberflabby” isn’t a word, so it can’t be translated!

That’s what happens when you write code that the compiler doesn’t understand. It doesn’t know how to translate your code into Java byte code, so it gives you an error. The rules of a language are called its syntax. Compiler errors are also called syntax errors, because it means that your code broke the rules of the langauge.

Compiler errors can be for things like forgotten semicolons or misspelled variables, but they can also be for violating the rules of Java, like using a non-static variable from a static function.

Here’s an example that contains a syntax error. Can you spot it?

class BadExample(){
	public static void main(String[] args){
		System.out.println("Happy Coding!");
	}
}

Do you see the syntax error? Try to compile this code. Save it to a file named BadExample.java, and then open a command prompt to the directory that contains that file, then type javac BadExample.java and press enter.

The compiler will show you this error:

> javac BadExample.java

BadExample.java:1: error: '{' expected
class BadExample(){
                ^
1 error

This might seem like gibberish, but there’s a ton of information packed in here:

  • The BadExample.java part tells you which class contains the error. This is useful if you’re compiling multiple classes.
  • The :1 part tells you which line of code has the error. In this case, the first line of code contains an error. Note that sometimes an error can impact multiple lines, so if you can’t spot an error, try looking at the lines just before the reported error.
  • The error: '{' expected tells you why the compiler can’t translate your code. In this case, it’s saying that it expected a curly bracket { character.
  • The ^ points to exactly where in the line of code the error was found. In this case, it’s pointing to the opening parenthesis ( character.

So, this error is telling us that the compiler thought it would see a curly bracket {, but it saw a parenthesis ( instead. This is a violation of the syntax for creating a class, which shouldn’t have () parentheses in the class declaration!

Now we know enough to fix our code:

class BadExample{
	public static void main(String[] args){
		System.out.println("Happy Coding!");
	}
}

Notice that we got rid of the parentheses () in the first line. This code will compile and run just fine.

It’s also possible to have more than one compiler error at a time. When this happens, always start with the first error. Fix that, and then try to compile again. Sometimes one syntax error can lead to multiple compiler errors. You should also make sure that you’ve split your problem up and you’re working on one small step. You don’t want to write 100 lines of code before compiling. Write a couple lines of code at a time, and compile as often as possible so you find errors as soon as you make them.

Runtime Errors

Even if you don’t get any compiler errors and the compiler translates your .java file into a .class file that you can run, your code still might contain other errors that the compiler can’t detect. Here’s an example:

public class ArgsPrinter{
	public static void main(String[] args){
		System.out.println(args[99]);
	}
}

This code prints the 100th argument from the args array (remember arrays are 0 based, so index 99 is the 100th index). It will compile fine, because the compiler has no way of knowing how many arguments you’re going to give your program until you actually run it.

But what happens if you run it but only give it 3 arguments?

> java ArgsPrinter
>java ArgsPrinter one two three
Exception in thread "main" java.lang.ArrayIndexOutOfBoundsException: 99
        at ArgsPrinter.main(ArgsPrinter.java:3)

You get a runtime error, which means that even though your code “looks” okay, it did something bad when it actually ran. Let’s look at the error message in more detail:

  • The Exception in thread "main" part tells us that we got a runtime error.
  • The java.lang.ArrayIndexOutOfBoundsException part tells you what type of error occurred. This is a class name that you can look up in the Java API. In this case, we’re getting an ArrayIndexOutOfBoundsException, which the Java API tells us means that “the index is either negative or greater than or equal to the size of the array.”
  • The 99 part gives you more information about the error. In this case it’s telling us that we tried to access the 99th index of an array.
  • The at ArgsPrinter.main(ArgsPrinter.java:3) part is called a stack trace, and it tells us which class, function, and line number the error occured on. In this case, the error occured on line 3 of the ArgsPrinter class, inside the main() function.

In this case the error was caused by accessing an index that the array didn’t have. We only gave the program 3 arguments, so the index only had 3 indexes. Then we tried to access index 99, which caused an error.

Stack Traces

Let’s look at another example that throws a runtime exception. Can you spot the error before running the code?

import java.util.ArrayList;

public class RuntimeErrorExample{

	private ArrayList<String> list = new ArrayList<String>();
	
	public void printLastThing(){
		int lastIndex = list.size() - 1;
		String thing = list.get(lastIndex);
		System.out.println(thing);
	}
	
	public static void main(String[] args){
		RuntimeErrorExample example = new RuntimeErrorExample();
		example.printLastThing();
	}
}

This code defines a RuntimeErrorExample class that contains one ArrayList variable named list. It also defines a function named printLastThing() that prints the last item in the ArrayList. The logic is correct: like arrays, ArrayList objects are 0 based, so if an ArrayList contains 5 items, the last item is at index 4. So getting its size and subtrating 1 will give us the last index.

The main() function then creates an instance of the class and calls the printLastThing() function. But when we run it, we get this runtime error:

>java RuntimeErrorExample
Exception in thread "main" java.lang.ArrayIndexOutOfBoundsException: -1
        at java.util.ArrayList.elementData(ArrayList.java:418)
        at java.util.ArrayList.get(ArrayList.java:431)
        at RuntimeErrorExample.printLastThing(RuntimeErrorExample.java:9)
        at RuntimeErrorExample.main(RuntimeErrorExample.java:15)

We’re getting an ArrayIndexOutOfBoundsException just like before, and we can see that we’re trying to access index -1, which causes an error because the index can’t be negative.

Notice that the stack trace now contains 4 lines. You might see that the error is actually happening inside the ArrayList class. Before you assume you found a bug in the ArrayList class, let’s take a closer look at the rest of the stack trace!

The stack trace shows you the sequence of events that lead to to the error happening. To make sense of a stack trace, read it from the bottom to the top:

  • at RuntimeErrorExample.main(RuntimeErrorExample.java:15): This tells us that the code started out in the main() function, and that it got to line 15 before calling another function.
  • at RuntimeErrorExample.printLastThing(RuntimeErrorExample.java:9): Then the main() function called the printLastThing() function. The printLastThing() function got to line 9 of the RuntimeErrorExample class before calling another function.
  • at java.util.ArrayList.get(ArrayList.java:431): The printLastThing() function then called the get() function in the ArrayList class. Inside the ArrayList class, the get() function got to line 431 before calling another function.
  • at java.util.ArrayList.elementData(ArrayList.java:418): Finally, line 418 of the ArrayList class, inside the elementData() function, the error actually happens.

So, even though the error is coming from inside the ArrayList class, we can use the stack trace to work backwards and find out where in our code the cause of the error came from.

In this example, the error is happening because we never actually add anything to the ArrayList, so its size is 0. Then we subtract 1, which gives us -1, and we use that as an index. That causes the error.

Catching Exceptions

We could prevent the ArrayIndexOutOfBoundsException by using an if statement that checks to make sure the index is valid before using it. Or we could use the isEmpty() function that ArrayList gives us:

import java.util.ArrayList;

public class RuntimeErrorExample{

	private ArrayList<String> list = new ArrayList<String>();
	
	public void printLastThing(){
		if(list.isEmpty()){
			System.out.println("You forgot to add something to the ArrayList.");
		}
		else{
			int lastIndex = list.size() - 1;
			String thing = list.get(lastIndex);
			System.out.println(thing);
		}
	}
	
	public static void main(String[] args){
		RuntimeErrorExample example = new RuntimeErrorExample();
		example.printLastThing();
	}
}

Now when we call the printLastThing() function, we first check if the list is empty, and print a friendly message if it is. Then only if it’s not empty, we get the last index and print out the last item.

It’s always a good idea to idiot-proof your code like this.

Another way to protect your code from exceptions is using try and catch blocks. You put code that might cause an error inside a try block, and you put code you want to happen in case of an error inside a catch block. It looks like this:

try{
	//dangerous code here
}
//exception that might happen here
catch(Exception e){
	//code you want to run when an error happens
}

Here’s the above example again, using a try and catch block instead of an if statement:

import java.util.ArrayList;

public class RuntimeErrorExample{

	private ArrayList<String> list = new ArrayList<String>();
	
	public void printLastThing(){
		
		try{
			int lastIndex = list.size() - 1;
			
			//this line throws an exception
			String thing = list.get(lastIndex); 
			
			//this line won't be called!
			System.out.println(thing);
		}
		catch(ArrayIndexOutOfBoundsException e){
			//the program "shortcuts" to this code when an exception happens
			System.out.println("You forgot to add something to the ArrayList.");
		}
	}
	
	public static void main(String[] args){
		RuntimeErrorExample example = new RuntimeErrorExample();
		example.printLastThing();
	}
}

Now, when the String thing = list.get(lastIndex); line causes an ArrayIndexOutOfBoundsException, the program automatically jumps to the code inside the catch block. This means that the System.out.println(thing); line is not run. Instead, the code inside the catch block is run instead.

Also note that the code inside the catch block is only run when an exception is thrown. If no exception is thrown, then the code inside the catch block is skipped.

Also note that the catch block is given an instance of a class representing the error that occurred. You should check the Java API for useful function, but one you’ll use all the time is printStackTrace():

catch(ArrayIndexOutOfBoundsException e){
	System.out.println("You forgot to add something to the ArrayList.");
	e.printStackTrace();
}

This lets you add a friendly error message, but still prints the stack trace to the console so you can figure out exactly what caused the error.

Checked Exceptions

In the above code, note that we could use a try and catch block, but we didn’t have to. That’s because ArrayIndexOutOfBoundsException is an unchecked exception. If a function might throw an unchecked exception, you don’t have to do anything special.

However, functions can also throw checked exceptions, which you do have to catch. Look at this program:

import java.io.PrintWriter;

public class FileMaker{

	public static void main(String[] args){
		PrintWriter output = new PrintWriter("OutputFile.txt");
		output.write("Happy Coding!");
		output.close();
	}
}

This code uses the PrintWriter class to create a file named OutputFile.txt. First, we create an instance of PrintWriter and give it the name of a file to create. Then we write the contents of the file, and finally we call the close() function to free the file up (otherwise we might get errors when we try to open the file in a text editor). As always, you should check out the Java API to learn more about new classes.

But if you try to compile this code, you’ll get an error:

> javac FileMaker.java
FileMaker.java:6: error: unreported exception FileNotFoundException; must be caught or declared to be thrown
                PrintWriter output = new PrintWriter("OutputFile.txt");
                                     ^
1 error

This error tells us that the PrintWriter output = new PrintWriter("OutputFile.txt"); line of code can give us a FileNotFoundException, so we have to use a try and catch block with this code. That’s because FileNotFoundException is a checked exception, so we have to specifically catch possible errors.

So, we can put our code inside a try block, and we add a catch block that catches the FileNotFoundException. We just call the printStackTrace() function so we can debug the error if it ever happens.

import java.io.PrintWriter;
import java.io.FileNotFoundException;

public class FileMaker{

	public static void main(String[] args){
		try{
			PrintWriter output = new PrintWriter("OutputFile.txt");
			output.write("Happy Coding!");
			output.close();
		}
		catch(FileNotFoundException e){
			e.printStackTrace();
		}
	}
}

Now we’re specifically catching the FileNotFoundException, so the compiler is happy and our code is safe.

Note: Never leave a catch block empty! You’ll have no way to know that anything went wrong, which makes it very hard to debug your code when something does go wrong. And you’ve probably learned by now that things do go wrong all the time when you’re programming! So at least put a call to printStackTrace() inside a catch block, even if you don’t think the exception will ever actually happen.

Logic Errors

Sometimes you’ll write code that compiles, and doesn’t throw any runtime exceptions, but still doesn’t work how you expected it to. This is almost always caused by a logic error, and it’s usually a result of the programmer (that’s you!) making an assumption or a typo.

Let’s look at this program:

public class ArrayCounter{

	public static int countArray(int[] array){
		int total = 0;
		for(int i = 1; i < array.length; i++){
			total += array[i];
		}
		return total;
	}
	
	public static void main(String[] args){
		int[] array = {1, 2, 3};
		int total = countArray(array);
		System.out.println("The total is: " + total);
	}
}

This program creates a countArray() function that takes an int[] array parameter. It loops over the array and adds every number to the total, which it then returns. Then the main() function creates an array, calls the countArray() function with it, and then prints out the resulting total.

If you compile and run this program, you’ll see that it prints out The total is: 5, even though the total should be 6! Can you spot the problem?

The problem is this line of code:

for(int i = 1; i < array.length; i++){

Remember that arrays are 0-based, so the first index is always 0, not 1. So this loop actually starts at the second index, and it skips the first number! To fix the logic error, we need to make the loop start at 0:

for(int i = 0; i < array.length; i++){

But even if we fix that error, things can still be wrong. Try compiling and running this:

public class ArrayCounter{

	public static int countArray(int[] array){
		int total = 0;
		for(int i = 0; i < array.length; i++){
			total += array[i];
		}
		return total;
	}
	
	public static void main(String[] args){
		int oneBillion = 1000000000;
		int[] array = {oneBillion, oneBillion, oneBillion};
		int total = countArray(array);
		System.out.println("The total is: " + total);
	}
}

You might expect this to print out 3 billion, but it actually prints out a negative number! What’s going on?

Remember that the different number types (like int and double) hold different types of numbers. The int type holds whole numbers, but they have to be between -2,147,483,648 and 2,147,483,647. This is because the number is stored in a 32-digit binary number, but you don’t really have to understand that part. The point is that when we try to hold 3 billion in an int value, the number goes over the limit and starts back over at the beginning, which is a negative number. That’s why we get a negative number instead of 3 billion.

To fix this error, we could use a long variable, which can hold larger values. For more info on data types in Java, check out the Java documentation.

The lesson is that even if you write code that compiles and runs without any exceptions, it still might contain logic errors. This doesn’t mean you’re a bad programmer! They happen all the time to every single one of us.

Debugging

When you encounter a runtime exception or a logic error, that means it’s time to debug your program. You need to figure out exactly what’s going on in your code, and exactly what in the code is behaving differently from what you expected.

One of the easiest ways to do that is by adding System.out.println() statements to your code. This can help you figure out the values of variables, which functions are being called in what order, how many times a loop is iterating, etc.

Let’s say we have a goal of writing a function that takes a String direction as a parameter, and returns the direction after rotating 90 degrees. We might write this program:

public class DirectionRotater{
	
	public static String rotate(String direction){
		if(direction.equals("up")){
			direction = "right";
		}
		if(direction.equals("right")){
			direction = "down";
		}
		if(direction.equals("down")){
			direction = "left";
		}
		if(direction.equals("left")){
			direction = "up";
		}
		return direction;
	}
	
	public static void main(String[] args){
		String direction = "up";
		direction = rotate(direction);
		direction = rotate(direction);
		System.out.println("Direction: " + direction);
	}
}

This program creates a rotate() function that takes a String parameter. Depending on the value of that parameter, the function reassigns the variable to be a rotated direction: up turns into right, right turns into down, down turns into left, and left turns into up. If this doesn’t make sense, look at the arrow keys on your keyboard, and imagine rotating each key by 90 degrees. Then the function just returns the value.

The main() function then creates a direction variable with a value of "up". The code passes that into the rotate() function, and then reassigns the direction variable to the value returned from that function. It does this twice, so we’d expect the printed direction to be down. But instead, we see that the direction is up!

> java DirectionRotater
Direction: up

(In fact, no matter what direction we pass into the rotate() function, it always returns "up"!)

To figure out what’s going on, we need to read through the program and make sure each line of code is doing what we expect it to. Try reading through the code in your head first, trying to figure out exactly what each line does. Use a piece of paper to jot down variable values.

If you still can’t figure it out, then you should add print statements to your program. Add as many as it takes to figure out exactly what the code is doing.

public class DirectionRotater{
	
	public static String rotate(String direction){
		System.out.println("rotate function got param: " + direction);
		if(direction.equals("up")){
			System.out.println("Entered first if statement.");
			direction = "right";
			System.out.println("Direction is now: " + direction);
		}
		if(direction.equals("right")){
			System.out.println("Entered second if statement.");
			direction = "down";
			System.out.println("Direction is now: " + direction);
		}
		if(direction.equals("down")){
			System.out.println("Entered third if statement.");
			direction = "left";
			System.out.println("Direction is now: " + direction);
		}
		if(direction.equals("left")){
			System.out.println("Entered fourth if statement.");
			direction = "up";
			System.out.println("Direction is now: " + direction);
		}
		
		System.out.println("Returning: " + direction);
		return direction;
	}
	
	public static void main(String[] args){
		String direction = "up";
		System.out.println("Direction starts as: " + direction);
		direction = rotate(direction);
		System.out.println("Rotated once. Direction is now: " + direction);
		direction = rotate(direction);
		System.out.println("Rotated twice. Direction is now: " + direction);
		System.out.println("Direction: " + direction);
	}
}

We’re using System.out.println() to figure out exactly which functions are being called, which if statements are being entered, and the value of variables. Now when we run the code, we see this:

> java DirectionRotater
Direction starts as: up
rotate function got param: up
Entered first if statement.
Direction is now: right
Entered second if statement.
Direction is now: down
Entered third if statement.
Direction is now: left
Entered fourth if statement.
Direction is now: up
Returning: up
Rotated once. Direction is now: up
rotate function got param: up
Entered first if statement.
Direction is now: right
Entered second if statement.
Direction is now: down
Entered third if statement.
Direction is now: left
Entered fourth if statement.
Direction is now: up
Returning: up
Rotated twice. Direction is now: up
Direction: up

Now if we step through the code while reading these print statements, we can see that the rotate() function is getting the correct parameter, but for some reason it’s entering every single if statement instead of just one of them.

This is because we forgot the else part of our if statements! So the rotate() function reaches the first if statement, which it enters because direction starts out as "up". It reassigns direction to be "right”, which is correct so far. But then it looks at the next if statement, which checks whether direction is "right"! It is, so it reassigns it to be "down". This process repeats for all of the if statements, until the last one reassigns direction to be "up".

To fix this, we need to use else if statements:

if(direction.equals("up")){
	direction = "right";
}
else if(direction.equals("right")){
	direction = "down";
}
else if(direction.equals("down")){
	direction = "left";
}
else if(direction.equals("left")){
	direction = "up";
}

Now when one of the if statements is entered, it doesn’t evaluate any of the other if statements. This causes the direction to be rotated only once, which was our original goal!

Let’s look at another example. Let’s say we have a goal of creating a class that represents a line segment. It should hold two Point objects and contain a getLength() function that returns the distance between those points. We might write this code:

import java.awt.Point;

public class LineSegment{

	private Point startPoint;
	private Point endPoint;
	
	public LineSegment(Point startPoint, Point endPoint){
		startPoint = startPoint;
		endPoint = endPoint;
	}
	
	public double getLength(){
		double distance = Math.sqrt(Math.pow(endPoint.getX() - startPoint.getX(), 2) + Math.pow(endPoint.getY() - startPoint.getY(), 2));
		return distance;
	}
	
	public static void main(String[] args){
		Point pointOne = new Point(1, 2);
		Point pointTwo = new Point(100, 200);
		LineSegment line = new LineSegment(pointOne, pointTwo);
		System.out.println("Length: " + line.getLength());
	}
}

This class contains two instances of the Point class (as always, you should check out the Java API whenever you see a class you haven’t seen before) and uses the distance formula to find the length of the line segment.

However, if you run the code you’ll see that the code hits a NullPointerException:

> java LineSegment
Exception in thread "main" java.lang.NullPointerException
        at LineSegment.getLength(LineSegment.java:14)
        at LineSegment.main(LineSegment.java:22)

NullPointerException is probably the most common runtime error, and it means that your code uses a variable that doesn’t have a value. You can debug a NullPointerException exactly like any other error: by stepping through the code and understanding exactly what each line does, and by adding print statements that help you understand exactly what’s happening.

For example, the stack trace tells us that the error is happening on this line:

double distance = Math.sqrt(Math.pow(endPoint.getX() - startPoint.getX(), 2) + Math.pow(endPoint.getY() - startPoint.getY(), 2));
		return distance;

Which means that one of the variables on that line doesn’t have a value. More specifically, the value is null. To figure out exactly which variable is null, we can print out their values just before the line that hits the exception:

public double getLength(){
	System.out.println("startPoint: " + startPoint);
	System.out.println("endPoint: " + endPoint);
	double distance = Math.sqrt(Math.pow(endPoint.getX() - startPoint.getX(), 2) + Math.pow(endPoint.getY() - startPoint.getY(), 2));
	return distance;
}

When we run that code, we can see that both startPoint and endPoint are null!

> java LineSegment

startPoint: null
endPoint: null

Exception in thread "main" java.lang.NullPointerException
        at LineSegment.getLength(LineSegment.java:16)
        at LineSegment.main(LineSegment.java:24)

So now we have to work backwards and find out why those values are null. We could add more print statements:

import java.awt.Point;

public class LineSegment{

	private Point startPoint;
	private Point endPoint;
	
	public LineSegment(Point startPoint, Point endPoint){
		System.out.println("in constructor, parameter startPoint: " + startPoint);
		System.out.println("in constructor, parameter endPoint: " + endPoint);
		
		startPoint = startPoint;
		endPoint = endPoint;
		
		System.out.println("in constructor, this.startPoint: " + this.startPoint);
		System.out.println("in constructor, this.endPoint: " + this.endPoint);
	}
	
	public double getLength(){
		System.out.println("startPoint: " + startPoint);
		System.out.println("endPoint: " + endPoint);
		double distance = Math.sqrt(Math.pow(endPoint.getX() - startPoint.getX(), 2) + Math.pow(endPoint.getY() - startPoint.getY(), 2));
		return distance;
	}
	
	public static void main(String[] args){
		Point pointOne = new Point(1, 2);
		Point pointTwo = new Point(100, 200);
		
		System.out.println("in main, pointOne: " + pointOne);
		System.out.println("in main, pointTwo: " + pointTwo);
		
		LineSegment line = new LineSegment(pointOne, pointTwo);
		System.out.println("Length: " + line.getLength());
	}
}

Then we can run that code to get the output:

> java LineSegment
in main, pointOne: java.awt.Point[x=1,y=2]
in main, pointTwo: java.awt.Point[x=100,y=200]
in constructor, parameter startPoint: java.awt.Point[x=1,y=2]
in constructor, parameter endPoint: java.awt.Point[x=100,y=200]
in constructor, this.startPoint: null
in constructor, this.endPoint: null
startPoint: null
endPoint: null

Exception in thread "main" java.lang.NullPointerException
        at LineSegment.getLength(LineSegment.java:22)
        at LineSegment.main(LineSegment.java:34)

Now you can use the output to help you trace through the code in your head. You can see that the points have values inside the main() function, and the parameters are passed correctly. But then the class-level variables aren’t set, which is why they’re null when we call the getLength() function. So something is wrong with how we’re setting the class-level variables using the parameter variables:

startPoint = startPoint;
endPoint = endPoint;

Now that you have the problem narrowed down to just a couple lines, you can go back and read the tutorials for what those lines are doing. In this case, we’re creating a class. You might read through that and realize that we needed to use the this keyword to reference the class-level variables! Without that, these lines are just assigning the parameters back to themselves, which doesn’t change anything. We needed to do this:

this.startPoint = startPoint;
this.endPoint = endPoint;

Now our code sets the class-level variables to the values of the parameters. Now our code works fine!

> java LineSegment
Length: 221.37072977247917

If you still can’t figure it out after debugging, adding print statements, and narrowing it down to just a few lines that aren’t behaving correctly, then you can get help by posting in the forum!

General Tips

Debugging can be frustrating, but it’s a huge part of being a programmer. Here are a couple tips to keep yourself sane:

  • Blame yourself first. It can be tempting to assume you found a bug in Java, or in the library you’re using. And while it’s not impossible that you found a bug, it’s much more likely that it’s a bug in your code. So you should ask yourself “what am I doing wrong?” and “which of my assumptions is incorrect?” instead of blaming the code.
  • Don’t take it personally. Those questions don’t mean that you’re a bad programmer. Bugs happen to every single programmer, every single time they sit down to write code. So try not to get frustrated, especially when people ask you to narrow your problem down or debug your program. Just go through the process we just talked about: run through your code in your head, and use print statements to figure out what’s going on.
  • Work in small chunks. Don’t try to write your program all at one time. You should be recompiling as often as possible- after every line if you can. Test single methods by themselves with hard-coded values, and make sure it’s doing exactly what you expected before you move on to the next step. That will also make it easier to get help when you do get stuck!

If all else fails, sometimes the best thing you can do is take a break. Go on a walk, pet your cat, and try to clear your head. You’ll be amazed at how many solutions you end up thinking of in the shower.

Homework

  • Write a program that outputs 100 random points to a text file. Write another program that reads in those points and prints out the center of all those points.

An exception (or exceptional event) is a problem that arises during the execution of a program. When an Exception occurs the normal flow of the program is disrupted and the program/Application terminates abnormally, which is not recommended, therefore, these exceptions are to be handled.

An exception can occur for many different reasons. Following are some scenarios where an exception occurs.

  • A user has entered an invalid data.

  • A file that needs to be opened cannot be found.

  • A network connection has been lost in the middle of communications or the JVM has run out of memory.

Some of these exceptions are caused by user error, others by programmer error, and others by physical resources that have failed in some manner.

Based on these, we have three categories of Exceptions. You need to understand them to know how exception handling works in Java.

  • Checked exceptions − A checked exception is an exception that is checked (notified) by the compiler at compilation-time, these are also called as compile time exceptions. These exceptions cannot simply be ignored, the programmer should take care of (handle) these exceptions.

For example, if you use FileReader class in your program to read data from a file, if the file specified in its constructor doesn’t exist, then a FileNotFoundException occurs, and the compiler prompts the programmer to handle the exception.

Example

import java.io.File;
import java.io.FileReader;

public class FilenotFound_Demo {

   public static void main(String args[]) {		
      File file = new File("E://file.txt");
      FileReader fr = new FileReader(file); 
   }
}

If you try to compile the above program, you will get the following exceptions.

Output

C:>javac FilenotFound_Demo.java
FilenotFound_Demo.java:8: error: unreported exception FileNotFoundException; must be caught or declared to be thrown
      FileReader fr = new FileReader(file);
                      ^
1 error

Note − Since the methods read() and close() of FileReader class throws IOException, you can observe that the compiler notifies to handle IOException, along with FileNotFoundException.

  • Unchecked exceptions − An unchecked exception is an exception that occurs at the time of execution. These are also called as Runtime Exceptions. These include programming bugs, such as logic errors or improper use of an API. Runtime exceptions are ignored at the time of compilation.

For example, if you have declared an array of size 5 in your program, and trying to call the 6th element of the array then an ArrayIndexOutOfBoundsExceptionexception occurs.

Example

public class Unchecked_Demo {
   
   public static void main(String args[]) {
      int num[] = {1, 2, 3, 4};
      System.out.println(num[5]);
   }
}

If you compile and execute the above program, you will get the following exception.

Output

Exception in thread "main" java.lang.ArrayIndexOutOfBoundsException: 5
	at Exceptions.Unchecked_Demo.main(Unchecked_Demo.java:8)
  • Errors − These are not exceptions at all, but problems that arise beyond the control of the user or the programmer. Errors are typically ignored in your code because you can rarely do anything about an error. For example, if a stack overflow occurs, an error will arise. They are also ignored at the time of compilation.

Exception Hierarchy

All exception classes are subtypes of the java.lang.Exception class. The exception class is a subclass of the Throwable class. Other than the exception class there is another subclass called Error which is derived from the Throwable class.

Errors are abnormal conditions that happen in case of severe failures, these are not handled by the Java programs. Errors are generated to indicate errors generated by the runtime environment. Example: JVM is out of memory. Normally, programs cannot recover from errors.

The Exception class has two main subclasses: IOException class and RuntimeException Class.

Exceptions1

Following is a list of most common checked and unchecked Java’s Built-in Exceptions.

Exceptions Methods

Following is the list of important methods available in the Throwable class.

Sr.No. Method & Description
1

public String getMessage()

Returns a detailed message about the exception that has occurred. This message is initialized in the Throwable constructor.

2

public Throwable getCause()

Returns the cause of the exception as represented by a Throwable object.

3

public String toString()

Returns the name of the class concatenated with the result of getMessage().

4

public void printStackTrace()

Prints the result of toString() along with the stack trace to System.err, the error output stream.

5

public StackTraceElement [] getStackTrace()

Returns an array containing each element on the stack trace. The element at index 0 represents the top of the call stack, and the last element in the array represents the method at the bottom of the call stack.

6

public Throwable fillInStackTrace()

Fills the stack trace of this Throwable object with the current stack trace, adding to any previous information in the stack trace.

Catching Exceptions

A method catches an exception using a combination of the try and catch keywords. A try/catch block is placed around the code that might generate an exception. Code within a try/catch block is referred to as protected code, and the syntax for using try/catch looks like the following −

Syntax

try {
   // Protected code
} catch (ExceptionName e1) {
   // Catch block
}

The code which is prone to exceptions is placed in the try block. When an exception occurs, that exception occurred is handled by catch block associated with it. Every try block should be immediately followed either by a catch block or finally block.

A catch statement involves declaring the type of exception you are trying to catch. If an exception occurs in protected code, the catch block (or blocks) that follows the try is checked. If the type of exception that occurred is listed in a catch block, the exception is passed to the catch block much as an argument is passed into a method parameter.

Example

The following is an array declared with 2 elements. Then the code tries to access the 3rd element of the array which throws an exception.

// File Name : ExcepTest.java
import java.io.*;

public class ExcepTest {

   public static void main(String args[]) {
      try {
         int a[] = new int[2];
         System.out.println("Access element three :" + a[3]);
      } catch (ArrayIndexOutOfBoundsException e) {
         System.out.println("Exception thrown  :" + e);
      }
      System.out.println("Out of the block");
   }
}

This will produce the following result −

Output

Exception thrown  :java.lang.ArrayIndexOutOfBoundsException: 3
Out of the block

Multiple Catch Blocks

A try block can be followed by multiple catch blocks. The syntax for multiple catch blocks looks like the following −

Syntax

try {
   // Protected code
} catch (ExceptionType1 e1) {
   // Catch block
} catch (ExceptionType2 e2) {
   // Catch block
} catch (ExceptionType3 e3) {
   // Catch block
}

The previous statements demonstrate three catch blocks, but you can have any number of them after a single try. If an exception occurs in the protected code, the exception is thrown to the first catch block in the list. If the data type of the exception thrown matches ExceptionType1, it gets caught there. If not, the exception passes down to the second catch statement. This continues until the exception either is caught or falls through all catches, in which case the current method stops execution and the exception is thrown down to the previous method on the call stack.

Example

Here is code segment showing how to use multiple try/catch statements.

try {
   file = new FileInputStream(fileName);
   x = (byte) file.read();
} catch (IOException i) {
   i.printStackTrace();
   return -1;
} catch (FileNotFoundException f) // Not valid! {
   f.printStackTrace();
   return -1;
}

Catching Multiple Type of Exceptions

Since Java 7, you can handle more than one exception using a single catch block, this feature simplifies the code. Here is how you would do it −

catch (IOException|FileNotFoundException ex) {
   logger.log(ex);
   throw ex;

The Throws/Throw Keywords

If a method does not handle a checked exception, the method must declare it using the throws keyword. The throws keyword appears at the end of a method’s signature.

You can throw an exception, either a newly instantiated one or an exception that you just caught, by using the throw keyword.

Try to understand the difference between throws and throw keywords, throws is used to postpone the handling of a checked exception and throw is used to invoke an exception explicitly.

The following method declares that it throws a RemoteException −

Example

import java.io.*;
public class className {

   public void deposit(double amount) throws RemoteException {
      // Method implementation
      throw new RemoteException();
   }
   // Remainder of class definition
}

A method can declare that it throws more than one exception, in which case the exceptions are declared in a list separated by commas. For example, the following method declares that it throws a RemoteException and an InsufficientFundsException −

Example

import java.io.*;
public class className {

   public void withdraw(double amount) throws RemoteException, 
      InsufficientFundsException {
      // Method implementation
   }
   // Remainder of class definition
}

The Finally Block

The finally block follows a try block or a catch block. A finally block of code always executes, irrespective of occurrence of an Exception.

Using a finally block allows you to run any cleanup-type statements that you want to execute, no matter what happens in the protected code.

A finally block appears at the end of the catch blocks and has the following syntax −

Syntax

try {
   // Protected code
} catch (ExceptionType1 e1) {
   // Catch block
} catch (ExceptionType2 e2) {
   // Catch block
} catch (ExceptionType3 e3) {
   // Catch block
}finally {
   // The finally block always executes.
}

Example

public class ExcepTest {

   public static void main(String args[]) {
      int a[] = new int[2];
      try {
         System.out.println("Access element three :" + a[3]);
      } catch (ArrayIndexOutOfBoundsException e) {
         System.out.println("Exception thrown  :" + e);
      }finally {
         a[0] = 6;
         System.out.println("First element value: " + a[0]);
         System.out.println("The finally statement is executed");
      }
   }
}

This will produce the following result −

Output

Exception thrown  :java.lang.ArrayIndexOutOfBoundsException: 3
First element value: 6
The finally statement is executed

Note the following −

  • A catch clause cannot exist without a try statement.

  • It is not compulsory to have finally clauses whenever a try/catch block is present.

  • The try block cannot be present without either catch clause or finally clause.

  • Any code cannot be present in between the try, catch, finally blocks.

The try-with-resources

Generally, when we use any resources like streams, connections, etc. we have to close them explicitly using finally block. In the following program, we are reading data from a file using FileReader and we are closing it using finally block.

Example

import java.io.File;
import java.io.FileReader;
import java.io.IOException;

public class ReadData_Demo {

   public static void main(String args[]) {
      FileReader fr = null;		
      try {
         File file = new File("file.txt");
         fr = new FileReader(file); char [] a = new char[50];
         fr.read(a);   // reads the content to the array
         for(char c : a)
         System.out.print(c);   // prints the characters one by one
      } catch (IOException e) {
         e.printStackTrace();
      }finally {
         try {
            fr.close();
         } catch (IOException ex) {		
            ex.printStackTrace();
         }
      }
   }
}

try-with-resources, also referred as automatic resource management, is a new exception handling mechanism that was introduced in Java 7, which automatically closes the resources used within the try catch block.

To use this statement, you simply need to declare the required resources within the parenthesis, and the created resource will be closed automatically at the end of the block. Following is the syntax of try-with-resources statement.

Syntax

try(FileReader fr = new FileReader("file path")) {
   // use the resource
   } catch () {
      // body of catch 
   }
}

Following is the program that reads the data in a file using try-with-resources statement.

Example

import java.io.FileReader;
import java.io.IOException;

public class Try_withDemo {

   public static void main(String args[]) {
      try(FileReader fr = new FileReader("E://file.txt")) {
         char [] a = new char[50];
         fr.read(a);   // reads the contentto the array
         for(char c : a)
         System.out.print(c);   // prints the characters one by one
      } catch (IOException e) {
         e.printStackTrace();
      }
   }
}

Following points are to be kept in mind while working with try-with-resources statement.

  • To use a class with try-with-resources statement it should implement AutoCloseable interface and the close() method of it gets invoked automatically at runtime.

  • You can declare more than one class in try-with-resources statement.

  • While you declare multiple classes in the try block of try-with-resources statement these classes are closed in reverse order.

  • Except the declaration of resources within the parenthesis everything is the same as normal try/catch block of a try block.

  • The resource declared in try gets instantiated just before the start of the try-block.

  • The resource declared at the try block is implicitly declared as final.

User-defined Exceptions

You can create your own exceptions in Java. Keep the following points in mind when writing your own exception classes −

  • All exceptions must be a child of Throwable.

  • If you want to write a checked exception that is automatically enforced by the Handle or Declare Rule, you need to extend the Exception class.

  • If you want to write a runtime exception, you need to extend the RuntimeException class.

We can define our own Exception class as below −

class MyException extends Exception {
}

You just need to extend the predefined Exception class to create your own Exception. These are considered to be checked exceptions. The following InsufficientFundsException class is a user-defined exception that extends the Exception class, making it a checked exception. An exception class is like any other class, containing useful fields and methods.

Example

// File Name InsufficientFundsException.java
import java.io.*;

public class InsufficientFundsException extends Exception {
   private double amount;
   
   public InsufficientFundsException(double amount) {
      this.amount = amount;
   }
   
   public double getAmount() {
      return amount;
   }
}

To demonstrate using our user-defined exception, the following CheckingAccount class contains a withdraw() method that throws an InsufficientFundsException.

// File Name CheckingAccount.java
import java.io.*;

public class CheckingAccount {
   private double balance;
   private int number;
   
   public CheckingAccount(int number) {
      this.number = number;
   }
   
   public void deposit(double amount) {
      balance += amount;
   }
   
   public void withdraw(double amount) throws InsufficientFundsException {
      if(amount <= balance) {
         balance -= amount;
      }else {
         double needs = amount - balance;
         throw new InsufficientFundsException(needs);
      }
   }
   
   public double getBalance() {
      return balance;
   }
   
   public int getNumber() {
      return number;
   }
}

The following BankDemo program demonstrates invoking the deposit() and withdraw() methods of CheckingAccount.

// File Name BankDemo.java
public class BankDemo {

   public static void main(String [] args) {
      CheckingAccount c = new CheckingAccount(101);
      System.out.println("Depositing $500...");
      c.deposit(500.00);
      
      try {
         System.out.println("nWithdrawing $100...");
         c.withdraw(100.00);
         System.out.println("nWithdrawing $600...");
         c.withdraw(600.00);
      } catch (InsufficientFundsException e) {
         System.out.println("Sorry, but you are short $" + e.getAmount());
         e.printStackTrace();
      }
   }
}

Compile all the above three files and run BankDemo. This will produce the following result −

Output

Depositing $500...

Withdrawing $100...

Withdrawing $600...
Sorry, but you are short $200.0
InsufficientFundsException
         at CheckingAccount.withdraw(CheckingAccount.java:25)
         at BankDemo.main(BankDemo.java:13)

Common Exceptions

In Java, it is possible to define two catergories of Exceptions and Errors.

  • JVM Exceptions − These are exceptions/errors that are exclusively or logically thrown by the JVM. Examples: NullPointerException, ArrayIndexOutOfBoundsException, ClassCastException.

  • Programmatic Exceptions − These exceptions are thrown explicitly by the application or the API programmers. Examples: IllegalArgumentException, IllegalStateException.

As developers, we would like our users to interact with applications that run smoothly and without issues. We want the libraries that we create to be widely adopted and successful. All of that will not happen without the code that handles errors.

Java exception handling is often a significant part of the application code. You might use conditionals to handle cases where you expect a certain state and want to avoid erroneous execution – for example, division by zero. However, there are cases where conditions are not known or are well hidden because of third party code. In other cases, code is designed to create an exception and throw it up the stack to allow for the graceful handling of a Java error at a higher level.

If all this is new to you, this tutorial will help you understand what Java exceptions are, how to handle them and the best practices you should follow to maintain the natural flow of the application.

What Is an Exception in Java?

An Exception is an event that causes your normal Java application flow to be disrupted. Exceptions can be caused by using a reference that is not yet initialized, dividing by zero, going beyond the length of an array, or even JVM not being able to assign objects on the heap.

In Java, an exception is an Object that wraps the error that caused it and includes information like:

  • The type of error that caused the exception with the information about it.
  • The stack trace of the method calls.
  • Additional custom information that is related to the error.

Various Java libraries throw exceptions when they hit a state of execution that shouldn’t happen – from the standard Java SDK to the enormous amounts of open source code that is available as a third-party library.

Exceptions can be created automatically by the JVM that is running our code or explicitly our code itself. We can extend the classes that are responsible for exceptions and create our own, specific Java exceptions that handle unexpected situations. But keep in mind that throwing an exception doesn’t come for free. It is expensive. The larger the call stack the more expensive the exception.

Exception handling in Java is a mechanism to process, catch and throw Java errors that signal an abnormal state of the program so that the execution of the business code can continue uninterrupted.

Why Handle Java Exceptions?

Using Java exceptions is very handy; they let you separate the business logic from the application code for handling errors. However, exceptions are neither free nor cheap. Throwing an exception requires the JVM to perform operations like gathering the full stack trace of the method calls and passing it to the method that is responsible for handling the exception. In other words, it requires additional resources compared to a simple conditional.

No matter how expensive the exceptions are, they are invaluable for troubleshooting issues. Correlating exceptions with other data like JVM metrics and various application logs can help with resolving your problems fast and in a very efficient manner.

Exception Class Hierarchy

Java is an object-oriented language, and thus, every class will extend the java.lang.Object. The same goes for the Throwable class, which is the base class for the errors and exceptions in Java. The following picture illustrates the class hierarchy of the Throwable class and its most common subclasses:

The Difference Between a Java Exception and Error

Before going into details about the Exception class, we should ask one fundamental question: What is the difference between an Error and an Exception in Java?

To answer the question, let’s look at Javadocs and start from the Throwable class. The Throwable class is the mother of all errors–the superclass of all errors and exceptions that your Java code can produce. Only objects that are instances of the Throwable class or any of its subclasses can be thrown by the code running inside the JVM or can be declared in the methods throw clause. There are two main implementations of the Throwable class.

A Java Error is a subclass of Throwable that represents a serious problem that a reasonable application should not try to catch. The method does not have to declare an Error or any of its subclasses in its throws clause for it to be thrown during the execution of a method. The most common subclasses of the Error class are Java OutOfMemoryError and StackOverflowError classes. The first one represents JVM not being able to create a new object; we discussed potential causes in our article about the JVM garbage collector. The second error represents an issue when the application recurses too deeply.

The Java Exception and its subclasses, on the other hand, represent situations that an application should catch and try to handle. There are lots of implementations of the Exception class that represent situations that your application can gracefully handle. The FileNotFoundException, SocketException, or NullPointerException are just a few examples that you’ve probably come across when writing Java applications.

Types of Java Exceptions

There are multiple implementations of the Exception class in Java. They come from the Java Development Kit itself, but also from various libraries and applications that you might be using when writing your own code. We will not discuss every Exception subclass that you can encounter, but there are two main types that you should be aware of to understand how exception handling works in Java–the checked and unchecked, aka runtime exceptions.

Checked Exceptions

The Java checked exceptions are the ones that implement the Exception class and not the RuntimeException. They are called checked exceptions because the compiler verifies them during the compile-time and refuses to compile the code if such exceptions are not handled or declared. Instead, the compiler will notify you to handle these exceptions. For example, the FileNotFoundException is an example of such an exception.

In order for a method or constructor to throw a checked exception it needs to be explicitly declared:

public CheckedExceptions() throws FileNotFoundException {
  throw new FileNotFoundException("File not found");
}

public void throwsExample() throws FileNotFoundException {
  throw new FileNotFoundException("File not found");
}

You can see that in both cases we explicitly have the throws clause mentioning the FileNotFoundException that can be thrown by the execution of the constructor of the throwsExample method. Such code will be successfully compiled and can be executed.

On the other hand, the following code will not compile:

public void wrongThrowsExample() {
  throw new FileNotFoundException("File not found");
}

The reason for the compiler not wanting to compile the above code will be raising the checked exception and not processing it. We need to either include the throws clause or handle the Java exception in the try/catch/finally block. If we were to try to compile the above code as is the following error would be returned by the compiler:

/src/main/java/com/sematext/blog/java/CheckedExceptions.java:18: error: unreported exception FileNotFoundException; must be caught or declared to be thrown
    throw new FileNotFoundException("File not found");
    ^

Unchecked Exceptions / Runtime Exceptions

The unchecked exceptions are exceptions that the Java compiler does not require us to handle. The unchecked exceptions in Java are the ones that implement the RuntimeException class. Those exceptions can be thrown during the normal operation of the Java Virtual Machine. Unchecked exceptions do not need to be declared in the method throws clause in order to be thrown. For example, this block of code will compile and run without issues:

public class UncheckedExceptions {
  public static void main(String[] args) {
    UncheckedExceptions ue = new UncheckedExceptions();
    ue.run();
  }

  public void run() {
    throwRuntimeException();
  }

  public void throwRuntimeException() {
    throw new NullPointerException("Null pointer");
  }
}

We create an UncheckedExceptions class instance and run the run method. The run method calls the throwRuntimeException method which creates a new NullPointerException. Because the NullPointerException is a subclass of the RuntimeException we don’t need to declare it in the throws clause.

The code compiles and propagates the exception up to the main method. We can see that in the output when the code is run:

Exception in thread "main" java.lang.NullPointerException: Null pointer
        at com.sematext.blog.java.UncheckedExceptions.throwRuntimeException(UncheckedExceptions.java:14)
        at com.sematext.blog.java.UncheckedExceptions.run(UncheckedExceptions.java:10)
        at com.sematext.blog.java.UncheckedExceptions.main(UncheckedExceptions.java:6)

This is exactly what we expected.

The most common subclasses of the Java RuntimeException that you probably saw already are ClassCastException, ConcurrentModificationException, IllegalArgumentException, or everyone’s favorite, NullPointerException.

Let’s now look at how we throw exceptions in Java.

How to Handle Exceptions in Java: Code Examples

Handling exceptions in Java is a game of using five keywords that combined give us the possibility of handling errors – the try, catch, finally, throw, and throws.

The first one – try is used to specify the block of code that can throw an exception:

try {
   File file = openNewFileThatMayNotExists(location);
   // process the file
}

The try block must be followed by the catch or finally blocks. The first one mentioned can be used to catch and process exceptions thrown in the try block:

try {
   ...
} catch (IOException ioe) {
   // handle missing file
}

The finally block can be used to handle the code that needs to be executed regardless of whether the exception happened or not.

The throw keyword is used to create a new Exception instance and the throws keyword is used to declare what kind of exceptions can be expected when executing a method.

When handling exceptions in Java, we don’t want to just throw the created exception to the top of the call stack, for example, to the main method. That would mean that each and every exception that is thrown would crash the application and this is not what should happen. Instead, we want to handle Java exceptions, at least the ones that we can deal with, and either help fixing the problem or fail gracefully.

Java gives us several ways to handle exceptions.

Throwing Exceptions

An Exception in Java can be handled by using the throw keyword and creating a new Exception or re-throwing an already created exception. For example, the following very naive and simple method creates an instance of the File class and checks if the file exists. If the file doesn’t exist the method throws a new IOException:

public File openFile(String path) throws IOException {
  File file = new File(path);
  if (!file.exists()) {
    throw new IOException(String.format("File %s doesn't exist", path));
  }
  // continue execution of the business logic
  return file;
}

You can also re-throw a Java exception that was thrown inside the method you are executing. This can be done by the try-catch block:

public class RethrowException {
  public static void main(String[] args) throws IOException {
    RethrowException exec = new RethrowException();
    exec.run();
  }

  public void run() throws IOException {
    try {
     methodThrowingIOE();
    } catch (IOException ioe) {
      // do something about the exception
      throw ioe;
    }
  }

  public void methodThrowingIOE() throws IOException {
    throw new IOException();
  }
}

You can see that the run method re-throws the IOException that is created in the methodThrowingIOE. If you plan on doing some processing of the exception, you can catch it as in the above example and throw it further. However, keep in mind that in most cases, this is not a good practice. You shouldn’t catch the exception, process it, and push it up the execution stack. If you can’t process it, it is usually better to pack it into a more specialized Exception class, so that a dedicated error processing code can take care of it. You can also just decide that you can’t process it and just throw it:

public class RethrowException {
  public static void main(String[] args) throws IOException {
    RethrowException exec = new RethrowException();
    exec.run();
  }

  public void run() throws IOException {
    try {
     methodThrowingIOE();
    } catch (IOException ioe) {
      throw ioe;
    }
  }

  public void methodThrowingIOE() throws IOException {
    throw new IOException();
  }
}

There are additional cases, but we will discuss them when talking about how to catch exceptions in Java.

Try-Catch Block

The simplest and most basic way to handle exceptions is to use the try – catch block. The code that can throw an exception is put into the try block and the code that should handle it is in the catch block. The exception can be either checked or unchecked. In the first case, the compiler will tell you which kind of exceptions need to be caught or defined in the method throws clause for the code to compile. In the case of unchecked exceptions, we are not obligated to catch them, but it may be a good idea – at least in some cases. For example, there is a DOMException or DateTimeException that indicate issues that you can gracefully handle.

To handle the exception, the code that might generate an exception should be placed in the try block which should be followed by the catch block. For example, let’s look at the code of the following openFileReader method:

public Reader openFileReader(String filePath) {
  try {
    return new FileReader(filePath);
  } catch (FileNotFoundException ffe) {
    // tell the user that the file was not found
  }
  return null;
}

The method tries to create a FileReader class instance. The constructor of that class can throw a checked FileNotFoundException if the file provided as the argument doesn’t exist. We could just include the FileNotFoundException in the throws clause of our openFileReader method or catch it in the catch section just like we did. In the catch section, we can do whatever we need to get a new file location, create a new file, and so on.

If we would like to just throw it further up the call stack the code could be further simplified:

public Reader openFileReaderWithThrows(String filePath) throws FileNotFoundException {
  return new FileReader(filePath);
}

This passes the responsibility of handling the FIleNotFoundException to the code that calls it.

Multiple Catch Block

We are not limited to a single catch block in the try-catch block. We can have multiple try-catch blocks that allow you to handle each exception differently, would you need that. Let’s say that we have a method that lists more than a single Java exception in its throws clause, like this:

public void readAndParse(String file) throws FileNotFoundException, ParseException {
  // some business code
}

In order to compile and run this we need multiple catch blocks to handle each of the listed Java exceptions:

public void run(String file) {
  try {
    readAndParse(file);
  } catch (FileNotFoundException ex) {
    // do something when file is not found
  } catch (ParseException ex) {
    // do something if the parsing fails
  }
}

Such code organization can be used when dealing with multiple Java exceptions that need to be handled differently. Hypothetically, the above code could ask for a new file location when the FileNotFoundException happens and inform the user of the issues with parsing when the ParseException happens.

There is one more thing we should mention when it comes to handle exceptons using multiple catch blocks. You need to remember that the order of the catch blocks matters. If you have a more specialized Java exception in the catch block after the more general exception the more specialized catch block will never be executed. Let’s look at the following example:

public void runTwo(String file) {
  try {
    readAndParse(file);
  } catch (Exception ex) {
    // this block will catch all exceptions
  } catch (ParseException ex) {
    // this block will not be executed
  }
}

Because the first catch block catches the Java Exception the catch block with the ParseException will never be executed. That’s because the ParseException is a subclass of the Exception.

Catching Multiple Exceptions

To handle multiple Java exceptions with the same logic, you can list them all inside a single catch block. Let’s redo the above example with the FileNotFoundException and the ParseException to use a single catch block:

public void runSingleCatch(String file) {
  try {
    readAndParse(file);
  } catch (FileNotFoundException | ParseException ex) {
    // do something when file is not found
  }
}

You can see how easy it is–you can connect multiple Java exceptions together using the | character. If any of these exceptions is thrown in the try block the execution will continue inside the catch block.

The Finally Block

In addition to try and the catch blocks, there is one additional section that may come in handy when handling exceptions in Java–the finally block. The finally block is the last section in your try-catch-finally expression and will always get executed–either after the try or after the catch. It will be executed even if you use the return statement in the try block, which by the way, you shouldn’t do.

Let’s look at the following example:

public void exampleOne() {
  FileReader reader = null;
  try {
    reader = new FileReader("/tmp/somefile");
    // do some processing
  } catch (FileNotFoundException ex) {
    // do something
  } finally {
    if (reader != null) {
      try {
        reader.close();
      } catch (IOException ex) {
        // do something
      }
    }
  }
}

You can see the finally block. Keep in mind that you can have at most one finally block present. The way this code will be executed is as follows:

  1. The JVM will execute the try section first and will try to create the FileReader instance.
  2. If the /tmp/somefile is present and readable the try block execution will continue.
  3. If the /tmp/somefile is not present or is not readable the FileNotFoundException will be raised and the execution of the code will go to the catch block.
  4. After 2) or 3) the finally block will be executed and will try to close the FileReader instance if it is present.

The finally section will be executed even if we modify the try block and include the return statement. The following code does exactly the same as the one above despite having the return statement at the end of the try block:

public void exampleOne() {
  FileReader reader = null;
  try {
    reader = new FileReader("/tmp/somefile");
    // do something
    return;
  } catch (FileNotFoundException ex) {
    // do something
  } finally {
    if (reader != null) {
      try {
        reader.close();
      } catch (IOException ex) {
        // do something
      }
    }
  }
}

So, why and when should you use the finally block to handle exceptions in Java? Well, it is a perfect candidate for cleaning up resources, like closing objects, calculating metrics, including Java logs about operation completion, and so on.

The Try-With-Resources Block

The last thing when it comes to handling exceptions in Java is the try-with-resources block. The idea behind that Java language structure is opening resources in the try section that will be automatically closed at the end of the statement. That means that instead of including the finally block we can just open the resources that we need in the try section and rely on the Java Virtual Machine to deal with the closing of the resource.

For the class to be usable in the try-with-resource block it needs to implement the java.lang.AutoCloseable, which includes every class implementing the java.io.Closeable interface. Keep that in mind.

An example method that reads a file using the FileReader class which uses the try-with-resources might look as follows:

public void readFile(String filePath) {
  try (FileReader reader = new FileReader(filePath)) {
    // do something
  } catch (FileNotFoundException ex) {
    // do something when file is not found
  } catch (IOException ex) {
    // do something when issues during reader close happens
  }
}

Of course, we are not limited to a single resource and we can have multiple of them, for example:

public void readFiles(String filePathOne, String filePathTwo) {
  try (
      FileReader readerOne = new FileReader(filePathOne);
      FileReader readerTwo = new FileReader(filePathTwo);
  ) {
    // do something
  } catch (FileNotFoundException ex) {
    // do something when file is not found
  } catch (IOException ex) {
    // do something when issues during reader close happens
  }
}

One thing that you have to remember is that you need to process the Java exceptions that happen during resources closing in the catch section of the try-catch-finally block. That’s why in the above examples, we’ve included the IOException in addition to the FileNotFoundException. The IOException may be thrown during FileReader closing and we need to process it.

Catching User-Defined Exceptions

The Throwable and Exception are Java classes and so you can easily extend them and create your own exceptions. Depending on if you need a checked or unchecked exception you can either extend the Exception or the RuntimeException class. To give you a very simple example on how such code might look like, have a look at the following fragment:

public class OwnExceptionExample {
  public void doSomething() throws MyOwnException {
    // code with very important logic
    throw new MyOwnException("My Own Exception!");
  }

  class MyOwnException extends Exception {
    public MyOwnException(String message) {
      super(message);
    }
  }
}

In the above trivial example we have a new Java Exception implementation called MyOwnException with a constructor that takes a single argument – a message. It is an internal class, but usually you would just move it to an appropriate package and start using it in your application code.

How to Catch Specific Java Exceptions

Catching specific Java exceptions is not very different from handling a general exception. Let’s look at the code examples. Catching exceptions that implement the Exception class is as simple as having a code similar to the following one:

try {
  // code that can result in exception throwing
} catch (Exception ex) {
  // handle exception
}

The catch block in the above example would run for every object implementing the Exception class. These include IOException, EOFException, FileNotFoundException, or the NullPointerException. But sometimes we may want to have different behavior depending on the exception that was thrown. You may want different behavior for the IOException and different for the FileNotFoundException. This can be achieved by having multiple catch blocks:

try {
  // code that can result in exception throwing
} catch (FileNotFoundException ex) {
  // handle exception
} catch (IOException ex) {
  // handle exception
}

There is one thing to remember though. The first catch clause that will match the exception class will be executed. The FileNotFoundException is a subclass of the IOException. That’s why I specified the FileNotFoundException as the first one. If I would do the opposite, the block with the IOException handling would catch all IOException instances and their subclasses. Something worth remembering.

Finally, we’ve mentioned that before, but I wanted to repeat myself here – if you would like to handle numerous exceptions with the same code you can do that by combining them in a single catch block:

try {
  // code that can result in exception throwing
} catch (FileNotFoundException | EOFException ex) {
  // handle exception
} catch (IOException ex) {
  // handle exception
}

That way you don’t have to duplicate the code.

Java Exception Handling Best Practices

There are a lot of best practices when it comes to handling exceptions in the Java Virtual Machine world, but I find a few of them useful and important.

Keep Exceptions Use to a Minimum

Every time you throw an Exception it needs to be handled by the JVM. Throwing an exception doesn’t cost much, but for example, getting the stack trace for the exception is noticeable, especially when you deal with a large number of concurrent requests and get the stack trace for every exception.

What I will say is not true for every situation and for sure makes the code a bit uglier, but if you want to squeeze every bit of performance from your code, try to avoid Java exceptions when a simple comparison is enough. Look at the following method:

public int divide(int dividend, int divisor) {
  try {
    return dividend / divisor;
  } catch (ArithmeticException ex) {
    LOG.error("Error while division, stack trace:", ex.getStackTrace());
  }
  return -1;
}

It tries to divide two numbers and catches the ArithmeticException in case of a Java error. What kind of error can happen here? Well, division by zero is the perfect example. If the divisor argument is 0 the code will throw an exception, catch it to avoid failure in the code and continue returning -1. This is not the perfect way to go since throwing a Java exception has a performance penalty – we talk about it later in the blog post. In such cases, you should check the divisor argument and allow the division only if it is not equal to 0, just like this:

public int divide(int dividend, int divisor) {
  if (divisor != 0) {
    return 10 / divisor;
  }
  return -1;
}

The performance of throwing an exception is not high, but parts of the error handling code may be expensive – for example stack trace retrieval. Keep that in mind when writing your code that handles Java exceptions and situations that should not be allowed.

Always Handle Exceptions, Don’t Ignore Them

Always handle the Java Exception, unless you don’t care about one. But if you think that you should ignore one, think twice. The methods that you call throw exceptions for a reason and you may want to process them to avoid problematic situations.

Process the exceptions, log them, or just print them to the console. Avoid doing things you can see in the following code:

try {
  FileReader reader = new FileReader(filePath);
  // some business code
} catch (FileNotFoundException ex) {}

As you can see in the code above the FileNotFoundException is hidden and we don’t have any idea that the creation of the FileReader failed. Of course, the code that runs after the creation of the FileReader would probably fail if it were to operate on that. Now imagine that you are catching Java exceptions like this:

try {
  FileReader reader = new FileReader(filePath);
  // some business code
} catch (Exception ex) {}

You would catch lots of Java exceptions and completely ignore them all. The least you would like to do is fail and log the information so that you can easily find the problem when doing log analysis or setting up an alert in your log centralization solution. Of course, you may want to process the exception, maybe do some interaction with external systems or the user itself, but for sure not hide the problem.

If you really don’t want to handle an exception in Java you can just print it to the log or error stream, for example:

try {
  FileReader reader = new FileReader(filePath);
  // some business code
} catch (Exception ex) {
  ex.printStackTrace();
}

Or even better, if you are using a centralized logging solution just do the following to store the error log there:

try {
  FileReader reader = new FileReader(filePath);
  // some business code
} catch (Exception ex) {
  LOG.error("Error during FileReader creation", ex);
}

Use Descriptive Messages When Throwing Exceptions

When using exceptions, think about the person who will be looking at the logs or will be troubleshooting your application. Think about what kind of information will be needed to quickly and efficiently find the root cause of the problem – Java exceptions in our case.

When throwing an exception you can use code like this:

throw new FileNotFoundException(“file not found”);

Or code that looks like this:

throw new FileNotFoundException(String.format(“File %s not found in directory %s”, file, directory));

The first one will just say that some mystery file was not found. The person that will try to diagnose and fix the problem will not know which and where the file is expected to be. The second example explicitly mentions which file is expected and where – and it is exactly what you should do when throwing exceptions.

Never Use Return Statement in the Finally Block

The finally block is the place in which you can execute code regardless if the exception happened or not – for example close the opened resources to avoid leaks. The next thing you should avoid is using the return statement in the finally block of your code. Have a look at the following code fragment:

public class ReturnInFinally {
  public static void main(String[] args) {
    ReturnInFinally app = new ReturnInFinally();
    app.example();
    System.out.println("Ended without error");
  }

  public void example() {
    try {
      throw new NullPointerException();
    } finally {
      return;
    }
  }
}

If you were to run it, it would end up printing the Ended without error to the console. But we did throw the NullPointerException, didn’t we? Yes, but that would be hidden because of our finally block. We didn’t catch the exception and according to Java language Exception handling specification, the exception would just be discarded. We don’t want something like that to happen, because that would mean that we are hiding issues in the code and its execution.

Never Use Throw Statement in the Finally Block

A very similar situation to the one above is when you try to throw a new Java Exception in the finally block. Again, the code speaks louder than a thousand words, so let’s have a look at the following example:

public class ThrowInFinally {
  public static void main(String[] args) {
    ThrowInFinally app = new ThrowInFinally();
    app.example();
  }

  public void example() {
    try {
      throw new RuntimeException("Exception in try");
    } finally {
      throw new RuntimeException("Exception in finally");
    }
  }
}

If you were to execute the above code the sentence that will be printed in the error console would be the following:

Exception in thread "main" java.lang.RuntimeException: Exception in finally
  at com.sematext.blog.java.ThrowInFinally.example(ThrowInFinally.java:13)
  at com.sematext.blog.java.ThrowInFinally.main(ThrowInFinally.java:6)

Yes, it is true. The Java RuntimeException that was thrown in the try block will be hidden and the one that was thrown in the finally block will take its place. It may not seem big, but have a look at the code like this:

public void example() throws Exception {
  FileReader reader = null;
  try {
    reader = new FileReader("/tmp/somefile");
  } finally {
    reader.close();
  }
}

Now think about the execution of the code and what happens in a case where the file specified by the filePath is not available. First, the FileReader constructor would throw a FileNotFoundException and the execution would jump to the finally block. Once it gets there it would try to call the close method on a reference that is null. That means that the NullPointerException would be thrown here and the whole example method would throw it. So practically, the FileNotFoundException would be hidden and thus the real problem would not be easily visible that well.

Performance Side Effects of Using and Handling Exceptions in Java

We’ve mentioned that using exceptions in Java doesn’t come for free. Throwing an exception requires the JVM to fill up the whole call trace, list each method that comes with it, and pass it further to the code that will finally catch and handle the Java exception. That’s why you shouldn’t use exceptions unless it is really necessary.

Let’s look at a very simple test. We will run two classes–one will do the division by zero and catch the exception that is caused by that operation. The other code will check if the divisor is zero before throwing the exception. The mentioned code is encapsulated in a method.

The code that uses an exception looks as follows:

public int divide(int dividend, int divisor) {
  try {
    return dividend / divisor;
  } catch (Exception ex) {
    // handle exception
  }
  return -1;
}

The code that does a simple check using a conditional looks as follows:

public int divide(int dividend, int divisor) {
  if (divisor != 0) {
    return 10 / divisor;
  }
  return -1;
}

One million executions of the first method take 15 milliseconds, while one million executions of the second method take 5 milliseconds. So you can clearly see that there is a large difference in the execution time when running the code with exceptions and when using a simple conditional to check if the execution should be allowed. Of course, keep in mind that this comparison is very, very simple, and doesn’t reflect real-world scenarios, but it should give you an idea of what to expect when crafting your own code.

The test execution time will differ depending on the machine, but you can run it on your own if you would like by cloning this Github repository.

Troubleshooting Java Exceptions with Sematext

Handling exceptions properly in your Java code is important. Equally important is being able to use them for troubleshooting your Java applications. With Sematext Cloud you can find the most frequent errors and exceptions in your Java application logs, create custom dashboards for your team and set up real-time alerts and anomaly detection to notify you of issues that require your attention. Can you also correlate errors, exceptions, and other application logs with your application performance metrics? You can use Sematext not only for Java monitoring, but also to monitor Elasticsearch, Tomcat, Solr, Kafka, Nginx, your servers, processes, databases, even your packages, and the rest of your infrastructure. With service auto-discovery and monitoring everything is just a click away 🙂

Conclusion

Even though exceptions in Java are not free and have a performance penalty they are invaluable for handling errors in your applications. They help in decoupling the main business code from the error handling code making the whole code cleaner and easier to understand. Using exceptions wisely will make your code look good, be extensible, maintainable, and fun to work with. Use them following exception handling best practices and log everything they tell you into your centralized logging solution so that you can get the most value out of any thrown exception.

If you don’t know where to start looking for the perfect logging solution for you, we wrote in-depth comparisons of various log management tools, log analyzers, and cloud logging services available today to fund the one that fits your use case.

Понравилась статья? Поделить с друзьями:
  • Java error could not find or load main class app
  • Jam 4209 ошибка kyocera
  • Java error could not create the java virtual machine linux
  • Jam 4201 ошибка kyocera 2040
  • Java error code too large