JavaRush /Java Blog /Random EN /Exceptions in Java (Java Exception)

Exceptions in Java (Java Exception)

Published in the Random EN group
In everyday life, sometimes situations arise that we did not plan. For example, you get up in the morning for work, looking for a charger for your phone - but it is not there. You go to the bathroom to wash yourself - the water is turned off. Got in the car and it won't start. But a person is able to cope with such unforeseen situations quite easily. And how Java programs cope with them, we will try to figure it out in this article.

What are exceptions (java exceptions)

In the world of programming, the occurrence of errors and unforeseen situations during the execution of a program is called an exception. In the program, exceptions can occur as a result of incorrect user actions, the lack of a necessary resource on disk, or a loss of connection to the server over the network. Program execution exceptions can also be caused by programming errors or incorrect API usage. Unlike our world, the program must clearly know how to act in such a situation. Java provides an exception mechanism for this.

Briefly about try, catch, finally, throws keywords

Exception handling in Java is based on the use of the following keywords in a program:
  • try - defines a block of code in which an exception can occur;
  • catch - defines the block of code in which the exception is handled;
  • finally - defines a block of code that is optional, but if present, is executed anyway, regardless of the results of the try block.
These keywords are used to create special processing constructs in the program code: try{}catch, try{}catch{}finally, try{}finally{}.
  • throw - used to raise an exception;
  • throws - used in method signatures to warn that a method might throw an exception.
An example of using keywords in a Java program:
//method reads a string from the keyboard

public String input() throws MyException {//warn with throws,
// that the method can throw MyException
      BufferedReader reader = new BufferedReader(new InputStreamReader(System.in));
    String s = null;
// in the try block we enclose the code in which an exception can occur, in this
// if the compiler tells us that the readLine() method of the class
// BufferedReader may throw an I/O exception
    try {
        s = reader.readLine();
// in the catch block we enclose the code for handling the IOException exception
    } catch (IOException e) {
        System.out.println(e.getMessage());
// close the read stream in the finally block
    } finally {
// when closing the stream, an exception is also possible, for example, if it was not opened, so we “wrap” the code in a try block
        try {
            reader.close();
// write exception handling when closing the read stream
        } catch (IOException e) {
            System.out.println(e.getMessage());
        }
    }

    if (s.equals("")) {
// we decided that an empty string could disrupt the work of our program in the future, for example, on the result of this method, we need to call the substring(1,2) method, so we are forced to interrupt the program execution with the generation of our exception type MyException using throw
        throw new MyException("String can not be empty!");
    }
    return s;
}

What is the exception mechanism for?

Let's look at an example from the real world. Imagine that there is a section on a highway with an emergency bridge with limited carrying capacity. If a car with a mass exceeding the carrying capacity of the bridge drives over it, it may collapse, and the situation for the driver may become, to put it mildly, exceptional. To prevent this from happening, the road service sets up warning signs on the road in advance. The driver of the car, looking at the warning sign, will compare the mass of his car with that allowed to drive on the bridge. If it exceeds it, he will take the detour. Thanks to the actions of the road service, truck drivers, firstly, were able to change their route in advance, secondly, they were warned of the danger on the main route, and, finally,
Exceptions in Java - 2
The ability to prevent and resolve an exception in a program so that it can continue is one of the reasons for using exceptions in Java. The exception mechanism also allows you to protect the code (programming interface) you write from misuse by the user by validating (checking) the incoming data. Let's be a road service for a second now. First, you must know the places where motorists can expect trouble. Secondly, you need to prepare and install warning signs. And finally, you need to provide detour routes in case of danger on the main route. In Java, the exception mechanism works in a similar way. At the stage of program development, we "protect" dangerous sections of the code in relation to exceptions using the try {} block, provide "alternate" paths using the catch {} block, in the finally{} block, we write code that is executed in the program for any outcome. In cases where we cannot provide a "fallback" or deliberately want to give the user the right to choose one, we should at least warn him of the danger. Why? And just imagine the indignation of the driver who will reach the emergency bridge, which cannot be passed without meeting a single warning sign along the way! In programming, when writing our classes and methods, we cannot always foresee the context of their use by other developers in our programs, so we cannot foresee a 100% correct way to resolve an exception. At the same time, it's good practice to warn users of our code about the possibility of an exception.

Trouble warning

When you don't plan to handle an exception in your method, but want to warn users of the method about possible exceptions, use the throws keyword. This keyword in the method signature means that, under certain conditions, the method may throw an exception. This warning is part of the method interface and entitles the user to their own implementation of the exception handler. After throws, we specify the type of exception to be thrown. These are usually inherited from the Java Exception class . Because Java is an object-oriented language, all exceptions in Java are objects.
Exceptions in Java - 3

Java Exception Hierarchy

When an error occurs during program execution, the JVM runtime creates an object of the desired type from the Java exception hierarchy - a set of possible exceptions inherited from a common "ancestor" - the Throwable class. Exceptions that occur in a program can be divided into two groups:
  1. Situations in which the restoration of further normal operation of the program is impossible
  2. Recovery is possible.
The first group includes situations when there are exceptions inherited from the Error class . These are errors that occur during program execution as a result of a JVM crash, memory overflow, or system crash. Usually they indicate serious problems that cannot be eliminated by software. This type of exception in Java is unchecked at compile time. This group also includes RuntimeException - exceptions, heirs of the Exception classgenerated by the JVM during program execution. They are often caused by programming errors. These exceptions are also unchecked at compile time, so writing code to handle them is not necessary. The second group includes exceptional situations that are foreseen at the stage of writing the program, and for which the processing code must be written. Such exceptions are controlled (checked). A major part of a Java developer's job when dealing with exceptions is handling these situations.

Creating an exception

When a program is executed, an exception is thrown by the JVM or manually, using the throw statement . This creates an exception object in memory and interrupts the execution of the main program code, while the JVM exception handler tries to find a way to handle the exception.

Exception Handling

The creation of code blocks for which we provide exception handling in Java is done in the program using the try{}catch, try{}catch{}finally, try{}finally{} constructs.
Exceptions in Java - 4
When an exception is thrown in a try block, the exception handler is looked up in the catch block that follows it. If there is a handler for this type of exception in catch, control passes to it. If not, then the JVM looks for a handler for this type of exception in the method call chain until a suitable catch is found. After the catch block is executed, control is transferred to the optional finally block . If a suitable catch block is not found, the JVM stops the execution of the program and displays the method call stack - stack trace , after executing the code of the finally block before that, if any. Exception handling example:
public class Print {

     void print(String s) {
        if (s == null) {
            throw new NullPointerException("Exception: s is null!");
        }
        System.out.println("Inside method print: " + s);
    }

    public static void main(String[] args) {
        Print print = new Print();
        List list= Arrays.asList("first step", null, "second step");

        for (String s:list) {
            try {
                print.print(s);
            }
            catch (NullPointerException e) {
                System.out.println(e.getMessage());
                System.out.println("Exception was processed. Program continues");
            }
            finally {
                System.out.println("Inside bloсk finally");
            }
            System.out.println("Go program....");
            System.out.println("-----------------");
        }

    }
    }
The results of the main method :
Inside method print: first step
Inside bloсk finally
Go program....
-----------------
Exception: s is null!
Exception was processed. Program continues
Inside bloсk finally
Go program....
-----------------
Inside method print: second step
Inside bloсk finally
Go program....
-----------------
The block finallyis usually used to close streams opened in the try block or release resources. However, when writing a program, it is not always possible to keep track of the closing of all resources. To make our lives easier, the Java developers have provided us with a construct try-with-resourcesthat automatically closes resources opened in a try block. Our first example can be rewritten as try-with-resources:
public String input() throws MyException {
    String s = null;
    try(BufferedReader reader = new BufferedReader(new InputStreamReader(System.in))){
        s = reader.readLine();
   } catch (IOException e) {
       System.out.println(e.getMessage());
   }
    if (s.equals("")){
        throw new MyException ("String can not be empty!");
    }
    return s;
}
Thanks to the Java 7 features, we can also combine the catching of different types of exceptions in one block, making the code more compact and readable. For example:
public String input() {
    String s = null;
    try (BufferedReader reader = new BufferedReader(new InputStreamReader(System.in))) {
        s = reader.readLine();
        if (s.equals("")) {
            throw new MyException("String can not be empty!");
        }
    } catch (IOException | MyException e) {
        System.out.println(e.getMessage());
    }
    return s;
}

Results

Using exceptions in Java allows you to increase the fault tolerance of the program through the use of "fallback" paths, to separate the logic of the main code from the exception handling code through the use of catch blocks, and also gives us the opportunity to shift exception handling to the user of our code using throws.
What else to read:

Top 10 Java Exception Questions

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