JavaRush /Java Blog /Random EN /Java Exceptions: Catching and Handling

Java Exceptions: Catching and Handling

Published in the Random EN group
Hello! I hate to tell you this, but a huge part of being a programmer is dealing with bugs. And most often - with their own. It so happened that there are no people who do not make mistakes. And there are no such programs. Of course, the main thing when working on a mistake is to understand its cause. And there can be a whole bunch of reasons for such in the program. At one fine moment, the creators of Java faced the question: what to do with these most potential errors in programs? Avoiding them completely is unrealistic. Programmers can write something that is impossible even to imagine :) So, it is necessary to put into the language a mechanism for dealing with errors. In other words, if some error has already occurred in the program, a script is needed for further work. What exactly should the program do when an error occurs? Today we will get acquainted with this mechanism. And it's called "Exceptions" (Exceptions ).

What is an Exception in Java

An exception is some exceptional, unplanned situation that occurred while the program was running. There are many examples of exceptions in Java. For example, you wrote code that reads text from a file and prints the first line to the console.
public class Main {

   public static void main(String[] args) throws IOException {
       BufferedReader reader = new BufferedReader(new FileReader("C:\\Users\\Username\\Desktop\\test.txt"));
       String firstString = reader.readLine();
       System.out.println(firstString);
   }
}
But no such file exists! The result of the program will be an exception - FileNotFoundException. Conclusion:

Exception in thread "main" java.io.FileNotFoundException: C:\Users\Username\Desktop\test.txt (Системе не удается найти указанный путь)
Each exception is represented in Java by a separate class. All exception classes come from a common “ancestor” - the parent class Throwable. The name of the exception class usually briefly reflects the reason for its occurrence:
  • FileNotFoundException(file not found)
  • ArithmeticException(exception when doing math operation)
  • ArrayIndexOutOfBoundsException(the number of the array cell outside its length is indicated). For example, if you try to print to the console the cell array[23] for an array array of length 10.
There are almost 400 such classes in Java! Why so many? Just to make it easier for programmers to work with them. Imagine: you wrote a program, and when it runs, it throws an exception that looks like this:
Exception in thread "main"
Uh-uh-m :/ Nothing is clear. What kind of error, where it came from - is unclear. There is no useful information. But thanks to such a variety of classes, the programmer gets the main thing for himself - the type of error and its probable cause, which is embedded in the class name. After all, it is quite another thing to see in the console:
Exception in thread "main" java.io.FileNotFoundException: C:\Users\Username\Desktop\test.txt (Системе не удается найти указанный путь)
It immediately becomes clear what could be the matter and “in which direction to dig” to solve the problem! Exceptions, like any class instances, are objects.

Catching and Handling Exceptions

To work with exceptions in Java, there are special code blocks: try, catchand finally. Exceptions: interception and processing - 2Code where the programmer expects exceptions to occur is placed in a try. This does not mean that an exception will necessarily occur at this point. This means that it can happen there, and the programmer is aware of this. The type of error you expect to receive is placed in a block catch(“trap”). All the code that needs to be executed if an exception occurs is also placed here. Here is an example:
public static void main(String[] args) throws IOException {
   try {
       BufferedReader reader = new BufferedReader(new FileReader("C:\\Users\\Username\\Desktop\\test.txt"));

       String firstString = reader.readLine();
       System.out.println(firstString);
   } catch (FileNotFoundException e) {

       System.out.println("Error! File not found!");
   }
}
Conclusion:

Ошибка! Файл не найден!
We have placed our code in two blocks. In the first block, we expect a “File not found” error to occur. This is a block try. In the second, we tell the program what to do if an error occurs. Moreover, a specific type of error - FileNotFoundException. If we pass catcha different class of exception to the block brackets, it will not be caught.
public static void main(String[] args) throws IOException {
   try {
       BufferedReader reader = new BufferedReader(new FileReader("C:\\Users\\Username\\Desktop\\test.txt"));
       String firstString = reader.readLine();
       System.out.println(firstString);
   } catch (ArithmeticException e) {

       System.out.println("Error! File not found!");
   }
}
Conclusion:

