Java 异常中 e.getMessage() 和 e.toString() e.printStackTrace()的区别
一、概述
在java异常体系中,要打印异常信息,可以通过:e.getMessage() 、 e.toString() e.printStackTrace() 等方法打印出 一些 异常信息。已知的是这些方法都可以打印异常信息,但是这些方法打印的异常信息 都不相同,那么问题来啦: 这些方法打印异常信息的区别是?日常开发工作中,该用哪个方法打印异常信息呢?
二、代码理解
1、 Junit 单元测试 — 模拟异常信息输出
@Test
public void test(){int num = 0 ;try {int i = 3/num ;} catch (Exception e) {System.out.println(" e.printStackTrace() ==== start");e.printStackTrace();System.out.println(" e.printStackTrace() ==== end ");System.out.println();System.out.println(" e.getMessage() ==== start");System.out.println(e.getMessage());System.out.println(" e.getMessage() ==== end");System.out.println();System.out.println(" e.toString() ==== start");System.out.println(e.toString());System.out.println(" e.toString() ==== end");System.out.println();System.out.println(" e.getExceptionToString() ==== start");System.out.println(Exceptions.getExceptionToString(e));System.out.println(" e.getExceptionToString() ==== end");}
}
1.1、输出结果如下:
@Test
public void test(){int num = 0 ;try {int i = 3/num ;} catch (Exception e) {System.out.println(" e.printStackTrace() ==== start");e.printStackTrace();System.out.println(" e.printStackTrace() ==== end ");System.out.println();System.out.println(" e.getMessage() ==== start");System.out.println(e.getMessage());System.out.println(" e.getMessage() ==== end");System.out.println();System.out.println(" e.toString() ==== start");System.out.println(e.toString());System.out.println(" e.toString() ==== end");System.out.println();System.out.println(" e.getExceptionToString() ==== start");System.out.println(Exceptions.getExceptionToString(e));System.out.println(" e.getExceptionToString() ==== end");}
}
1.2、结果分析 :
- e.printStackTrace(): 打印完整的异常堆栈信息
- e.getMessage(): 打印 异常的原因
- e.toString(): 打印 异常类型 和 异常的原因
- e.getExceptionToString(): 打印完整的异常堆栈信息
2、web 环境下 — 模拟异常信息输出
@RequestMapping("/exp")
@ResponseBody
public String exp(String key){int num = 0 ;try {int i = 3/num ;} catch (Exception e) {System.out.println(" e.printStackTrace() ==== start");e.printStackTrace();System.out.println(" e.printStackTrace() ==== end ");System.out.println();System.out.println(" e.getMessage() ==== start");System.out.println(e.getMessage());System.out.println(" e.getMessage() ==== end");System.out.println();System.out.println(" e.toString() ==== start");System.out.println(e.toString());System.out.println(" e.toString() ==== end");System.out.println();System.out.println(" e.getExceptionToString() ==== start");System.out.println(Exceptions.getExceptionToString(e));System.out.println(" e.getExceptionToString() ==== end");}return "success";
}
2.1、输出结果如下:
e.printStackTrace() ==== starte.printStackTrace() ==== end e.getMessage() ==== start
/ by zeroe.getMessage() ==== ende.toString() ==== start
java.lang.ArithmeticException: / by zeroe.toString() ==== ende.getExceptionToString() ==== start
java.lang.ArithmeticException: / by zeroat com.runcode.springboottourist.ExpController.exp(ExpController.java:54)at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)at java.lang.reflect.Method.invoke(Method.java:498)at org.springframework.web.method.support.InvocableHandlerMethod.doInvoke(InvocableHandlerMethod.java:189)at org.springframework.web.method.support.InvocableHandlerMethod.invokeForRequest(InvocableHandlerMethod.java:138)at org.springframework.web.servlet.mvc.method.annotation.ServletInvocableHandlerMethod.invokeAndHandle(ServletInvocableHandlerMethod.java:102)at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.invokeHandlerMethod(RequestMappingHandlerAdapter.java:895)at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.handleInternal(RequestMappingHandlerAdapter.java:800)at org.springframework.web.servlet.mvc.method.AbstractHandlerMethodAdapter.handle(AbstractHandlerMethodAdapter.java:87)at org.springframework.web.servlet.DispatcherServlet.doDispatch(DispatcherServlet.java:1038)at org.springframework.web.servlet.DispatcherServlet.doService(DispatcherServlet.java:942)at org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:1005)at org.springframework.web.servlet.FrameworkServlet.doGet(FrameworkServlet.java:897)at javax.servlet.http.HttpServlet.service(HttpServlet.java:634)at org.springframework.web.servlet.FrameworkServlet.service(FrameworkServlet.java:882)at javax.servlet.http.HttpServlet.service(HttpServlet.java:741)at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:231)at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166)at org.apache.tomcat.websocket.server.WsFilter.doFilter(WsFilter.java:53)at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193)at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166)at org.springframework.web.filter.RequestContextFilter.doFilterInternal(RequestContextFilter.java:99)at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107)at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193)at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166)at org.springframework.web.filter.FormContentFilter.doFilterInternal(FormContentFilter.java:92)at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107)at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193)at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166)at org.springframework.web.filter.HiddenHttpMethodFilter.doFilterInternal(HiddenHttpMethodFilter.java:93)at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107)at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193)at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166)at org.springframework.web.filter.CharacterEncodingFilter.doFilterInternal(CharacterEncodingFilter.java:200)at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107)at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193)at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166)at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:199)at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:96)at org.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:490)at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:139)at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:92)at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:74)at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:343)at org.apache.coyote.http11.Http11Processor.service(Http11Processor.java:408)at org.apache.coyote.AbstractProcessorLight.process(AbstractProcessorLight.java:66)at org.apache.coyote.AbstractProtocol$ConnectionHandler.process(AbstractProtocol.java:834)at org.apache.tomcat.util.net.NioEndpoint$SocketProcessor.doRun(NioEndpoint.java:1417)at org.apache.tomcat.util.net.SocketProcessorBase.run(SocketProcessorBase.java:49)at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1149)at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:624)at org.apache.tomcat.util.threads.TaskThread$WrappingRunnable.run(TaskThread.java:61)at java.lang.Thread.run(Thread.java:748)e.getExceptionToString() ==== end
java.lang.ArithmeticException: / by zeroat com.runcode.springboottourist.ExpController.exp(ExpController.java:54)at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)at java.lang.reflect.Method.invoke(Method.java:498)at org.springframework.web.method.support.InvocableHandlerMethod.doInvoke(InvocableHandlerMethod.java:189)at org.springframework.web.method.support.InvocableHandlerMethod.invokeForRequest(InvocableHandlerMethod.java:138)at org.springframework.web.servlet.mvc.method.annotation.ServletInvocableHandlerMethod.invokeAndHandle(ServletInvocableHandlerMethod.java:102)at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.invokeHandlerMethod(RequestMappingHandlerAdapter.java:895)at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.handleInternal(RequestMappingHandlerAdapter.java:800)at org.springframework.web.servlet.mvc.method.AbstractHandlerMethodAdapter.handle(AbstractHandlerMethodAdapter.java:87)at org.springframework.web.servlet.DispatcherServlet.doDispatch(DispatcherServlet.java:1038)at org.springframework.web.servlet.DispatcherServlet.doService(DispatcherServlet.java:942)at org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:1005)at org.springframework.web.servlet.FrameworkServlet.doGet(FrameworkServlet.java:897)at javax.servlet.http.HttpServlet.service(HttpServlet.java:634)at org.springframework.web.servlet.FrameworkServlet.service(FrameworkServlet.java:882)at javax.servlet.http.HttpServlet.service(HttpServlet.java:741)at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:231)at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166)at org.apache.tomcat.websocket.server.WsFilter.doFilter(WsFilter.java:53)at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193)at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166)at org.springframework.web.filter.RequestContextFilter.doFilterInternal(RequestContextFilter.java:99)at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107)at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193)at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166)at org.springframework.web.filter.FormContentFilter.doFilterInternal(FormContentFilter.java:92)at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107)at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193)at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166)at org.springframework.web.filter.HiddenHttpMethodFilter.doFilterInternal(HiddenHttpMethodFilter.java:93)at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107)at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193)at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166)at org.springframework.web.filter.CharacterEncodingFilter.doFilterInternal(CharacterEncodingFilter.java:200)at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107)at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193)at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166)at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:199)at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:96)at org.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:490)at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:139)at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:92)at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:74)at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:343)at org.apache.coyote.http11.Http11Processor.service(Http11Processor.java:408)at org.apache.coyote.AbstractProcessorLight.process(AbstractProcessorLight.java:66)at org.apache.coyote.AbstractProtocol$ConnectionHandler.process(AbstractProtocol.java:834)at org.apache.tomcat.util.net.NioEndpoint$SocketProcessor.doRun(NioEndpoint.java:1417)at org.apache.tomcat.util.net.SocketProcessorBase.run(SocketProcessorBase.java:49)at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1149)at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:624)at org.apache.tomcat.util.threads.TaskThread$WrappingRunnable.run(TaskThread.java:61)at java.lang.Thread.run(Thread.java:748)
2.2、结果分析:
- e.printStackTrace(): 打印完整的异常堆栈信息 (在e.getExceptionToString 后面) e.getMessage(): 打印 异常的原因
- e.toString(): 打印 异常类型 和 异常的原因
- e.getExceptionToString(): 打印完整的异常堆栈信息
三、总结
1、Exceptions.getExceptionToString(e) 方法,参考这里:java中将异常Exception转化为String字符串输出
2、e.getMessage() 和 e.toString() 方法: 打印的异常信息太少,没有具体的堆栈信息,不利于问题的定位处理, 不建议使用!
3、e.printStackTrace() 和 Exceptions.getExceptionToString(e) 方法:都可以打印完整的异常堆栈信息; 二者的区别是: e.printStackTrace() 在遇到大量并发访问 且 出现异常时,会发生:内存被占满的情况,导致服务挂掉,不可用 …
4、日常开发中,会使用 log.error 来打印异常信息,下面比较几种 log.error 打印异常信息的区别:
@RequestMapping("/log")
@ResponseBody
public String log(String key){int num = 0 ;try {int i = 3/num ;} catch (Exception e) {System.out.println(" log.error(\"exp failure \"+ e) ==== start");log.error("exp failure "+ e);System.out.println(" log.error(\"exp failure \"+ e) ==== end");System.out.println();System.out.println(" log.error(\"exp failure {}\"+ e) ==== start");log.error("exp failure {}" + e);System.out.println(" log.error(\"exp failure {}\"+ e) ==== end");System.out.println();System.out.println(" log.error(\"exp failure {}\", e) ==== start");log.error("exp failure {}" , e);System.out.println(" log.error(\"exp failure {}\" ,e) ==== end");System.out.println();System.out.println(" log.error(\"exp failure {}\", getExceptionToString) ==== start");log.error("exp failure {}" , Exceptions.getExceptionToString(e));System.out.println(" log.error(\"exp failure {}\" ,getExceptionToString) ==== end");}return "success";
}
4.1、输出结果:
1、 log.error("exp failure "+ e) ==== start2022-09-20 16:48:51.783 ERROR 34220 --- [nio-8080-exec-8] c.r.springboottourist.ExpController : exp failure java.lang.ArithmeticException: / by zerolog.error("exp failure "+ e) ==== end2、 log.error("exp failure {}"+ e) ==== start2022-09-20 16:48:51.783 ERROR 34220 --- [nio-8080-exec-8] c.r.springboottourist.ExpController : exp failure {}java.lang.ArithmeticException: / by zerolog.error("exp failure {}"+ e) ==== end3、 log.error("exp failure {}", e) ==== start2022-09-20 16:48:51.784 ERROR 34220 --- [nio-8080-exec-8] c.r.springboottourist.ExpController : exp failure {}java.lang.ArithmeticException: / by zero-- 省略异常堆栈信息log.error("exp failure {}" ,e) ==== end4、 log.error("exp failure {}", getExceptionToString) ==== start2022-09-20 16:48:51.785 ERROR 34220 --- [nio-8080-exec-8] c.r.springboottourist.ExpController : exp failure java.lang.ArithmeticException: / by zero-- 省略异常堆栈信息log.error("exp failure {}" ,getExceptionToString) ==== end
4.2、结果分析:
1、2 两种情况:都是属于拼接字符串,实际调用的是 e.toString() 方法
3 :使用了占位符输出日志,打印了完整的堆栈信息, 但是 占位符 貌似没被识别到。
4 :使用了占位符输出日志,打印了完整的堆栈信息, 将异常对象转换为字符串后, 占位符 被识别到。
5、日常开发工作中,该用哪个方法打印异常信息呢:
1.异常对象转换为字符串:
String errMsg = Exceptions.getExceptionToString(e);
- 日志输出:
log.error("exp failure : {}",errMsg);
常见的几种异常常见的几种异常
异常是程序中的一些错误,但并不是所有的错误都是异常,并且错误有时候是可以避免的。比如说,代码中少了一个分号,那么就会提示错误 java.lang.Error;又比如我们在数学运算的时候,让 0 作了除数,那么此时就会抛出 java.lang.ArithmeticException 异常。异常产生的原因有很多,通常来说,包括以下几类:
(1)用户输入了非法的数据;
(2)要打开的文件不存在
(3)网络通信时连接中断,或者 JVM 内存溢出
这些异常有些是因为用户的错误引起的,有些则是因为程序错误引起的,还有其他一些可能是因为物理错误引起的。通常来说,有以下三种类型的异常:
(1)检查性异常:最具代表的检查性异常就是用户错误引起的异常,这是程序无法预见的。例如要打开一个不存在的文件时,异常就会发生,这些异常在编译时不能被简单地忽略。
(2)运行时异常:运行时异常是可能被程序员避免的异常。与检查性异常相反,运行时异常可以在编译时被忽略。
(3)错误:其实错误并不是异常,而是脱离了程序员控制的问题。错误在代码中通常会被忽略。例如,当栈溢出时,错误就发生了,它们在编译也检查不到的。
Exception 类的层次
所有的异常类其实都是从 java.lang.Exception 类继承的子类,而 Exception 类又是 Throwable 类的子类,除了 Exception 外,Throwable 还有一个子类叫 Error。Error 用来指示运行时环境发生的错误,Java 程序通常不捕获错误,错误一般发生在严重故障时,它们是在 Java 程序处理的范畴之外的。例如,JVM 内存溢出时,一般情况下,程序是不会从错误中恢复的。Exception 类有两个主要的字类:IOException 类和 RuntimeException 类。
Java 内置异常类
Java 语言在 java.lang 标准包中定义了一些异常类。标准运行时异常类的子类是最常见的异常类,由于 java.lang 包是默认加载到所有的 Java 程序中的,所以大部分从运行时异常类继承而来的异常都是可以直接使用的。常见的非检查性异常有:
异常名称 | 说明 |
---|---|
ArithmeticException | 当出现异常的运算条件时,抛出此异常。如,0 作为除数 |
ArrayIndexOutOfBoundsException | 使用非法索引访问数组时抛出的异常。如索引为负,或者索引大于等于数组长度 |
ArrayStoreException | 试图将错误类型的对象存储到一个对象数组时抛出的异常 |
ClassCaseException | 试图将对象强制转换为不是实例的子类时,抛出该异常 |
IllegalArgumentException | 向方法传递了一个不合法或不正确的参数时抛出该异常 |
IllegalMonitorStateException | 某一线程已经试图等待对象的监视器,或者试图通知其他正在等待对象的监视器而本身没有指定监视器的线程时抛出该异常 |
IllegalThreadStateException | 线程没有处于请求操作所要求的适当状态时抛出的异常 |
IllegalStateException | 在非法或不适当的时间调用方法时产生的异常,即 Java 环境或 Java 应用程序没有处于请求操作所要求的适当状态下 |
IndexOutOfBoundsException | 某排序索引(如对数组、字符串或向量排序时)超出范围时抛出 |
NegativeArraySizeException | 如果应用程序试图创建大小为负的数组,抛出该异常 |
NullPointerException | 当应用程序试图在需要使用对象的地方使用 null 时,抛出该异常 |
NumberFormatException | 当应用程序试图将字符串转换成一种数值类型,但该字符串不能转换为适当格式时,抛出该异常 |
SecurityException | 由安全管理器抛出的异常,指示存在安全侵犯 |
StringIndexOutOfBoundsException | String 字符串中,索引为负,或者索引超出字符串的大小时抛出该异常 |
UnsupportedOperationException | 当不支持请求的操作时,抛出该异常 |
检查性异常有:
异常 | 说明 |
---|---|
ClassNotFoundException | 应用程序试图加载类时,找不到相应的类,抛出该异常 |
CloneNotSupportedException | 当调用 Object 类中的 clone 方法克隆对象,但该对象的类无法实现 Cloneable 接口时,抛出该异常 |
IllegalAccessException | 拒绝访问一个类的时候抛出该异常 |
InstantiationException | 当试图使用 class 类中的 newInstance 方法创建一个类的实例,而指定的类对象因为是一个接口或是一个抽象类而无法实例化时,抛出该异常 |
InterruptedException | 一个线程被另一个线程中断时,抛出该异常 |
NoSuchFieldException | 请求的变量不存在时抛出该异常 |
NoSuchMethodException | 请求的方法不存在时抛出该异常 |
异常方法
Throwable 类的主要方法:
方法 | 说明 |
---|---|
public String getMessage() | 返回关于发生的异常的详细信息 |
public Throwable getCause() | 返回一个 Throwable 对象代表异常原因 |
public String toString() | 使用 getMessage() 的结果返回类的串级名字 |
public void printStackTrace() | 打印 toString() 结果和栈层次到错误输出流 |
public StackTraceElement[] getStackTrace() | 返回一个包含堆栈层次的数组,下标为 0 的元素代表栈顶,最后一个元素代表方法调用堆栈的栈底 |
public Throwable fillInStackTrace() | 用当前的调用栈层次填充 Throwable 对象栈层次,添加栈层次中任何之前信息中 |
Java 异常处理方式
Java 通过面向对象的方法进行异常处理,一旦方法抛出异常,系统自动根据该异常对象寻找合适的异常处理器(Exception Handle)来处理该异常,把各种不同的异常进行分类,并提供了良好的接口。
在 Java 中,每个异常都是一个对象,它是 Throwable 类或其子类的实例。当一个方法出现异常之后便会抛出一个异常对象,该对象中包含异常信息,调用这个对象的方法可以捕获到这个异常并可以对其进行处理。Java 的异常处理是通过 5 个关键字来实现的:throw、throws、try、catch、finally。
在 Java 中,异常的处理机制分为声明异常(由关键字 throws 处理)、抛出异常(由关键字 throw 处理)和捕获异常。
throw 和 throws 的区别:
位置不同:throw 在方法内部使用;throws 在方法的声明处使用;
内容不同:throw + 异常对象(检查异常,运行时异常);throws + 异常类型(可以 throws 多个类型,用 “,” 分隔即可)
作用不同:throw 使用在异常的源头,即制造异常;throws 使用在方法的声明处,即告诉方法的调用者,这个方法可能会出现声明的这种异常,调用者需要对这种异常进行处理,要么自己内部消化,要么继续向上抛。