【Java】异常 打印

如何打印一个异常?

分两种case吧。

1.不使用日志框架,即简单的systemout方式。

    public static void main(String args[]) {
        try {
            new Main().g();
        } catch (Exception e) {
            System.out.println(e);
            System.out.println(e.getMessage());
        }
    }

    public void g() {
        throw new RuntimeException("testEx");
    }

上面是一个简单的例子,运行之后,输出如下:

java.lang.RuntimeException: testEx
testEx

可以看到,似乎并不是我们想要的样子,因为没有堆栈信息,所以直接打印e或者e.getMessage都不是正确姿势。

为什么?

直接打印e,相当于直接调用Exception的toString方法,让我们看看其实现,是继承自其父类中的:

    public String toString() {
        String s = getClass().getName();
        String message = getLocalizedMessage();
        return (message != null) ? (s + ": " + message) : s;
    }

可以看到,仅仅是打印了异常的类名,确实没有调用栈信息。这里的message是一些额外的信息,是父类Throwable里的一个成员变量,如果在构建一个Throwable实例(或子类)传入一个string类型的message时,这个变量就会被赋值。

所以,异常类的toString方法仅仅会打印出异常的类名外加额外指定的message(如果有指定的话)。并且,e.getMessage()方法正是返回了额外的message信息。

那么该如何打印堆栈信息呢?

继续查看Throwable类,发现其有一个stacktrace变量以及相关的方法:

    /**
     * Native code saves some indication of the stack backtrace in this slot.
     */
    private transient Object backtrace;


    private synchronized StackTraceElement[] getOurStackTrace() {
        // Initialize stack trace field with information from
        // backtrace if this is the first call to this method
        if (stackTrace == UNASSIGNED_STACK ||
            (stackTrace == null && backtrace != null) /* Out of protocol state */) {
            int depth = getStackTraceDepth();
            stackTrace = new StackTraceElement[depth];
            for (int i=0; i < depth; i++)
                stackTrace[i] = getStackTraceElement(i);
        } else if (stackTrace == null) {
            return UNASSIGNED_STACK;
        }
        return stackTrace;
    }

    native StackTraceElement getStackTraceElement(int index);

看来,如果想打印异常栈,必须调用这些方法才行。

我们可以看一下apache common库中的工具类:

ExceptionUtils.getStackTrace(e)

结果如下:

java.lang.RuntimeException: testEx
    at com.liyao.s.Main.g(Main.java:114)
    at com.liyao.s.Main.main(Main.java:105)
可以看到,这次是成功打印了。

该方法的实现:

    public static String getStackTrace(Throwable throwable) {
        StringWriter sw = new StringWriter();
        PrintWriter pw = new PrintWriter(sw, true);
        throwable.printStackTrace(pw);
        return sw.getBuffer().toString();
    }

使用一个printwriter实例,将throwable实例的异常栈打印出来,这才是正确打印异常的方法。

 

2.使用日志框架,比如logback。

我们可以直接传入一个throwable实例即可,不需要手动处理其调用栈,logback内部已经封装了相关逻辑。

            logger.error("ex: ", e);

17:38:23.665 [main] ERROR com.liyao.s.Main - ex: 
java.lang.RuntimeException: testEx
    at com.liyao.s.Main.g(Main.java:113) ~[classes/:na]
    at com.liyao.s.Main.main(Main.java:105) ~[classes/:na]

日志框架中都提供了包含Throwable类型参数的日志打印接口:

    void xxx(String var1, Throwable var2);

内部会处理异常栈,我们不必再额外处理异常栈信息。

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值