4 min read

Java Interview Questions (Series) - Exceptions & Errors

Java Interview Questions (Series) - Exceptions & Errors

Anything that can go wrong will go wrong!

Brief

🐞 Errors are a given when it comes to software development.

To prevent them is one thing, but we all know that we can't keep them all from happening.

This is why error handling is a concept that every good Java developer should understand and know how to use.

💯 This is also the reason why you'll find it in every Java interview.

In this post we'll go through:

🔸  What is an Error ?

🔸  What is an Exception?

🔸  How are they different from another?

🔸  When can you expect each to occur?

🔸  Which to try and get around and which to leave alone?

Let's get into it! 🚀

Implementation

Throwable hierarchy

As you can see, Exception and Error are two different classes that extend Throwable.

In turn, Throwable extends Object ( the mother of all classes in Java ).

🔵  Exception

Exceptions are issues that can occur in your application at runtime or compile time.

There are lots, and I mean lots, of already defined Java exceptions. But you can also define your own custom ones. (It's actually a good practice to do so.)

You can find exceptions being split in a lot of different categories, but the ones that most interviewers expect you to say are:

🔸  checked exceptions

🔸  unchecked exceptions


🔷  Checked exceptions

These ones are checked, as per their name, at compile time. Meaning that if a line in a method throws one of these exceptions, that method should either:

🔸  Handle it.

🔸  Declare in its signature that this exception is expected to occur and the next caller of the method needs to handle it.

Examples of checked exceptions:

🔸  IOException - Signals that an Input/Output operation has failed.

🔸  SQLException - Provides information on DB actions that failed.

🔸  etc.

♻️  Example

Say we want to read some data from a file.

We first need to instantiate a FileInputStream object to which we pass the name of the file. Because that file may disappear in the meantime, or we may provide the wrong name, this operation might fail.

This is why the actual constructor of FileInputStream throws a checked exception 😮 FileNotFoundException.

   public FileInputStream(String name) throws FileNotFoundException
FIleInputStream.java

In order to use it, as we just learned, we need to either handle that exception or pass it to the next caller of our method.

    public void readBytes() throws FileNotFoundException { // add it in the signature
            FileInputStream fis =new FileInputStream("test.txt");
            ...
    }

OR

    public void readBytesHandleException() {
            try {
                FileInputStream fin=new FileInputStream("D:\\testout.txt");
            }
            catch (FileNotFoundException exception) {   // handle the exception
                System.out.print("FileNotFoundException");
            }
    }


🔷 Unchecked Exception

As you probably guessed, this kind of exceptions are not checked at compile-time, but they can appear at run-time.

Because of that, us as developers we need to think in advance of what could go wrong.

Examples of unchecked exceptions:

🔸  NullPointerException - Indicates that you do a called a method of a null object.

🔸  ArithmeticException - Thrown when an exceptional arithmetic condition has occurred.

🔸  etc.

♻️  Example

A simple example for this, is to create a method that divides two numbers returning the result.

    public double divide(double a, double b) {
            return a/b;
    }

🐞 All fun and games until the client decides to pass 0 as the second argument.

🔥  And if you remember from your math classes, division by zero makes the universe implode. Since we don't want this to happen yet, we need a way to handle this case.

   public double divide(double a, double b) {
        double result = 0;
        try {
            result = a/b;
        }
        catch (ArithmeticException exception) {  // ArithmeticException is the exception thrown by the JVM when dividing by zero
            System.out.print("ArithmeticException");
            return 0;
        }
        return result;
    }

Or, even better:

   public double divide(double a, double b) {
        if (b == 0) {
        System.out.print("Division by zero!");
            // throw your custom exception !
        }
        
         return a/b;
    }

💯  The main advantage of exception handling is that we can keep the application flow going and gracefully notifying the client that something went wrong.


🔵  Error

The Error class is also a child class of Throwable.  

It is used to signal that a problem occurred and it causes the application to terminate.  

Examples of Errors:

🔸  OutOfMemoryError - Thrown when the Java Virtual Machine cannot allocate an object because it is out of memory.

🔸  NoClassDefFoundError - The searched-for class definition existed when the currently executing class was compiled, but the definition can no longer be found.

🔸  AssertionError - Thrown to indicate that an assertion has failed.

♻️ Example

Generating a simple StackOverflowError:

  public static void stackOverflowError() {
        while (true) {
            stackOverflowError();
        }
    }

Output:

Since the StackOverflowError is derived from Throwable, you can still handle it within a try-catch block:

     try {
            stackOverflowError();
     } catch (StackOverflowError error) {
            System.out.println("Error caught!");
     }

Keep in mind!

The JVM throws errors to indicate severe problems from which it can't recover, such as lack of memory and stack overflows, among others.

This is why, in 99% of cases you are better off not handling Errors in a try-catch block and really look into the cause of it.


💡
Don't miss out on more posts like this! Susbcribe to our free newsletter!
💡
I am currently working on a Java Interview e-book designed to successfully get you through any Java technical interview you may take.
Stay tuned! 🚀