Exception in thread "main" java.io.FileNotFoundException: C:\Users\Username\Desktop\test.txt (Системе не удается найти указанный путь)
The code in the block catchdid not work, because we “configured” this block to intercept ArithmeticException, and the code in the block trythrew out a different type - FileNotFoundException. For FileNotFoundExceptionwe did not write a script, so the program outputs to the console the information that is displayed by default for FileNotFoundException. Here you need to pay attention to 3 things. First. As soon as an exception occurs in some line of code in the try block, the code after it will no longer be executed. The execution of the program will immediately “jump” into the block catch. For example:
public static void main(String[] args) {
   try {
       System.out.println("Divide a number by zero");
       System.out.println(366/0);//this line of code will throw an exception

       System.out.println("This");
       System.out.println("code");
       System.out.println("Not");
       System.out.println("will");
       System.out.println("done!");

   } catch (ArithmeticException e) {

       System.out.println("The program jumped to the catch block!");
       System.out.println("Error! You can't divide by zero!");
   }
}
Conclusion:

Делим число на ноль 
Программа перепрыгнула в блок catch! 
Ошибка! Нельзя делить на ноль! 
In the block tryin the second line, we tried to divide the number by 0, resulting in an exception ArithmeticException. After that, lines 6-10 of the block trywill no longer be executed. As we said, the program immediately started executing the block catch. Second. There may be several blocks catch. If the code in the block trycan throw not one, but several types of exceptions, you can write your own block for each of them catch.
public static void main(String[] args) throws IOException {
   try {
       BufferedReader reader = new BufferedReader(new FileReader("C:\\Users\\Username\\Desktop\\test.txt"));

       System.out.println(366/0);
       String firstString = reader.readLine();
       System.out.println(firstString);
   } catch (FileNotFoundException e) {

       System.out.println("Error! File not found!");

   } catch (ArithmeticException e) {

       System.out.println("Error! Division by 0!");

   }
}
In this example, we have written two blocks catch. If the block tryhappens FileNotFoundException, the first block will be executed catch. If occurs ArithmeticException, the second one will be executed. catchYou can write at least 50 blocks . But, of course, it's better not to write code that can throw 50 different types of errors :) Third. How do you know what exceptions your code might throw? Well, of course, you can guess about some, but it’s impossible to keep everything in your head. Therefore, the Java compiler is aware of the most common exceptions and knows in what situations they can occur. For example, if you wrote code and the compiler knows that 2 types of exceptions can occur during its work, your code will not compile until you process them. We will see examples of this below. Now for the exception handling. There are 2 ways to process them. We have already met the first one - the method can handle the exception on its own in the block catch(). There is a second option - the method can throw an exception up the call stack. What does it mean? For example, in our class there is a method - all the sameprintFirstString(), which reads the file and prints its first line to the console:
public static void printFirstString(String filePath) {

   BufferedReader reader = new BufferedReader(new FileReader(filePath));
   String firstString = reader.readLine();
   System.out.println(firstString);
}
At the moment our code does not compile because it has unhandled exceptions. On line 1 you specify the path to the file. The compiler knows that such code can easily lead to FileNotFoundException. On line 3, you read text from a file. In this process, it can easily occur IOException- an error in the input-output of data (Input-Output). Now the compiler is telling you, “Dude, I won't approve this code and I won't compile it until you tell me what I should do in case one of these exceptions occurs. And they definitely can happen, based on the code that you wrote!” . There is nowhere to go, you need to process both! We are already familiar with the first processing option: we need to place our code in a block try, and add two blocks catch:
public static void printFirstString(String filePath) {

   try {
       BufferedReader reader = new BufferedReader(new FileReader(filePath));
       String firstString = reader.readLine();
       System.out.println(firstString);
   } catch (FileNotFoundException e) {
       System.out.println("Error, file not found!");
       e.printStackTrace();
   } catch (IOException e) {
       System.out.println("Error while inputting/outputting data from file!");
       e.printStackTrace();
   }
}
But this is not the only option. We can avoid scripting the error inside the method, and just throw the exception up. This is done using the keyword throws, which is written in the method declaration:
public static void printFirstString(String filePath) throws FileNotFoundException, IOException {
   BufferedReader reader = new BufferedReader(new FileReader(filePath));
   String firstString = reader.readLine();
   System.out.println(firstString);
}
After the word, throwswe list, separated by commas, all kinds of exceptions that this method can throw during operation. Why is this being done? Now, if someone in the program wants to call the method printFirstString(), they will have to implement the exception handling themselves. For example, in another part of the program, one of your colleagues wrote a method inside which calls your method printFirstString():
public static void yourColleagueMethod() {

   //...your colleague's method does something

   //...and at one moment calls your printFirstString() method with the file it needs
   printFirstString("C:\\Users\\Eugene\\Desktop\\testFile.txt");
}
Error, the code does not compile! In the method, printFirstString()we did not write an error handling script. Therefore, the task falls on the shoulders of those who will use this method. That is, the method yourColleagueMethod()now faces the same 2 options: it must either handle both exceptions that “arrived” to it, using try-catch, or forward them further.
public static void yourColleagueMethod() throws FileNotFoundException, IOException {
   //...the method does something

   //...and at one moment calls your printFirstString() method with the file it needs
   printFirstString("C:\\Users\\Eugene\\Desktop\\testFile.txt");
}
In the second case, the processing will fall on the shoulders of the next method on the stack - the one that will call yourColleagueMethod(). That is why such a mechanism is called “thrown exception up”, or “passing up”. Exceptions: interception and processing - 3When you throw exceptions up with throws, the code compiles. The compiler at this point seems to say: “OK, okay. Your code contains a bunch of potential exceptions, but I'll compile it anyway. We will return to this conversation!” And when you call a method somewhere in the program that has not handled its exceptions, the compiler fulfills its promise and reminds you of them again. Finally, we'll talk about the block finally(sorry for the pun). This is the last part of the exception handling triumvirate.try-catch-finally. Its peculiarity is that it is executed in any scenario of the program.
public static void main(String[] args) throws IOException {
   try {
       BufferedReader reader = new BufferedReader(new FileReader("C:\\Users\\Username\\Desktop\\test.txt"));

       String firstString = reader.readLine();
       System.out.println(firstString);
   } catch (FileNotFoundException e) {
       System.out.println("Error! File not found!");
       e.printStackTrace();
   } finally {
       System.out.println("And here is the finally block!");
   }
}
In this example, the code inside the block finallyis executed in both cases. If the code in the block trycompletes without throwing an exception, the block will be executed at the end finally. If the code inside trybreaks and the program jumps to block catch, after it runs the code inside catch, block will still be selected finally. Why is it needed? Its main purpose is to execute a required part of the code; the part that must be done regardless of the circumstances. For example, it often releases some resources used by the program. In our code, we open a stream to read information from a file and pass it to a BufferedReader. Ourreaderclose and release resources. This must be done in any case: it does not matter if the program works as it should or throws an exception. It is convenient to do this in a block finally:
public static void main(String[] args) throws IOException {

   BufferedReader reader = null;
   try {
       reader = new BufferedReader(new FileReader("C:\\Users\\Username\\Desktop\\test.txt"));

       String firstString = reader.readLine();
       System.out.println(firstString);
   } catch (FileNotFoundException e) {
       e.printStackTrace();
   } finally {
       System.out.println("And here is the finally block!");
       if (reader != null) {
           reader.close();
       }
   }
}
Now we are sure that we have taken care of the resources used, no matter what happens when the program runs :) That's not all you need to know about exceptions. Error handling is a very important topic in programming, with more than one article devoted to it. In the next lesson, we will learn what types of exceptions are and how to create your own exception :) See you!
Comments
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION