与使用 Java 中的其他对象一样,我们总是用 new 在堆上创建异常对象,这也伴随着存储空间的分配和构造器的调用。所有标准异常类都有两个构造器:一个是无参构造器;另一个是接受字符串作为参数,以便能把相关信息放入异常对象的构造器
public class Catch { public static void main(String[] args) { // 传入参数给异常的构造函数 throw new NullPointerException("t = quan"); } } /* 结果: Exception in thread "main" java.lang.NullPointerException: t = quan at Catch.main(Catch.java:7) */
在使用 new 创建了异常对象之后,此对象的引用将传给 throw。
输出异常相应信息;
printStackTrace() 方法:指出异常的类型、性质、栈层次及出现在程序中的位置
getMessage() 方法:输出错误的性质。
toString() 方法:给出异常的类型与性质。
public class Catch { public static void main(String[] args) { try{ throw new NullPointerException(); }catch (NullPointerException e){ e.printStackTrace(); System.out.println("DDDDDDDDDDDDDDDD"); e.getMessage(); System.out.println("EEEEEEEEEEEEEEEEEE"); e.toString(); } } } /* 结果: java.lang.NullPointerException at Catch.main(Catch.java:9) DDDDDDDDDDDDDDDD EEEEEEEEEEEEEEEEEE */
异常的捕获便于我们对方法内部的代码检验,一旦方法内部出现异常,我们可以使用try语句进行捕获
try { // Code that might generate exceptions } catch(Type1 id1) { // Handle exceptions of Type1 } catch(Type2 id2) { // Handle exceptions of Type2 } catch(Type3 id3) { // Handle exceptions of Type3 } // etc.
在多个 catch 代码块的情况下,当一个 catch 代码块捕获到一个异常时,其它的 catch 代码块就不再进行匹配。
或者使用: try{ x(); }catch(Exception1|Exception2 e){ do somethings }
注意:当捕获的多个异常类之间存在父子关系时,捕获异常时一般先捕获子类,再捕获父类。所以子类异常必须在父类异常的前面,否则子类捕获不到
捕获所有异常
只写一个异常处理程序来捕获所有类型的异常。通过捕获异常类型的基类 Exception
catch(Exception e) { System.out.println("Caught an exception"); }
这将捕获所有异常,所以最好把它放在处理程序列表的末尾,以防它抢在其他处理程序之前先把异常捕获了
public static void f() throws NullPointerException{ System.out.println("00"); }
它使得调用者能确切知道写什么样的代码可以捕获所有潜在的异常
public class Catch { public static void f() { try{ throw new Exception(); }catch (Exception e){ for(StackTraceElement ste:e.getStackTrace()) System.out.println(ste.getMethodName()); } } public static void h(){f();} public static void g(){f();} public static void main(String[] args) { f(); System.out.println("@@@@@@@@@@@@"); g(); System.out.println("@@@@@@@@@@@@"); h(); System.out.println("@@@@@@@@@@@@"); } } /* f 后进栈 main 先进栈 @@@@@@@@@@@@ f g main @@@@@@@@@@@@ f h main @@@@@@@@@@@@ */
public static void f() { try{ g(); }catch (Exception e){ // 重新抛出异常 throw e; } }
重抛异常会把异常抛给上一级环境中的异常处理程序,同一个 try 块的后续 catch 子句将被忽略。此外,异常对象的所有信息都得以保持,所以高一级环境中捕获此异常的处理程序可以从这个异常对象中得到所有信息。
如果只是把当前异常对象重新抛出,那么 printStackTrace() 方法显示的将是原来异常抛出点的调用栈信息,而并非重新抛出点的信息。要想更新这个信息,可以调用 filInStackTrace() 方法,这将返回一个 Throwable 对象,它是通过把当前调用栈信息填入原来那个异常对象而建立的
public class Rethrowiing { public static void f() throws Exception{ System.out.println("fffffffffffff"); throw new Exception("up f"); } public static void g() throws Exception{ try{ f(); }catch (Exception e){ System.out.println("gggg"); e.printStackTrace(System.out); throw e; } } public static void h() throws Exception{ try{ g(); }catch (Exception e){ System.out.println("hhhh"); e.printStackTrace(System.out); throw (Exception)e.fillInStackTrace(); } } public static void main(String[] args) { try{ g(); }catch (Exception e){ System.out.println("mmmmm"); e.printStackTrace(System.out); } try{ h(); }catch (Exception e){ System.out.println("mmmmm"); e.printStackTrace(System.out); } } } // fffffffffffff // gggg // java.lang.Exception: up f // at Rethrowiing.f(Rethrowiing.java:4) // at Rethrowiing.g(Rethrowiing.java:9) // at Rethrowiing.main(Rethrowiing.java:28) // mmmmm // java.lang.Exception: up f // at Rethrowiing.f(Rethrowiing.java:4) // at Rethrowiing.g(Rethrowiing.java:9) // at Rethrowiing.main(Rethrowiing.java:28) //上面的异常的栈轨迹没有发生变化,因为打印的还是原来产生异常的点 // fffffffffffff // gggg // java.lang.Exception: up f // at Rethrowiing.f(Rethrowiing.java:4) // at Rethrowiing.g(Rethrowiing.java:9) // at Rethrowiing.h(Rethrowiing.java:19) // at Rethrowiing.main(Rethrowiing.java:35) // hhhh // java.lang.Exception: up f // at Rethrowiing.f(Rethrowiing.java:4) // at Rethrowiing.g(Rethrowiing.java:9) // at Rethrowiing.h(Rethrowiing.java:19) // at Rethrowiing.main(Rethrowiing.java:35) // mmmmm // java.lang.Exception: up f // at Rethrowiing.h(Rethrowiing.java:23) // at Rethrowiing.main(Rethrowiing.java:35)
Throwable 这个 Java 类被用来表示任何可以作为异常被抛出的类。Throwable 对象可分为两种类型(指从 Throwable 继承而得到的类型):Error 用来表示编译时和系统错误(除特殊情况外,一般不用你关心);Exception 是可以被抛出的基本类型,
有一些代码片段,可能会希望无论 try 块中的异常是否抛出,它们都能得到执行。这通常适用于内存回收之外的情况(因为回收由垃圾回收器完成),为了达到这个效果,可以在异常处理程序后面加上 finally 子句
try{ something }catch (some Exception e){ do something }final { do something }
class ThreeException extends Exception{} public class FinallyWorks { static int count = 0; public static void main(String[] args) { while (true){ try{ if (count++ ==0){ throw new ThreeException(); } System.out.println("No exception"); }catch (ThreeException e ){ System.out.println("ThreeException"); } finally { System.out.println("in finally clasus"); if (count == 2) break; } } } }
当要把除内存之外的资源恢复到它们的初始状态时,就要用到 finally 子句。这种需要清理的资源包括:已经打开的文件或网络连接,在屏幕上画的图形,甚至可以是外部世界的某个开关
finally 和return无关;
public class MultipleReturns { public static void f(int i){ System.out.println("BBBBB"); try{ System.out.println("1111"); if (i == 1){ return; } System.out.println("222"); if (i == 2){ return; } System.out.println("333"); if (i == 3){ return; } }finally { System.out.println("DDDDDD"); } } public static void main(String[] args) { for (int i =1;i <= 4;i++){ f(i); } } }
try-with-resources 语法
python的with语句差不多:
主要是在打开的时候发生错误,或者在打开之后,写入的时候发生的异常,导致文件对象丢失
不能得到关闭
def writing_in_python(): with open("pdata", "w") as f: f.write(str(666)) f.write("Hello")
java使用的是:
public class TryWith { public static void main(String[] args) { try( InputStream in = new FileInputStream( new File("Catch.java")) ){ int contents = in.read(); }catch (IOException e){ System.out.println("something"); } } }
注意try旁边是括号,然后紧接的是中括号。在 try 块中声明打开的任何资源都会关闭。因此,这个新结构使您不必配对使用 try 块与对应的 finally 块,后者专用于正确的资源管理。
try 总是后面跟着一个 {,但是现在可以跟一个带括号的定义 - 这里是我们创建的 FileInputStream
对象。括号内的部分称为资源规范头(resource specification header)。现在可用于整个 try 块
的其余部分。更重要的是,无论你如何退出 try 块(正常或异常),都会执行前一个 finally 子句的
等价物
在 try-with-resources 定义子句中创建的对象(在括号内)必须实现 java.lang.AutoCloseable
接口,这个接口有一个方法:close()。当在 Java 7 中引入 AutoCloseable 时,许多接口和类被
修改以实现它;
异常处理的一个重要原则是“只有在你知道如何处理的情况下才捕获异常"。实际上,异常处理的一个重要目
标就是把错误处理的代码同错误发生的地点相分离。这使你能在一段代码中专注于要完成的事情,至于如
何处理错误,则放在另一段代码中完成。这样一来,主要代码就不会与错误处理逻辑混在一起,也更容易理
解和维护。通过允许一个处理程序去处理多个出错点,异常处理还使得错误处理代码的数量趋于减少
原文:https://www.cnblogs.com/java-quan/p/12982507.html