企业🤖AI智能体构建引擎,智能编排和调试,一键部署,支持私有化部署方案 广告
# 9.4 创建自己的异常 并不一定非要使用Java异常。这一点必须掌握,因为经常都需要创建自己的异常,以便指出自己的库可能生成的一个特殊错误——但创建Java分级结构的时候,这个错误是无法预知的。 为创建自己的异常类,必须从一个现有的异常类型继承——最好在含义上与新异常近似。继承一个异常相当简单: ``` //: Inheriting.java // Inheriting your own exceptions class MyException extends Exception { public MyException() {} public MyException(String msg) { super(msg); } } public class Inheriting { public static void f() throws MyException { System.out.println( "Throwing MyException from f()"); throw new MyException(); } public static void g() throws MyException { System.out.println( "Throwing MyException from g()"); throw new MyException("Originated in g()"); } public static void main(String[] args) { try { f(); } catch(MyException e) { e.printStackTrace(); } try { g(); } catch(MyException e) { e.printStackTrace(); } } } ///:~ ``` 继承在创建新类时发生: ``` class MyException extends Exception { public MyException() {} public MyException(String msg) { super(msg); } } ``` 这里的关键是`extends Exception`,它的意思是:除包括一个`Exception`的全部含义以外,还有更多的含义。增加的代码数量非常少——实际只添加了两个构造器,对`MyException`的创建方式进行了定义。请记住,假如我们不明确调用一个基类构造器,编译器会自动调用基类默认构造器。在第二个构造器中,通过使用`super`关键字,明确调用了带有一个`String`参数的基类构造器。 该程序输出结果如下: ``` Throwing MyException from f() MyException at Inheriting.f(Inheriting.java:16) at Inheriting.main(Inheriting.java:24) Throwing MyException from g() MyException: Originated in g() at Inheriting.g(Inheriting.java:20) at Inheriting.main(Inheriting.java:29) ``` 可以看到,在从`f()`“抛”出的`MyException`异常中,缺乏详细的消息。 创建自己的异常时,还可以采取更多的操作。我们可添加额外的构造器及成员: ``` //: Inheriting2.java // Inheriting your own exceptions class MyException2 extends Exception { public MyException2() {} public MyException2(String msg) { super(msg); } public MyException2(String msg, int x) { super(msg); i = x; } public int val() { return i; } private int i; } public class Inheriting2 { public static void f() throws MyException2 { System.out.println( "Throwing MyException2 from f()"); throw new MyException2(); } public static void g() throws MyException2 { System.out.println( "Throwing MyException2 from g()"); throw new MyException2("Originated in g()"); } public static void h() throws MyException2 { System.out.println( "Throwing MyException2 from h()"); throw new MyException2( "Originated in h()", 47); } public static void main(String[] args) { try { f(); } catch(MyException2 e) { e.printStackTrace(); } try { g(); } catch(MyException2 e) { e.printStackTrace(); } try { h(); } catch(MyException2 e) { e.printStackTrace(); System.out.println("e.val() = " + e.val()); } } } ///:~ ``` 此时添加了一个数据成员`i`;同时添加了一个特殊的方法,用它读取那个值;也添加了一个额外的构造器,用它设置那个值。输出结果如下: ``` Throwing MyException2 from f() MyException2 at Inheriting2.f(Inheriting2.java:22) at Inheriting2.main(Inheriting2.java:34) Throwing MyException2 from g() MyException2: Originated in g() at Inheriting2.g(Inheriting2.java:26) at Inheriting2.main(Inheriting2.java:39) Throwing MyException2 from h() MyException2: Originated in h() at Inheriting2.h(Inheriting2.java:30) at Inheriting2.main(Inheriting2.java:44) e.val() = 47 ``` 由于异常不过是另一种形式的对象,所以可以继续这个进程,进一步增强异常类的能力。但要注意,对使用自己这个包的客户程序员来说,他们可能错过所有这些增强。因为他们可能只是简单地寻找准备生成的异常,除此以外不做任何事情——这是大多数Java库异常的标准用法。若出现这种情况,有可能创建一个新异常类型,其中几乎不包含任何代码: ``` //: SimpleException.java class SimpleException extends Exception { } ///:~ ``` 它要依赖编译器来创建默认构造器(会自动调用基类的默认构造器)。当然,在这种情况下,我们不会得到一个`SimpleException(String)`构造器,但它实际上也不会经常用到。