关于Java异常处理

首先

這篇文章是我對即將開始學習Java的人的理解內容記錄。

我們將根據下面的清單,分類列舉有關Java功能與使用方法的內容。此次是關於例外處理的部分。

・变量和类型,类型转换
・变量的作用域
・字符串操作(准备中)
・数组操作(准备中)
・运算符(准备中)
・条件分支(准备中)
・循环处理(准备中)
・异常处理(当前页面)
・关于类(准备中)
・抽象类(准备中)
・接口(准备中)
・封装(准备中)
・关于模块(准备中)

例外处理是指在程序执行过程中出现异常情况时,对这些异常情况进行特殊处理的机制。

作为异常处理的思考方法,是在代码中假设出现了意外的行为,并预先编写相应的处理方式,以应对异常的发生。

例外在本质上是什么,与错误有何区别?

例外(Exception)是指在程序执行过程中出现的异常事件。通常会与错误(Error)混淆,但它们是完全不同的东西,错误是虚拟机无法处理的异常事件,会导致强制终止,因此无法通过例外处理进行应对。
在例外情况下,可以继续进行程序运行,而不需要终止。

关于异常处理机制

我将解释一下try-catch语句。

class Main{
    public static void main(String args[]){
        try{
            int[] array = {0,1,2};

            System.out.println(array[3]);
        }catch(ArrayIndexOutOfBoundsException e){
            System.out.println("例外が出ました");
        }
    }
}

上述的记录采用了try~catch的形式。其机制是,在try和catch内部,当抛出与catch类相同的异常时,将异常消息传递给catch(exception message),然后执行catch内部的代码。希望您能理解这个大致的概念。

编译并执行

例外が出ました

在中文中可以这样表达:显示了。catch语句块中的内容正在运行。

检查异常 (检查例外)

「チェック例外」とは、例外処理を行わないと実行できない処理において使用される例外処理のことです。具体的な例を挙げると、以下のようなものがあります。

以下的代码没有异常处理。

import java.io.BufferedReader;
import java.io.FileReader;
import java.io.IOException;

class Main{
    public static void main(String args[]){
        BufferedReader bufferReader = null;
        FileReader fileReaderr = null;

        // 入力ファイル
        fileReaderr = new FileReader("test.txt");
        bufferReader = new BufferedReader(fileReaderr);

        // 1行づつ読み込んで出力
        String line;
        while ((line = bufferReader.readLine()) != null) {

            System.out.println(line);

            //意図的にストリームを閉じ、IOExceptionを発生させる
            bufferReader.close();
        }
    }
}

尝试编译这个

test.java:11: エラー: 例外FileNotFoundExceptionは報告されません。スローするには、捕捉または宣言する必要があります
        fileReaderr = new FileReader("test.txt");
                      ^
test.java:16: エラー: 例外IOExceptionは報告されません。スローするには、捕捉または宣言する必要があります
        while ((line = bufferReader.readLine()) != null) {
                                            ^
test.java:21: エラー: 例外IOExceptionは報告されません。スローするには、捕捉または宣言する必要があります
            bufferReader.close();
                              ^

可能有点难以理解,但上述描述的意思是,如果没有异常处理,这个操作将不起作用。

如果不在代码中处理IOException,它将不允许编译通过。因此,IOException是受检异常的一种。

所以让我们试试用try~catch来包围这些操作的部分。


import java.io.BufferedReader;
import java.io.FileReader;
import java.io.IOException;

class Main{
    public static void main(String args[]){
        BufferedReader bufferReader = null;
        FileReader fileReaderr = null;

        try {
            // 入力ファイル
            fileReaderr = new FileReader("test.txt");
            bufferReader = new BufferedReader(fileReaderr);

            // 1行づつ読み込んで出力
            String line;
            while ((line = bufferReader.readLine()) != null) {

                System.out.println(line);

                //意図的にストリームを閉じ、IOExceptionを発生させる
                bufferReader.close();
            }
        } catch (IOException e) {
            System.out.println("IOExceptionが発生");
        }
    }
}

当编译并运行这个。

IOExceptionが発生

在处理过程中,通过读取txt文件并在while循环中强制退出,在try块中会发生IOException。这时异常处理起作用,执行catch块中的输出操作。

此外,您还可以通过在方法中定义throws来避免编译错误。

import java.io.BufferedReader;
import java.io.FileReader;
import java.io.IOException;

class Main{
    public static void main(String args[]) throws IOException{
        BufferedReader bufferReader = null;
        FileReader fileReaderr = null;

        // 入力ファイル
        fileReaderr = new FileReader("test.txt");
        bufferReader = new BufferedReader(fileReaderr);

        // 1行づつ読み込んで出力
        String line;
        while ((line = bufferReader.readLine()) != null) {

            System.out.println(line);

            //意図的にストリームを閉じ、IOExceptionを発生させる
            bufferReader.close();
        }
    }
}

这段描述是可以编译的。这段描述也可以处理检查异常。执行的时候就好了。

Exception in thread "main" java.io.FileNotFoundException: test.txt (No such file or directory)
    at java.base/java.io.FileInputStream.open0(Native Method)
    at java.base/java.io.FileInputStream.open(FileInputStream.java:212)
    at java.base/java.io.FileInputStream.<init>(FileInputStream.java:154)
    at java.base/java.io.FileInputStream.<init>(FileInputStream.java:109)
    at java.base/java.io.FileReader.<init>(FileReader.java:60)
    at Main.main(test.java:11)

在执行过程中发生异常,处理将终止。与try~catch不同之处在于没有异常发生时的处理(catch)。

作为处理流程,首先发生的是IOException,此时会直接跳转到catch语句进行处理,因此不会发生其他异常操作。

throws此时只是表示IOException是被允许的状态,随后发生了其他异常并导致程序终止。关于throws的详细信息请参阅另一部分的说明。

顺便提一下,我听说只有Java有一个叫做“检查异常”的概念。所以那些从其他编程语言转来的人可能会因为代码没有问题却遇到错误而感到困惑。

非检查异常

这个在其他语言中也很常见的形式,是指写入异常处理是针对任意异常的。这次我们打算用ArrayIndexOutOfBoundsException(访问不存在的数组元素)来确认。

这里是没有异常处理的说明。

class Main{
    public static void main(String args[]){
        int[] array = {0,1,2};

        System.out.println(array[3]);
    }
}

尝试引用数组array的第三个元素,但只有0到2的元素可用。即使没有编译错误,但执行时也会遇到问题。

Exception in thread "main" java.lang.ArrayIndexOutOfBoundsException: Index 3 out of bounds for length 3
    at Main.main(test.java:6)

出现了 ArrayIndexOutOfBoundsException。被告知在尝试查看数组范围外。

我将加入异常处理并尝试运行。以下是标题中的异常处理机制所描述的代码。

编译通过后,执行时表现相同。

例外が出ました

我能够阅读到 catch 文中的信息。

基本上可以避免处理的错误被称为非检查异常,没有义务进行记录。我觉得更多是出于谨慎的意思。

最后

接下来我会介绍一种在catch后面使用finally的情况。

class Main{
    public static void main(String args[]){
        try{
            int[] array = {0,1,2};

            System.out.println(array[2]);
        }catch(ArrayIndexOutOfBoundsException e){
            System.out.println("例外が出ました");
        }finally{
            System.out.println("どちらでも動く");
        }
    }
}

这是一个没有异常的处理,但是当编译并执行时。

2
どちらでも動く

以类似的方式,最后的处理也在finally块中运行。现在我们尝试一个抛出异常的情况。

class Main{
    public static void main(String args[]){
        try{
            int[] array = {0,1,2};

            System.out.println(array[3]);
        }catch(ArrayIndexOutOfBoundsException e){
            System.out.println("例外が出ました");
        }finally{
            System.out.println("どちらでも動く");
        }
    }
}

当进行编译和执行时

例外が出ました
どちらでも動く

显示如下。
无论是否出现异常,在try语句块中都进行了显示。不管是哪一种情况,想要执行的操作都应在此处进行记录。

抛掷

过去我们一直按照在发生异常时执行这个操作的流程来处理异常,但是通过throw语句我们可以让自己来触发异常处理(术语上称为抛出异常)。

首先,让我们尝试写出throw的代码。

class Main{
    public static void main(String args[]){
        System.out.println("例外スロー");
        try{
            throw new Exception("例外を投げる");
        }catch(Exception e){
            System.out.println("例外処理");
        }
    }
}

一旦执行

例外スロー
例外処理

该处理在try语句中执行。

throw new IOException("例外を投げる");

正在运行。在这个代码段中,触发了一个异常,被捕捉到的catch语句将进行处理并输出两个结果。

投掷

throws是一种在异常发生时在方法调用源中进行异常处理的指定。
因为仅仅这句话可能不容易理解,所以我也会实际写下来。

class Main{
    public static void main(String args[]){
        System.out.println("例外スロー");
        try{
            Main.mikan();
        }catch(Exception e){
            System.out.println("例外処理");
        }
    }

    static void mikan() throws Exception{
        throw new Exception("例外を投げる");
    }
}

编译并运行

例外スロー
例外処理

在代码中显示为:“と表示されます”。程序的流程是在main方法的try语句块内调用了mikan方法。

在调用的mikan方法中定义了throws Exception。简单地说,它的意思是如果在方法内部发生了异常,就将其传递给调用者。

在方法内部引发了一个异常,然后将异常抛给调用者。捕获语句会捕捉到异常并执行异常处理输出,这是整个流程的一系列步骤。

不过,为了方便理解样例,我们在这里使用catch语句来捕获异常处理。但实际上,在实际编写代码时,最好是记录下此方法可能发生的异常。因此,接下来的样例将被写成接收IOException(检查异常)的方式。

对于使用throws的方法来说,需要注意的是如果将其定义为抛出了checked exception,那么在调用该方法时未使用try~catch语句进行包围将会导致错误;而如果该方法未定义throws语句,则无论是否在调用处使用了try~catch语句进行包围,都会导致错误。我也会将其实际写出来。

这里的方法调用被try~catch语句块包围,但方法本身并没有定义throws。

import java.io.BufferedReader;
import java.io.FileReader;
import java.io.IOException;

class Main{
    public static void main(String args[]){
        try{
            Main.mikan();
        }catch(IOException e){
            System.out.println("IOExceptionが出ています");
        }
    }

    static void mikan(){
        BufferedReader bufferReader = null;
        FileReader fileReaderr = null;
        // 入力ファイル
        fileReaderr = new FileReader("test.txt");
        bufferReader = new BufferedReader(fileReaderr);

        // 1行づつ読み込んで出力
        String line;
        while ((line = bufferReader.readLine()) != null) {
            System.out.println(line);

            //意図的にストリームを閉じ、IOExceptionを発生させる
            bufferReader.close();
        }
    }
}

当试图编译这个代码

test.java:9: エラー: 例外IOExceptionは対応するtry文の本体ではスローされません
        }catch(IOException e){
         ^
test.java:18: エラー: 例外FileNotFoundExceptionは報告されません。スローするには、捕捉または宣言する必要があります
        fileReaderr = new FileReader("test.txt");
                      ^
test.java:23: エラー: 例外IOExceptionは報告されません。スローするには、捕捉または宣言する必要があります
        while ((line = bufferReader.readLine()) != null) {
                                            ^
test.java:27: エラー: 例外IOExceptionは報告されません。スローするには、捕捉または宣言する必要があります
            bufferReader.close();
                              ^
エラー4個

会显示错误。下面的三个错误与没有使用try-catch块时的错误内容相似,它们是针对检查异常的,但似乎没有提供针对IOException的处理。这是一种错误的状态。

上面的错误是在try-catch块中表示IOException不会发生的错误。实际上,它发生在方法内部,但由于没有声明它,所以try块无法进行确认。

让我们检查一下没有在方法调用方中进行try~catch的情况,而在方法中定义了throws的情况下的操作。

import java.io.BufferedReader;
import java.io.FileReader;
import java.io.IOException;

class Main{
    public static void main(String args[]){
        Main.mikan();
    }

    static void mikan() throws IOException{
        BufferedReader bufferReader = null;
        FileReader fileReaderr = null;
        // 入力ファイル
        fileReaderr = new FileReader("test.txt");
        bufferReader = new BufferedReader(fileReaderr);

        // 1行づつ読み込んで出力
        String line;
        while ((line = bufferReader.readLine()) != null) {
            System.out.println(line);

            //意図的にストリームを閉じ、IOExceptionを発生させる
            bufferReader.close();
        }
    }
}

这段代码是关于检查异常样例的,必须使用try语句块包围的处理方式被写入了mikan方法中。尝试编译这段代码的话

例外IOExceptionは報告されません。スローするには、捕捉または宣言する必要があります
        Main.mikan();
                  ^

出现错误。这与之前的情况相反,表示调用方发生了IOException,根据throws定义已经知道这种情况是可能发生的,但由于它是checked exception,所以必须用try~catch块来处理。

将上述的示例放入try语句块中。

import java.io.BufferedReader;
import java.io.FileReader;
import java.io.IOException;

class Main{
    public static void main(String args[]){
        try{
            Main.mikan();
        }catch(IOException e){
            System.out.println("IOExceptionが出ています");
        }
    }

    static void mikan() throws IOException{
        BufferedReader bufferReader = null;
        FileReader fileReaderr = null;
        // 入力ファイル
        fileReaderr = new FileReader("test.txt");
        bufferReader = new BufferedReader(fileReaderr);

        // 1行づつ読み込んで出力
        String line;
        while ((line = bufferReader.readLine()) != null) {
            System.out.println(line);

            //意図的にストリームを閉じ、IOExceptionを発生させる
            bufferReader.close();
        }
    }
}

将其编译和执行就可以了

IOExceptionが出ています

在调用部分的catch块中可以进行输出处理。当存在由throws定义的检查异常时,请注意调用者的说明。

结束

在前面的讨论中,我们已经谈到了一些关于例外的内容。如果你正在学习Java,我认为了解并确认检查例外能帮助你处理错误。

广告
将在 10 秒后关闭
bannerAds