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. For example, you get up for work in the morning, look for a charger for your phone, but there isn’t one. You go to the bathroom to wash your face - the water has been turned off. I got into the car and it wouldn’t start. But a person is able to cope with such unforeseen situations quite easily. We’ll try to figure out how Java programs deal with them in this article.

What are exceptions java

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

Briefly about the keywords try, catch, finally, throws

Exception handling in Java is based on the use of the following keywords in the 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 may 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;
}

Why do we need an exception mechanism?

Let's look at a real world example. Imagine that there is a section on a highway with an emergency bridge with limited load capacity. If a vehicle with a mass exceeding the bridge's carrying capacity drives across 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 installs warning signs on the road in advance. The driver of the car, looking at the warning sign, will compare the weight of his car with that allowed for driving on the bridge. If it exceeds it, he will take a detour. Thanks to the actions of the road service, truck drivers, firstly, were given the opportunity to change their route in advance, secondly, they were warned about the danger on the main route, and, finally, they were warned about the impossibility of using the bridge under certain conditions.
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 you write (programming interface) from misuse by the user by validating (checking) incoming data. Now let's be the traffic police for a second. First, you should know the places where motorists can get into trouble. Secondly, you need to prepare and install warning signs. 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 program development stage, we “protect” dangerous sections of code from exceptions using the try{} block, provide “backup” paths using the catch{} block, and in the finally{} block we write code that is executed in the program for any outcome. In cases where we cannot provide an “emergency route” or deliberately want to leave the choice to the user, we must at least warn him of the danger. Why? Just imagine the indignation of a driver who will reach an emergency bridge that cannot be driven across without encountering 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 their programs, so we cannot foresee the 100% correct path to resolve the exception situation. At the same time, it is good practice to warn users of our code about the possibility of an exception. Java's exception mechanism allows us to do this by using throws—essentially declaring the general behavior of our method to throw an exception, thereby leaving it up to the user of the method to write code to handle the exception in Java.

Warning of "trouble"

When you don't plan to handle an exception in your method, but want to warn users of the method about possible exception situations, use the throws keyword. This keyword in a method signature means that under certain conditions the method may throw an exception. This warning is part of the method interface and gives the user the right to customize the implementation of the exception handler. After throws we indicate the type of exception being thrown. These are usually descendants of the Java Exception class . Since 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 required type from the Java exception hierarchy - the set of possible exceptions inherited from a common “ancestor” - the Throwable class. Exceptional situations that occur in a program can be divided into two groups:
  1. Situations in which restoration of further normal operation of the program is impossible
  2. Recovery is possible.
The first group includes situations when exceptions inherited from the Error class occur . These are errors that occur during program execution as a result of a JVM failure, memory overflow, or system crash. They usually indicate serious problems that cannot be fixed using software. This type of exception in Java is classified as unchecked at the compilation stage. This group also includes RuntimeException - exceptions, inheritors of the Exception class , generated 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 processing code must be written. Such exceptions are checked. The bulk of a Java developer's job when dealing with exceptions is handling such situations.

Creating an Exception

During program execution, an exception is thrown by the JVM or manually using the throw statement . This creates an exception object in memory and interrupts 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 raised in a try block, the exception handler is looked for in the following catch block. If the catch contains a handler for this type of exception, control passes to it. If not, the JVM looks for a handler for that type of exception in the chain of method calls until a suitable catch is found. After the catch block is executed, control is passed to an optional finally block . If a suitable catch block is not found, the JVM stops program execution and displays a stack of method calls - stack trace , having previously executed the finally block code, if present. 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 to free resources. However, when writing a program, it is not always possible to keep track of the closure of all resources. To make our lives easier, Java developers offered us a construct try-with-resourcesthat automatically closes resources opened in a try block. Our first example can be rewritten like this 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 capabilities of Java, starting with version 7, we can also combine the catching of different types of exceptions in a single 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

The use of exceptions in Java allows us to increase the fault tolerance of the program through the use of “backup” 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 delegate exception handling to the user of our code using throws.
Comments
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION