Heim  >  Artikel  >  Java  >  Ausnahmen in Java müssen Sie kennen

Ausnahmen in Java müssen Sie kennen

尚
nach vorne
2019-11-29 17:21:171688Durchsuche

Ausnahmen in Java müssen Sie kennen

1. Die Definition einer Ausnahme (empfohlen: Java-Video-Tutorial)

ist in „Java Programming Thoughts“ wie folgt definiert: Ausnahme: ein Problem, das die weitere Ausführung der aktuellen Methode oder des aktuellen Bereichs verhindert. Obwohl es in Java einen Ausnahmebehandlungsmechanismus gibt, muss klar sein, dass Ausnahmen niemals mit einer „normalen“ Einstellung betrachtet werden sollten. Absolut gesehen ist eine Ausnahme in gewissem Sinne ein Fehler, ein Problem, und sie kann dazu führen, dass das Programm fehlschlägt. Der Grund, warum Java einen Ausnahmebehandlungsmechanismus vorschlägt, besteht darin, Entwicklern mitzuteilen, dass in Ihrem Programm etwas nicht stimmt. Bitte achten Sie darauf.

Ich erinnere mich, als ich zum ersten Mal Java lernte, war ich immer verwirrt über Ausnahmen. Ich weiß nicht, was diese Ausnahme bedeutet und warum es diesen Mechanismus gibt. Aber mit der Anhäufung von Wissen begann ich allmählich, ein wenig über die Anomalien nachzudenken. Geben Sie ein Beispiel, um die Verwendung von Ausnahmen zu veranschaulichen.

public class Calculator {
    public int devide(int num1, int num2) {
        //判断除数是否为0
        if(num2 == 0) {
            throw new IllegalArgumentException("除数不能为零");
        }
         
        return num1/num2;
    }
}

Schauen Sie sich die Divisionsoperationsmethode in dieser Klasse an. Wenn Sie ein Anfänger sind, können Sie das Berechnungsergebnis direkt zurückgeben, ohne zu überlegen, ob die Parameter korrekt oder zulässig sind (natürlich können Sie es verzeihen). ist so) kam vorbei). Wir sollten jedoch so gründlich wie möglich vorgehen, um die „Anzeichen“ zu beseitigen, die dazu führen können, dass das Programm in der Basisstation fehlschlägt. Daher ist es notwendig, die Rechtmäßigkeit der Parameter zu überprüfen.

Die von der Parameterprüfung ausgelöste Ausnahme wegen unzulässiger Parameter ist eine Anomalie dieser Methode. Unter normalen Umständen verwenden wir den Rechner korrekt, es ist jedoch nicht ausgeschlossen, dass wir versehentlich den Divisor auf 0 setzen. Wenn Sie diese Situation noch nicht in Betracht gezogen haben und es vorkommt, dass der Benutzer über schlechte mathematische Kenntnisse verfügt, dann sind Sie am Arsch. Aber wenn Sie diese Situation schon einmal in Betracht gezogen haben, ist es klar, dass der Fehler in Ihrer Kontrolle liegt.

2. Abnormale Alphabetisierungsaktion

Als ich heute mit jemandem chattete, sah ich einen Witz: Die wahrste Abhängigkeit der Welt besteht darin, dass man es versucht und ich es erwischt. Egal wie wütend du bist, ich werde es still ertragen und ruhig damit umgehen. Das Gefühl der meisten Anfänger in Bezug auf Java-Ausnahmen ist: versuchen ... fangen ... Ja, das ist das am häufigsten verwendete und praktischste. Mein Gefühl ist: Java-Ausnahmen kommen von „try...catch…“.

Machen wir uns zunächst mit dem Ausnahmesystem von Java vertraut:

Die Throwable-Klasse ist die Superklasse aller Fehler oder Ausnahmen in der Java-Sprache (das ist alles, was ausgelöst werden kann). Es gibt zwei Unterklassen: Fehler und Ausnahme.

Fehler: Wird verwendet, um auf schwerwiegende Probleme hinzuweisen, die vernünftige Anwendungen nicht beheben sollten. Diese Situation ist ein großes Problem, zu groß für Sie, also lassen Sie es einfach los und machen Sie sich darüber keine Sorgen. Beispiel: VirtualMachineError: Dieser Fehler wird ausgelöst, wenn die Java Virtual Machine abstürzt oder nicht mehr über die Ressourcen verfügt, die sie für den weiteren Betrieb benötigt. Okay, selbst wenn diese Ausnahme existiert, wann und wie sollte sie behandelt werden? ? Überlassen Sie es der JVM, es gibt nichts Professionelleres als es.

Ausnahme: Sie weist auf eine Bedingung hin, die eine vernünftige Anwendung abfangen möchte. Die Ausnahme ist in zwei Kategorien unterteilt: eine ist CheckedException und die andere ist UncheckedException.

Der Hauptunterschied zwischen diesen beiden Ausnahmen besteht darin, dass CheckedException explizit mit try...catch... erfasst werden muss, während UncheckedException nicht erfasst werden muss. Normalerweise wird UncheckedException auch RuntimeException genannt.

Zu unseren allgemeinen RuntimeExcepitons gehören IllegalArgumentException, IllegalStateException, NullPointerException, IndexOutOfBoundsException und so weiter. Es gibt zu viele CheckedExceptions, um sie alle aufzuzählen. Während des Schreibens des Programms sind die Ausnahmen, die wir mit try...catch... abfangen, allesamt CheckedExceptions. IOException und seine Unterklassen im io-Paket sind CheckedException.

Drei. Die Verwendung von Ausnahmen

Bei diesem Teil der Verwendung von Ausnahmen handelt es sich hauptsächlich um Demonstrationscode. Dies sind alles Dinge, auf die wir beim Schreiben von Code stoßen (natürlich nur ein kleiner Teil). Möchten Sie andere inspirieren?

Beispiel 1. Dieses Beispiel demonstriert hauptsächlich den Ausführungsfluss des Codes nach dem Auftreten einer Ausnahme durch den Vergleich zweier Methoden.

public static void testException1() {
        int[] ints = new int[] { 1, 2, 3, 4 };
        System.out.println("异常出现前");
        try {
            System.out.println(ints[4]);
            System.out.println("我还有幸执行到吗");// 发生异常以后,后面的代码不能被执行
        } catch (IndexOutOfBoundsException e) {
            System.out.println("数组越界错误");
        }
        System.out.println("异常出现后");
    }
    /*output:
    异常出现前
    数组越界错误
    4
    异常出现后
    */
rrree

Weisen Sie zunächst auf die Mängel im Beispiel hin. IndexOutofBoundsException ist eine ungeprüfte Ausnahme, daher besteht keine Notwendigkeit, ... zu fangen ..., um die Erfassung anzuzeigen, aber mein Zweck ist die Verwendung unterschiedliche Verarbeitung für die gleiche Ausnahme und sehen Sie, welchen Unterschied es erzeugt (hier kann ich es nur für eine Weile verwenden). Wenn eine Ausnahme auftritt, springt die erste Methode einfach aus dem Try-Block, der Code dahinter wird jedoch weiterhin ausgeführt.

Aber die zweite Methode ist anders und springt einfach aus der Methode heraus, die schwieriger ist. Aus der ersten Methode geht hervor, dass try...catch... eine „Transaktions“-Garantie ist. Ihr Zweck besteht darin, sicherzustellen, dass die Ausführung des Programms unter ungewöhnlichen Umständen abgeschlossen wird, und sie benachrichtigt den Programmierer außerdem über detaillierte Informationen der Fehler (die Details hängen manchmal vom Design des Programmierers ab).

Beispiel 2. Ausnahme erneut auslösen

public class Rethrow {
    public static void readFile(String file) throws FileNotFoundException {
        try {
            BufferedInputStream in = new BufferedInputStream(new FileInputStream(file));
        } catch (FileNotFoundException e) {
            e.printStackTrace();
            System.err.println("不知道如何处理该异常或者根本不想处理它,但是不做处理又不合适,这是重新抛出异常交给上一级处理");
            //重新抛出异常
            throw e;
        }
    }
     
    public static void printFile(String file) {
        try {
            readFile(file);
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        }
    }
     
    public static void main(String[] args) {
        printFile("D:/file");
    }
}

异常的本意是好的,让我们试图修复程序,但是现实中我们修复的几率很小,我们很多时候就是用它来记录出错的信息。如果你厌倦了不停的处理异常,重新抛出异常对你来说可能是一个很好的解脱。原封不动的把这个异常抛给上一级,抛给调用这个方法的人,让他来费脑筋吧。这样看来,java异常(当然指的是受检异常)又给我们平添很多麻烦,尽管它的出发点是好的。

例3. 异常链的使用及异常丢失

定义三个异常类:ExceptionA,ExceptionB,ExceptionC

public class ExceptionA extends Exception {
    public ExceptionA(String str) {
        super();
    }
}
 
public class ExceptionB extends ExceptionA {
 
    public ExceptionB(String str) {
        super(str);
    }
}
 
public class ExceptionC extends ExceptionA {
    public ExceptionC(String str) {
        super(str);
    }
}

异常丢失的情况:

public class NeverCaught {
    static void f() throws ExceptionB{
        throw new ExceptionB("exception b");
    }
 
    static void g() throws ExceptionC {
        try {
            f();
        } catch (ExceptionB e) {
            ExceptionC c = new ExceptionC("exception a");
            throw c;
        }
    }
 
    public static void main(String[] args) {
            try {
                g();
            } catch (ExceptionC e) {
                e.printStackTrace();
            }
    }
 
}
/*
exception.ExceptionC
at exception.NeverCaught.g(NeverCaught.java:12)
at exception.NeverCaught.main(NeverCaught.java:19)
*/

为什么只是打印出来了ExceptionC而没有打印出ExceptionB呢?这个还是自己分析一下吧!

上面的情况相当于少了一种异常,这在我们排错的过程中非常的不利。那我们遇到上面的情况应该怎么办呢?这就是异常链的用武之地:保存异常信息,在抛出另外一个异常的同时不丢失原来的异常。

public class NeverCaught {
    static void f() throws ExceptionB{
        throw new ExceptionB("exception b");
    }
 
    static void g() throws ExceptionC {
        try {
            f();
        } catch (ExceptionB e) {
            ExceptionC c = new ExceptionC("exception a");
            //异常连
            c.initCause(e);
            throw c;
        }
    }
 
    public static void main(String[] args) {
            try {
                g();
            } catch (ExceptionC e) {
                e.printStackTrace();
            }
    }
 
}
/*
exception.ExceptionC
at exception.NeverCaught.g(NeverCaught.java:12)
at exception.NeverCaught.main(NeverCaught.java:21)
Caused by: exception.ExceptionB
at exception.NeverCaught.f(NeverCaught.java:5)
at exception.NeverCaught.g(NeverCaught.java:10)
... 1 more
*/

这个异常链的特性是所有异常均具备的,因为这个initCause()方法是从Throwable继承的。

例4. 清理工作

清理工作对于我们来说是必不可少的,因为如果一些消耗资源的操作,比如IO,JDBC。如果我们用完以后没有及时正确的关闭,那后果会很严重,这意味着内存泄露。异常的出现要求我们必须设计一种机制不论什么情况下,资源都能及时正确的清理。这就是finally。

public void readFile(String file) {
        BufferedReader reader = null;
        try {
            reader = new BufferedReader(new InputStreamReader(
                    new FileInputStream(file)));
            // do some other work
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        } finally {
            try {
                reader.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }

例子非常的简单,是一个读取文件的例子。这样的例子在JDBC操作中也非常的常见。(所以,我觉得对于资源的及时正确清理是一个程序员的基本素质之一。)

Try...finally结构也是保证资源正确关闭的一个手段。如果你不清楚代码执行过程中会发生什么异常情况会导致资源不能得到清理,那么你就用try对这段"可疑"代码进行包装,然后在finally中进行资源的清理。举一个例子:

public void readFile() {
        BufferedReader reader = null;
        try {
            reader = new BufferedReader(new InputStreamReader(
                    new FileInputStream("file")));
            // do some other work
         
            //close reader
            reader.close();
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        } 
    }

我们注意一下这个方法和上一个方法的区别,下一个人可能习惯更好一点,及早的关闭reader。但是往往事与愿违,因为在reader.close()以前异常随时可能发生,这样的代码结构不能预防任何异常的出现。因为程序会在异常出现的地方跳出,后面的代码不能执行(这在上面应经用实例证明过)。这时我们就可以用try...finally来改造:

public void readFile() {
        BufferedReader reader = null;
        try {
            try {
                reader = new BufferedReader(new InputStreamReader(
                        new FileInputStream("file")));
                // do some other work
 
                // close reader
            } finally {
                reader.close();
            }
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

及早的关闭资源是一种良好的行为,因为时间越长你忘记关闭的可能性越大。这样在配合上try...finally就保证万无一失了(不要嫌麻烦,java就是这么中规中矩)。

再说一种情况,假如我想在构造方法中打开一个文件或者创建一个JDBC连接,因为我们要在其他的方法中使用这个资源,所以不能在构造方法中及早的将这个资源关闭。那我们是不是就没辙了呢?答案是否定的。看一下下面的例子:

public class ResourceInConstructor {
    BufferedReader reader = null;
    public ResourceInConstructor() {
        try {
            reader = new BufferedReader(new InputStreamReader(new FileInputStream("")));
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        }
    }
     
    public void readFile() {
        try {
            while(reader.readLine()!=null) {
                //do some work
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
     
    public void dispose() {
        try {
            reader.close();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

这一部分讲的多了一点,但是异常确实是看起来容易用起来难的东西呀,java中还是有好多的东西需要深挖的。

四. 异常的误用

对于异常的误用着实很常见,上一部分中已经列举了几个,大家仔细的看一下。下面再说两个其他的。

例1. 用一个Exception来捕捉所有的异常,颇有"一夫当关万夫莫开"的气魄。不过这也是最傻的行为。

public void readFile(String file) {
        BufferedReader reader = null;
        Connection conn = null;
        try {
            reader = new BufferedReader(new InputStreamReader(
                    new FileInputStream(file)));
            // do some other work
             
            conn = DriverManager.getConnection("");
            //...
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            try {
                reader.close();
                conn.close();
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    }

从异常角度来说这样严格的程序确实是万无一失,所有的异常都能捕获。但是站在编程人员的角度,万一这个程序出错了我们该如何分辨是到底是那引起的呢,IO还是JDBC...所以,这种写法很值得当做一个反例。大家不要以为这种做法很幼稚,傻子才会做。我在公司实习时确实看见了类似的情况:只不过是人家没有用Exception而是用了Throwable。

例2. 这里就不举例子了,上面的程序都是反例。异常是程序处理意外情况的机制,当程序发生意外时,我们需要尽可能多的得到意外的信息,包括发生的位置,描述,原因等等。

这些都是我们解决问题的线索。但是上面的例子都只是简单的printStackTrace()。如果我们自己写代码,就要尽可能多的对这个异常进行描述。比如说为什么会出现这个异常,什么情况下会发生这个异常。如果传入方法的参数不正确,告知什么样的参数是合法的参数,或者给出一个sample。

例3. 将try block写的简短,不要所有的东西都扔在这里,我们尽可能的分析出到底哪几行程序可能出现异常,只是对可能出现异常的代码进行try。尽量为每一个异常写一个try...catch,避免异常丢失。

Weitere Java-Kenntnisse finden Sie in der Spalte Java-Grundlagen-Tutorial.

Das obige ist der detaillierte Inhalt vonAusnahmen in Java müssen Sie kennen. Für weitere Informationen folgen Sie bitte anderen verwandten Artikeln auf der PHP chinesischen Website!

Stellungnahme:
Dieser Artikel ist reproduziert unter:cnblogs.com. Bei Verstößen wenden Sie sich bitte an admin@php.cn löschen