CodeGym /Java Course /Module 1. Java Syntax /Types of exceptions

Types of exceptions

Module 1. Java Syntax
Level 21 , Lesson 3
Available

1. Types of exceptions

All exceptions are divided into 4 types, which are actually classes that inherit one another.

Throwable class

The base class for all exceptions is the Throwable class. The Throwable class contains the code that writes the current call stack (stack trace of the current method) to an array. We'll learn what a stack trace is a little later.

The throw operator can only accept an object that derives from the Throwable class. And although you can theoretically write code like throw new Throwable();, nobody usually does this. The main purpose of the Throwable class is to have a single parent class for all exceptions.

Error class

The next exception class is the Error class, which directly inherits the Throwable class. The Java machine creates objects of the Error class (and its descendants) when serious problems have occurred. For example, a hardware malfunction, insufficient memory, etc.

Usually, as a programmer, there is nothing you can do in a situation where such an error (the kind for which an Error should be thrown) has occurred in the program: these errors are too serious. All you can do is notify the user that the program is crashing and/or write all known information about the error to the program log.

Exception class

The Exception and RuntimeException classes are for common errors that happen in the operation of lots of methods. The goal of each thrown exception is to be caught by a catch block that knows how to properly handle it.

When a method cannot complete its work for some reason, it should immediately notify the calling method by throwing an exception of the appropriate type.

In other words, if a variable is equal to null, the method will throw a NullPointerException. If the incorrect arguments were passed to the method, it will throw an InvalidArgumentException. If the method accidentally divides by zero, it will throw an ArithmeticException.

RuntimeException class

RuntimeExceptions are a subset of Exceptions. We could even say that RuntimeException is a lightweight version of ordinary exceptions (Exception) — fewer requirements and restrictions are imposed on such exceptions

You'll learn the difference between Exception and RuntimeException later.


2. Throws: checked exceptions

All Java exceptions fall into 2 categories: checked and unchecked.

All exceptions that inherit the RuntimeException or Error are considered unchecked exceptions. All others are checked exceptions.

Important!

Twenty years after checked exceptions were introduced, almost every Java programmer thinks of this as a bug. In popular modern frameworks, 95% of all exceptions are unchecked. The C# language, which almost copied Java exactly, did not add checked exceptions.

What is the main difference between checked and unchecked exceptions?

There are additional requirements imposed on checked exceptions. Roughly speaking, they are these:

Requirement 1

If a method throws a checked exception, it must indicate the type of exception in its signature. That way, every method that calls it is aware that this "meaningful exception" might occur in it.

Indicate checked exceptions after the method parameters after the throws keyword (don't use the throw keyword by mistake). It looks something like this:

type method (parameters) throws exception

Example:

checked exception unchecked exception
public void calculate(int n) throws Exception
{
   if (n == 0)
      throw new Exception("n is null!");
}
public void calculate(n)
{
   if (n == 0)
      throw new RuntimeException("n is null!");
}

In the example on the right, our code throws an unchecked exception — no additional action is required. In the example on the left, the method throws a checked exception, so the throws keyword is added to the method signature along with the type of the exception.

If a method expects to throw multiple checked exceptions, all of them must be specified after the throws keyword, separated by commas. The order is not important. Example:

public void calculate(int n) throws Exception, IOException
{
   if (n == 0)
      throw new Exception("n is null!");
   if (n == 1)
      throw new IOException("n is 1");
}

Requirement 2

If you call a method that has checked exceptions in its signature, you cannot ignore the fact that it throws them.

You must either catch all such exceptions by adding catch blocks for each one, or by adding them to a throws clause for your method.

It's as if we're saying, "These exceptions are so important that we must catch them. And if we do not know how to handle them, then anyone who might call our method must be notified that such exceptions can occur in it.

Example:

Imagine that we are writing a method to create a world populated by humans. The initial number of people is passed as an argument. So we need to add exceptions if there are too few people.

Creating Earth Note
public void createWorld(int n) throws EmptyWorldException, LonelyWorldException
{
   if (n == 0)
      throw new EmptyWorldException("There are no people!");
   if (n == 1)
      throw new LonelyWorldException ("There aren't enough people!");
   System.out.println("A wonderful world was created. Population: " + n);
}
The method potentially throws two checked exceptions:

  • EmptyWorldException
  • LonelyWorldException

This method call can be handled in 3 ways:

1. Don't catch any exceptions

This is most often done when the method does not know how to properly handle the situation.

Code Note
public void createPopulatedWorld(int population)
throws EmptyWorldException, LonelyWorldException
{
   createWorld(population);
}
The calling method does not catch the exceptions and must inform others about them: it adds them to its own throws clause

2. Catch some of the exceptions

We handle the errors we can handle. But the ones we don't understand, we throw them up to the calling method. To do this, we need to add their name to the throws clause:

Code Note
public void createNonEmptyWorld(int population)
throws EmptyWorldException
{
   try
   {
      createWorld(population);
   }
   catch (LonelyWorldException e)
   {
      e.printStackTrace();
   }
}
The caller catches only one checked exception — LonelyWorldException. The other exception must be added to its signature, indicating it after the throws keyword

3. Catch all exceptions

If the method does not throw exceptions to the calling method, then the calling method is always confident that everything worked well. And it will be unable to take any action to fix an exceptional situations.

Code Note
public void createAnyWorld(int population)
{
   try
   {
      createWorld(population);
   }
   catch (LonelyWorldException e)
   {
      e.printStackTrace();
   }
   catch (EmptyWorldException e)
   {
      e.printStackTrace();
   }
}
All exceptions are caught in this method. The caller will be confident that everything went well.


3. Catching multiple exceptions

Programmers really hate to duplicate code. They even came up with a corresponding development principle — DRY: Don't Repeat Yourself. But when handling exceptions, there are frequent occasions when a try block is followed by several catch blocks with the same code.

Or there could be 3 catch blocks with the same code and another 2 catch blocks with other identical code. This is a standard situation when your project handles exceptions responsibly.

Starting with version 7, in the Java language added the ability to specify multiple types of exceptions in a single catch block. It looks roughly like this:

try
{
   // Code where an exception might occur
}
catch (ExceptionType1 | ExceptionType2 | ExceptionType3 name)
{
   // Exception handling code
}

You can have as many catch blocks as you want. However, a single catch block cannot specify exceptions that inherit one another. In other words, you cannot write catch (Exception | RuntimeException e), because the RuntimeException class inherits Exception.



Comments
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION