没网站能不能cpc广告点击赚钱做,dede产品展示网站模板,房地产app开发,wordpress 绿色主题本章概要
自定义异常 异常与记录日志 异常声明
自定义异常
不必拘泥于 Java 已有的异常类型。Java异常体系不可能预见你将报告的所有错误#xff0c;所以你可以创建自己的异常类#xff0c;来表示你的程序中可能遇到的问题。
要自己定义异常类#xff0c;必须从已有的异…本章概要
自定义异常 异常与记录日志 异常声明
自定义异常
不必拘泥于 Java 已有的异常类型。Java异常体系不可能预见你将报告的所有错误所以你可以创建自己的异常类来表示你的程序中可能遇到的问题。
要自己定义异常类必须从已有的异常类继承最好是选择意思相近的异常类继承不过这样的异常并不容易找。建立新的异常类型最简单的方法就是让编译器为你产生无参构造器所以这几乎不用写多少代码
class SimpleException extends Exception {
}public class InheritingExceptions {public void f() throws SimpleException {System.out.println(Throw SimpleException from f());throw new SimpleException();}public static void main(String[] args) {InheritingExceptions sed new InheritingExceptions();try {sed.f();} catch (SimpleException e) {System.out.println(Caught it!);}}
}输出为 编译器创建了无参构造器它将自动调用基类的无参构造器。本例中不会得到像 SimpleException(String) 这样的构造器这种构造器也不实用。你将看到对异常来说最重要的部分就是类名所以本例中建立的异常类在大多数情况下已经够用了。
本例的结果被显示在控制台。你也可以通过写入 System.err 而将错误发送给标准错误流。通常这比把错误信息输出到 System.out 要好因为 System.out 也许会被重定向。如果把结果送到 System.err它就不会随 System.out 一起被重定向所以用户就更容易注意到它。
你也可以为异常类创建一个接受字符串参数的构造器
// exceptions/FullConstructors.java
class MyException extends Exception {MyException() {}MyException(String msg) {super(msg);}
}public class FullConstructors {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(System.out);}try {g();} catch (MyException e) {e.printStackTrace(System.out);}}
}输出为 新增的代码非常简短两个构造器定义了 MyException 类型对象的创建方式。对于第二个构造器使用 super 关键字明确调用了其基类构造器它接受一个字符串作为参数。
在异常处理程序中调用了在 Throwable 类声明Exception 即从此类继承的 printStackTrace() 方法。就像从输出中看到的它将打印“从方法调用处直到异常抛出处”的方法调用序列。这里信息被发送到了 System.out并自动地被捕获和显示在输出中。但是如果调用默认版本
e.printStackTrace();信息就会被输出到标准错误流。
异常与记录日志
你可能还想使用 java.util.logging 工具将输出记录到日志中。基本的日志记录功能还是相当简单易懂的
import java.util.logging.*;
import java.io.*;class LoggingException extends Exception {private static Logger logger Logger.getLogger(LoggingException);LoggingException() {StringWriter trace new StringWriter();printStackTrace(new PrintWriter(trace));logger.severe(trace.toString());}
}public class LoggingExceptions {public static void main(String[] args) {try {throw new LoggingException();} catch (LoggingException e) {System.err.println(Caught e);}try {throw new LoggingException();} catch (LoggingException e) {System.err.println(Caught e);}}
}输出为 静态的 Logger.getLogger() 方法创建了一个 String 参数相关联的 Logger 对象通常与错误相关的包名和类名这个 Logger 对象会将其输出发送到 System.err。向 Logger 写入的最简单方式就是直接调用与日志记录消息的级别相关联的方法这里使用的是 severe()。为了产生日志记录消息我们欲获取异常抛出处的栈轨迹但是 printStackTrace() 不会默认地产生字符串。为了获取字符串我们需要使用重载的 printStackTrace() 方法它接受一个 java.io.PrintWriter 对象作为参数。如果我们将一个 java.io.StringWriter 对象传递给这个 PrintWriter 的构造器那么通过调用 toString() 方法就可以将输出抽取为一个 String。
尽管由于 LoggingException 将所有记录日志的基础设施都构建在异常自身中使得它所使用的方式非常方便并因此不需要客户端程序员的干预就可以自动运行但是更常见的情形是我们需要捕获和记录其他人编写的异常因此我们必须在异常处理程序中生成日志消息
import java.util.logging.*;
import java.io.*;public class LoggingExceptions2 {private static Logger logger Logger.getLogger(LoggingExceptions2);static void logException(Exception e) {StringWriter trace new StringWriter();e.printStackTrace(new PrintWriter(trace));logger.severe(trace.toString());}public static void main(String[] args) {try {throw new NullPointerException();} catch (NullPointerException e) {logException(e);}}
}输出结果为 还可以更进一步自定义异常比如加入额外的构造器和成员
// exceptions/ExtraFeatures.java
// Further embellishment of exception classes
class MyException2 extends Exception {private int x;MyException2() {}MyException2(String msg) {super(msg);}MyException2(String msg, int x) {super(msg);this.x x;}public int val() {return x;}Overridepublic String getMessage() {return Detail Message: x super.getMessage();}
}public class ExtraFeatures {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(System.out);}try {g();} catch (MyException2 e) {e.printStackTrace(System.out);}try {h();} catch (MyException2 e) {e.printStackTrace(System.out);System.out.println(e.val() e.val());}}
}输出为 新的异常添加了字段 x 以及设定 x 值的构造器和读取数据的方法。此外还覆盖了 Throwable.getMessage() 方法以产生更详细的信息。对于异常类来说getMessage() 方法有点类似于 toString() 方法。
既然异常也是对象的一种所以可以继续修改这个异常类以得到更强的功能。但要记住使用程序包的客户端程序员可能仅仅只是查看一下抛出的异常类型其他的就不管了大多数 Java 库里的异常都是这么用的所以对异常所添加的其他功能也许根本用不上。
异常声明
Java 鼓励人们把方法可能会抛出的异常告知使用此方法的客户端程序员。这是种优雅的做法它使得调用者能确切知道写什么样的代码可以捕获所有潜在的异常。当然如果提供了源代码客户端程序员可以在源代码中查找 throw 语句来获知相关信息然而程序库通常并不与源代码一起发布。为了预防这样的问题Java 提供了相应的语法并强制使用这个语法使你能以礼貌的方式告知客户端程序员某个方法可能会抛出的异常类型然后客户端程序员就可以进行相应的处理。这就是异常说明它属于方法声明的一部分紧跟在形式参数列表之后。
异常说明使用了附加的关键字 throws后面接一个所有潜在异常类型的列表所以方法定义可能看起来像这样
void f() throws TooBig, TooSmall, DivZero { // ...但是要是这样写
void f() { // ...就表示此方法不会抛出任何异常除了从 RuntimeException 继承的异常它们可以在没有异常说明的情况下被抛出这些将在后面进行讨论。
代码必须与异常说明保持一致。如果方法里的代码产生了异常却没有进行处理编译器会发现这个问题并提醒你要么处理这个异常要么就在异常说明中表明此方法将产生异常。通过这种自顶向下强制执行的异常说明机制Java 在编译时就可以保证一定水平的异常正确性。
不过还是有个能“作弊”的地方可以声明方法将抛出异常实际上却不抛出。编译器相信了这个声明并强制此方法的用户像真的抛出异常那样使用这个方法。这样做的好处是为异常先占个位子以后就可以抛出这种异常而不用修改已有的代码。在定义抽象基类和接口时这种能力很重要这样派生类或接口实现就能够抛出这些预先声明的异常。
这种在编译时被强制检查的异常称为被检查的异常。