服务器之家:专注于服务器技术及软件下载分享
分类导航

PHP教程|ASP.NET教程|JAVA教程|ASP教程|编程技术|正则表达式|C/C++|

服务器之家 - 编程语言 - JAVA教程 - Java中异常打印输出的常见方法总结

Java中异常打印输出的常见方法总结

2020-11-28 12:28bladestone JAVA教程

Java异常是在Java应用中的警报器,下面这篇文章主要给大家介绍了关于Java中异常打印输出的常见方法的相关资料,文中通过示例代码介绍的非常详细,需要的朋友可以参考借鉴,下面来一起看看吧。

前言

java异常是在java应用中的警报器,在出现异常的情况下,可以帮助我们程序猿们快速定位问题的类型以及位置。但是一般在我们的项目中,由于经验阅历等多方面的原因,依然有若干的童鞋在代码中没有正确的使用异常打印方法,导致在项目的后台日志中,没有收到日志或者日志信息不完整等情况的发生,这些都给项目埋下了若干隐患。本文将深入分析在异常日志打印过程中的若干情况,并给出若干的使用建议。

1. java异常exception的结构分析

我们通常所说的exception主要是继承于throwable而来,可以参见如下的结构图示:

Java中异常打印输出的常见方法总结

主要的throwable分为异常和错误两种,然后异常exception和错误error做为基类,分别被具体个性化以及衍生出nullpointerexception、eofexception等等异常信息类。

基于java中的源代码来分析,error和exception仅仅是继承了throwable,做了构造函数的拓展,没有进行额外方法的延展;exception输出的主要核心方法都是定义在throwable中的,感兴趣的童鞋可以尝试阅读jdk的源代码。

Java中异常打印输出的常见方法总结

下面将介绍一下关键的几个异常类方法:

1、getmessage(): string

输出异常的描述信息

2、getlocalizedmessage()

输出本地化的描述信息,一般此方法可被子类所覆盖,缺省实现与getmessage()输出信息一致

3、printstacktrace()

将异常栈打印到输出流中,此为一类方法,默认打印到console控制台,也可以显式指定输出流。

4、fillinstacktrace()

将当前的异常栈保存到一个throwable中,返回这个throwable。大部分情况下,用在保留异常栈嵌套调用的情况,尝试保留完整的异常栈,无需使用该方法。

2. error vs exception

error在java体系中定义为不可控制的问题,往往用来描述系统错误或者底层的问题,比如虚拟机错误,例如内存空间不足,方法调用栈溢等。我们以上图中列举出的内存溢出错误(stackoverflowerror)为例,它是在jvm层面发生的错误,已经游离于java应用层之外;在应用程序层面是无法进行捕获,且无法从错误中恢复的。一般一旦发了类似问题,一般都是直接宕机,应用停止正常的工作,需要重新启动或者修复问题之后,方可重新正常工作。

exception一般发生在应用层,即在由项目中的java代码层面引发的问题,且可以尝试进行捕获,此类问题不会影响到应用程序的正常工作的,即不会导致宕机现象的发生。我们在工作或者代码中常见的都是exception衍生出来的各类异常。

这里需要强调说明一下,jvm是java语言的运行环境和平台,但是并不是java语言体系的一个部分;在jvm平台上,还可以运行groovy, jpython, jruby, closure,scala等等遵守java语言规范(javalanguage specification)的编程语言,故我们可以将error理解为脱离java应用之外的问题。

3. exception中的运行时异常(runtimeexception)和受控异常(checked exception)

运行时异常(runtimeexception)是指在运行之时发生的异常,无需显式地进行捕获;如果程序中发生类似的异常,jvm会直接抛出此类异常,并打出响应的异常栈信息。此类异常也通常被称为unchecked exception, 未受控异常。

受控异常(checked exception)是我们最常见的异常种类,在代码中使用的异常基本上都是此类异常,此类异常会在代码编译阶段由java编译器进行语法检查,如果未显式进行异常捕获,则会报出相应的编译异常信息。

4. 如何在代码中正确打印异常信息

下面我们将通过一系列的例子来说明上述几个exception中方法的使用技巧。

case 1: getmessage()/getlocalizedmessage()

?
1
2
3
4
5
6
7
8
9
public void testcase1() {
system.out.println("we are going to do something interesting....");
try {
throw new nullpointerexception("i am an exception in the code.");
} catch (exception e) {
system.out.println("we got unexpected:" + e.getmessage());
system.out.println("we got unexpected:" + e.getlocalizedmessage());
}
}

输出结果:

?
1
2
3
we are going to do testing interesting....
we got unexpected in getmessage==> i am an exception in the code.
we got unexpected in getlocalizedmessage==> i am an exception in the code.

基于结果来分析, 上述两个方法只是将异常对象中的message打印出来,这些信息对于我们追踪问题和调试帮助有限。

case 2:e.printstacktrace()

?
1
2
3
4
5
6
7
8
public void testcase2() {
system.out.println("we are going to do something interesting....");
try {
throw new exception("i am an exception in the code.");
} catch (exception e) {
e.printstacktrace();
}
}

运行结果:

Java中异常打印输出的常见方法总结

运行结果图

printstacktrace()可以打印出整个异常栈,但是异常栈信息将输出到默认的输出流中,绝大多数情况下是系统的控制台,而在实际项目中,都是需要将异常栈输出到日志文件的,如果不显式指定,则会丢失异常信息,在日志文件中无从追查。

case 3: 基于log4j/slf4j等输出到日志文件

在实际项目中,一般会使用log4j/log4j2/jdk logging/slf4j/logback等日志系统来存放日志,那如何来讲日志的异常栈存入日志文件呢,我们来看示例。

?
1
2
3
4
5
6
7
8
public void testcase3() {
system.out.println("we are going to do something interesting....");
try {
throw new nullpointerexception("abcedfeg");
} catch (exception e) {
logger.info("unexpected error in ", e);
}
}

我们需要到日志文件中,找到相应的异常信息,异常信息如下:

?
1
2
3
4
12:24:45.387 [main] info org.demo.testexception - unexpected error in
java.lang.nullpointerexception: abcedfeg
at org.demo.testexception.testcase3(testexception.java:39)
at org.demo.testexception.main(testexception.java:12)

我们可以发现,整个异常栈信息由两个部分组成:

>> 异常中的message, 类似getmessage()输出的信息,

>> 使用logger.info之类的方法,将异常信息写入到日志流中.

以下为log4j的声明,这里以slf4j为例来示例:

?
1
private static final logger logger = loggerfactory.getlogger(testexception.class);

case 4: fillinstacktrace()

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
public class fillinexceptiontest {
public static void main(string[] args) {
fillinexceptiontest fit = new fillinexceptiontest();
try {
fit.outermehtod();
} catch (exception e) {
system.out.println("\n==========i am the one evil separation line==============");
e.printstacktrace();
}
}
public void innermethod() throws exception {
throw new exception("i got exception in an inner method.");
}
public void outermehtod() throws exception {
try {
innermethod(); //invoke inner method.
} catch (exception e) {
e.printstacktrace();
throw (exception)e.fillinstacktrace();
}
}
}

运行结果:

Java中异常打印输出的常见方法总结

基于上述的运行结果可知,fillinstacktrace()只提取了当下的异常栈信息,而非完整的异常栈信息,这个就是此方法带给我们的特殊之处。

如果我们需要在最外层将完整的异常栈打印出来,该如何做呢? 将下述的语句:

?
1
throw (exception)e.fillinstacktrace();

替换为:

?
1
throw e;

重新运行程序,我们就可以在最外层得到完整的异常栈信息了。

5. 总结

在本文中,我们介绍了异常类的继承体系,不同类型的异常区别与使用场景;并将基于代码示例展示了如何使用exception的若干方法,利用这些方法来保留尽可能多的日志信息,方便我们后续针对日志中的异常信息,追查和解决问题。

好了,以上就是这篇文章的全部内容了,希望本文的内容对大家的学习或者工作能带来一定的帮助,如果有疑问大家可以留言交流,谢谢大家对服务器之家的支持。

原文链接:http://blog.csdn.net/blueheart20/article/details/71036739

延伸 · 阅读

精彩推荐