- The Java Workshop
- David Cuartielles Andreas G?ransson Eric Foster Johnson
- 1909字
- 2021-06-11 13:05:26
Catching Exceptions
As mentioned earlier, there are two ways to handle exceptions: catching and throwing. In this section, we will deal with the first of these methods. Catching an exception requires encapsulating the code that might generate an unwanted result into a specific statement, as shown in the following code snippet:
try {
// code that could generate an exception of the type ExceptionM
} catch (ExceptionM e) {
// code to be executed in case of exception happening
}
We can put this code to test with any of the previous examples. Let's demonstrate how we could stop the exception we found in the first example of the chapter, where we tried to check the length of a string that was initialized to null:
public class Example07 {
public static void main(String[] args) {
// declare a string with nothing inside
String text = null;
// you will see this at the console
System.out.println("Go Java Go!");
try {
// null'ed strings should crash your program
System.out.println(text.length());
} catch (NullPointerException ex) {
System.out.println("Exception: cannot get the text's length");
}
// you will now see this print
System.out.println("done");
}
}
As you can see, we have wrapped the potentially broken code inside a try-catch statement. The result of this code listing is very different from the result that we saw previously:
Go Java Go!
Exception: cannot get the text's length
done
Process finished with exit code 0
Mainly, we find that the program is not interrupted until the end. The try section of the program detects the arrival of the exception, and the catch part will execute a specific code if the exception is of the NullPointerException type.
Several catch statements can be placed in sequence after the call to try as a way to detect different types of exceptions. To try this out, let's go back to the example where we were trying to open a non-existing file and try to catch the reason for readAllLines() stopping the program:
Example08.java
5 public class Example08 {
6 public static void main(String[] args) {
7 // declare a list that will contain all of the files
8 // inside of the readme.txt file
9 List<String> lines = Collections.emptyList();
10
11 try {
12 // provoke an exception
13 lines = Files.readAllLines(Paths.get("readme.txt"));
14 } catch (NoSuchFileException fe) {
15 System.out.println("Exception: File Not Found");
16 } catch (IOException ioe) {
17 System.out.println("Exception: IOException");
18 }
As we saw earlier in the chapter, we have made a program that tries to open a non-existing file. The exception that we got then was IOException. In reality, that exception is triggered by NoSuchFileException, which is escalated and triggers IOException. Therefore, we get that exception on the IDE. When implementing the multiple try-catch statements, as shown in the previous example, we get the following outcome:
Exception: File Not Found
Process finished with exit code 0
This means that the program detects the NoSuchFileException and, therefore, prints the message included in the corresponding catch statement. However, if you want to see the full sequence of exceptions triggered by the non-existing readme.txt file, you can use a method called printStackTrace(). This will send to the output everything that was on the way to the proper execution of the program. To see this, simply add the following highlighted changes to the previous example:
try {
// provoke an exception
lines = Files.readAllLines(Paths.get("readme.txt"));
} catch (NoSuchFileException fe) {
System.out.println("Exception: File Not Found");
fe.printStackTrace();
} catch (IOException ioe) {
System.out.println("Exception: IOException");
}
The output of the program will now include a full printout of the different exceptions triggered during program execution. You will see the output of the stack is inverted: first, you will see the reason why the program stopped (NoSuchFileException), and it will end with the method that starts the process that provokes the exception (readAllLines). This is due to the way exceptions are built. As we will discuss later, there are many different types of exceptions. Each one of these types is defined as a class of exceptions, which may be extended by several other subclasses of exceptions. If an extension of a certain type occurs, then the class that it is extending will also appear when printing out the stack. In our case, NoSuchFileException is a subclass of IOException.
Note
Depending on your operating system, the different nested exceptions for dealing with opening a file will probably be called differently.
We have been catching two different exceptions – one nested inside the other. It should also be possible to handle exceptions coming from different classes, such as IOException and NullPointerException. The following example demonstrates how to do this. If you are dealing with exceptions that are not a subclass of one another, it is possible to catch both exceptions using a logical OR operator:
import java.io.*;?
import java.nio.file.*;
import java.util.*;
public class Example09 {
public static void main(String[] args) {
List<String> lines = Collections.emptyList();
try {
lines = Files.readAllLines(Paths.get("readme.txt"));
} catch (NullPointerException|IOException ex) {
System.out.println("Exception: File Not Found or NullPointer");
ex.printStackTrace();
}
// you will never see this print
Iterator<String> iterator = lines.iterator();
while (iterator.hasNext())
System.out.println(iterator.next());
}
}
As you can see, it is possible to handle both exceptions in a single catch statement. However, if you want to handle the exceptions differently, you will have to work with the object containing the information about the exception, which, in this case, is ex. The keyword you need to distinguish the between the exceptions that you may be handling simultaneously is instanceof, as shown in the following modification of the previous example:
try {
// provoke an exception
lines = Files.readAllLines(Paths.get("readme.txt"));
} catch (NullPointerException|IOException ex) {
if (ex instanceof IOException) {
System.out.println("Exception: File Not Found");
}
if (ex instanceof NullPointerException) {
System.out.println("Exception: NullPointer");
}
}
How Many Different Exceptions Can You Catch in a Single Try?
The fact is that you can daisy chain as many catch statements as you need to. If you use the second method that we discussed in this chapter (that is, using the OR statement), then you should remember that it is not possible to have a subclass together with its parent class. For example, it is not possible to have NoSuchFileException and IOException together in the same statement – they should be placed in two different catch statements.
Exercise 1: Logging Exceptions
There are two main actions that you can perform when catching exceptions aside from any type of creative coding you may want to do to respond to the situation; these actions are logging or throwing. In this exercise, you will learn how to log the exception. In a later exercise, you will learn how to throw it instead. As we will reiterate in the Best Practices for Handling Exceptions section of this chapter, you should never do both at once:
- Create a new Java project in IntelliJ using the template for CLI. Name it LoggingExceptions. You will be creating classes inside it that you can then use later in other programs.
- In the code, you need to import the logging API by issuing the following command:
import java.util.logging.*;
- Declare an object that you will be using to log the data into. This object will be printed to the terminal upon program termination; therefore, you don't need to worry about where it will end up at this point:
Logger logger = Logger.getAnonymousLogger();
- Provoke an exception, as follows:
String s = null;
try {
System.out.println(s.length());
} catch (NullPointerException ne) {
// do something here
}
- At the time of catching the exception, send the data to the logger object using the log() method:
logger.log(Level.SEVERE, "Exception happened", ne);
- Your full program should read as follows:
import java.util.logging.*;
public class LoggingExceptions {
public static void main(String[] args) {
Logger logger = Logger.getAnonymousLogger();
String s = null;
try {
System.out.println(s.length());
} catch (NullPointerException ne) {
logger.log(Level.SEVERE, "Exception happened", ne);
}
}
}
- When you execute the code, the output should be as follows:
may 09, 2019 7:42:05 AM LoggingExceptions main
SEVERE: Exception happened
java.lang.NullPointerException
at LoggingExceptions.main(LoggingExceptions .java:10)
Process finished with exit code 0
- As you can see, the exception is logged at the determined SEVERE level, but the code ends without an error code because we were able to handle the exception. The log is useful because it tells us where the exception happened in the code and, additionally, helps us to find the place of where we can dig deeper into the code and fix any potential issues.
- DB2 V9權威指南
- Boost程序庫完全開發指南:深入C++”準”標準庫(第5版)
- Python機器學習:數據分析與評分卡建模(微課版)
- Visual C++串口通信開發入門與編程實踐
- Learning ArcGIS Pro 2
- C#程序設計(慕課版)
- Building Mapping Applications with QGIS
- Learning OpenStack Networking(Neutron)
- C#實踐教程(第2版)
- Tableau 10 Bootcamp
- OpenCV 4計算機視覺項目實戰(原書第2版)
- Internet of Things with ESP8266
- Microsoft Dynamics GP 2013 Cookbook
- Python Django Web從入門到項目實戰(視頻版)
- JavaScript編程精解(原書第3版)