🔥码云GVP开源项目 12k star Uniapp+ElementUI 功能强大 支持多语言、二开方便! 广告
### [异常与记录日志](https://lingcoder.gitee.io/onjava8/#/book/15-Exceptions?id=%e5%bc%82%e5%b8%b8%e4%b8%8e%e8%ae%b0%e5%bd%95%e6%97%a5%e5%bf%97) 你可能还想使用 java.util.logging 工具将输出记录到日志中。基本的日志记录功能还是相当简单易懂的: ~~~ // exceptions/LoggingExceptions.java // An exception that reports through a Logger // {ErrorOutputExpected} 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); } } } ~~~ 输出为: ~~~ ___[ Error Output ]___ May 09, 2017 6:07:17 AM LoggingException <init> SEVERE: LoggingException at LoggingExceptions.main(LoggingExceptions.java:20) Caught LoggingException May 09, 2017 6:07:17 AM LoggingException <init> SEVERE: LoggingException at LoggingExceptions.main(LoggingExceptions.java:25) Caught LoggingException ~~~ 静态的 Logger.getLogger() 方法创建了一个 String 参数相关联的 Logger 对象(通常与错误相关的包名和类名),这个 Logger 对象会将其输出发送到 System.err。向 Logger 写入的最简单方式就是直接调用与日志记录消息的级别相关联的方法,这里使用的是 severe()。为了产生日志记录消息,我们欲获取异常抛出处的栈轨迹,但是 printStackTrace() 不会默认地产生字符串。为了获取字符串,我们需要使用重载的 printStackTrace() 方法,它接受一个 java.io.PrintWriter 对象作为参数(PrintWriter 会在[附录:I/O 流](https://lingcoder.gitee.io/onjava8/#/./Appendix-IO-Streams)一章详细介绍)。如果我们将一个 java.io.StringWriter 对象传递给这个 PrintWriter 的构造器,那么通过调用 toString() 方法,就可以将输出抽取为一个 String。 尽管由于 LoggingException 将所有记录日志的基础设施都构建在异常自身中,使得它所使用的方式非常方便,并因此不需要客户端程序员的干预就可以自动运行,但是更常见的情形是我们需要捕获和记录其他人编写的异常,因此我们必须在异常处理程序中生成日志消息; ~~~ // exceptions/LoggingExceptions2.java // Logging caught exceptions // {ErrorOutputExpected} 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); } } } ~~~ 输出结果为: ~~~ ___[ Error Output ]___ May 09, 2017 6:07:17 AM LoggingExceptions2 logException SEVERE: java.lang.NullPointerException at LoggingExceptions2.main(LoggingExceptions2.java:17) ~~~ 还可以更进一步自定义异常,比如加入额外的构造器和成员: ~~~ // 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; } @Override public 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()); } } } ~~~ 输出为: ~~~ Throwing MyException2 from f() MyException2: Detail Message: 0 null at ExtraFeatures.f(ExtraFeatures.java:24) at ExtraFeatures.main(ExtraFeatures.java:38) Throwing MyException2 from g() MyException2: Detail Message: 0 Originated in g() at ExtraFeatures.g(ExtraFeatures.java:29) at ExtraFeatures.main(ExtraFeatures.java:43) Throwing MyException2 from h() MyException2: Detail Message: 47 Originated in h() at ExtraFeatures.h(ExtraFeatures.java:34) at ExtraFeatures.main(ExtraFeatures.java:48) e.val() = 47 ~~~ 新的异常添加了字段 x 以及设定 x 值的构造器和读取数据的方法。此外,还覆盖了 Throwable. getMessage() 方法,以产生更详细的信息。对于异常类来说,getMessage() 方法有点类似于 toString() 方法。 既然异常也是对象的一种,所以可以继续修改这个异常类,以得到更强的功能。但要记住,使用程序包的客户端程序员可能仅仅只是查看一下抛出的异常类型,其他的就不管了(大多数 Java 库里的异常都是这么用的),所以对异常所添加的其他功能也许根本用不上。