目录
一、测试案例
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.util.List;
/**
* @ClassName: T2
* @Author: BlueBlue
* @Description: 异常测试
* @Date: 2023/5/9 0009 10:51
*/
public class T2 {
private static Logger logger = LoggerFactory.getLogger(T2.class);
public static void main(String[] args) {
try{
List list = null;
list.add("1");
list.add("2");
for (Object a: list) {
System.out.println(a);
}
}catch (Exception e){
logger.info("toString:"+e.toString());
logger.info("getMessage:"+e.getMessage());
logger.info("getStackTrace:"+e.getStackTrace());
logger.info("e:"+e);
e.printStackTrace();
}
}
}
二、控制台展示
2023-05-10 14:56:15.317 INFO --- [ main]
com.task.test.T2 : toString:java.lang.NullPointerException
2023-05-10 14:56:15.326 INFO --- [ main]
com.task.test.T2 : getMessage:null
2023-05-10 14:56:15.327 INFO --- [ main]
com.task.test.T2 : getStackTrace:[Ljava.lang.StackTraceElement;@475530b9
2023-05-10 14:56:15.328 INFO --- [ main]
com.task.test.T2 : e:java.lang.NullPointerException
java.lang.NullPointerException
at com.task.test.T2.main(T2.java:22)
三、日志文件打印
四、区别
本文测试了e、e.toString()、e.getMessage()、e.getStackTrace()、e.printStackTrace(); 这五种异常打印,由上述测试案例可以看出:
1)e、e.toString() 和 e.printStackTrace(); 打印效果相同,都将Exception展示出来了,获取的信息包括异常类型和异常详细消息。
但e.printStackTrace();显示的更详细,具体到了某一行,缺点是不能输出到日志文件中,但可以手动定义代码,写入日志文件。
关于e,下面会进行详细介绍,此处不再介绍。
2)e.getMessage()只是获取了异常的详细消息字符串,同时输出到日志文件中。
3)e.getStackTrace()是返回一个表示该线程 堆栈跟踪元素数组。如果该线程尚未启动或已经终止,则该方法将返回一 个零长度数组。如果返回的数组不是零长度的,则其第一个元素代表堆栈 顶,它是该数组中最新的方法调用。最后一个元素代表堆栈 底,是该数组 中最旧的方法调用。
五、源码展示
5.1.e.toString()与getMessage()
/**
* Returns a short description of this throwable.
* The result is the concatenation of:
* <ul>
* <li> the {@linkplain Class#getName() name} of the class of this object
* <li> ": " (a colon and a space)
* <li> the result of invoking this object's {@link #getLocalizedMessage}
* method
* </ul>
* If {@code getLocalizedMessage} returns {@code null}, then just
* the class name is returned.
*
* @return a string representation of this throwable.
*/
/**
* 返回一个简短的描述关于此异常
* 获取此异常的根路径和方法名称
* 返回是此类中某方法的返回
* 三目运算
*/
public String toString() {
String s = getClass().getName();
String message = getLocalizedMessage();
return (message != null) ? (s + ": " + message) : s;
}
/**
* Creates a localized description of this throwable.
* Subclasses may override this method in order to produce a
* locale-specific message. For subclasses that do not override this
* method, the default implementation returns the same result as
* {@code getMessage()}.
*
* @return The localized description of this throwable.
* @since JDK1.1
*/
public String getLocalizedMessage() {
return getMessage();
}
/**
* Returns the detail message string of this throwable.
*
* @return the detail message string of this {@code Throwable} instance
* (which may be {@code null}).
*/
public String getMessage() {
return detailMessage;
}
/**
* Specific details about the Throwable. For example, for
* {@code FileNotFoundException}, this contains the name of
* the file that could not be found.
*
* @serial
*/
private String detailMessage;
toString上面的是英文注释,能看懂的尽量看英文,因为英文写的更详细,中文翻译会出现不准确。
e.toString在调用的过程中,调用了getMessage()方法,返回异常的详细信息。
5.2.e
这里的 e 就是一个类型为 Exception 的异常对象。当然异常类型和对象名都可以随着自己的需求偏好进行更换,只是大家都习惯了用 e 对异常对象进行命名而已。把它补全可能更方便理解:
Exception e = new Exception("运行时异常");
同时,既然它是对象,也有可能存在自己的方法。不写,默认为无参构造。
代码较多,直接截图展示:
重新抛出异常——fillInStackTrace()
fillInStackTrace会首先判断stackTrace是不是为null,如果不为null,则会调用native方法fillInStackTrace将当前线程的栈帧信息记录到此Throwable中 。
stackTrace 记录当前异常堆栈信息,数组中每一个StackTraceElement表示当前当前方法调用的一个栈帧,表示一次方法调用。
backtrace 当本地代码保存在slot中的一些栈的回溯指针
StackTraceElement中保存的有当前方法的类名、方法名、文件名、行号信息。
5.3.e.getStackTrace()
提供对printStackTrace()打印的堆栈跟踪信息的编程访问。堆栈跟踪元素数组,每个元素表示一个堆栈帧。数组的第零元素(假设数组的长度为非零)表示堆栈的顶部,这是顺序中的最后一次方法调用。
在某些情况下,某些虚拟机可能从堆栈跟踪中忽略一个或多个堆栈帧。在极端情况下,不包含堆栈跟踪信息的虚拟机允许从此方法返回零长度数组。一般来说,此方法返回的数组将包含由printStackTrace打印的每个帧的一个元素。写入返回的数组不会影响以后对此方法的调用。
返回:一个堆栈跟踪元素数组,表示与此throwable相关的堆栈跟踪。
getStackTrace()返回的是通过getOurStackTrace方法获取的StackTraceElement[]数组,而这个StackTraceElement是ERROR的每一个cause by的信息。使用者可以根据自己的需求去得到打印信息,相比printStackTrace()会更细一些。
printStackTrace()返回的是一个void值,但是可以看到其方法内部将当前传入打印流锁住,然后同样通过getOurStackTrace方法获取的StackTraceElement[]数组,只不过printStackTrace()方法直接打印出来了。
六、小言
知道不同的日志打印,是开发的基础使用。研究源码是为了弄懂这些方法是怎样实现的,方便进阶版自定义异常。 但自定义异常,本文不做介绍。