得到当前堆栈信息的两种方式(Thread和Throwable)的方法

今天看到有一个工具类中有一句

Thread.currentThread().getStackTrace()[2].getClassName();


原来工作中遇到的问题:使用Thread.currentThread().getStackTrace()[1].getClassName()得到的是当前类而不是调用类。

所以弄个明白 。

我进行了一组测试:

测试A:

public class ThreadTest {

	public static void TestString(){
		StackTraceElement[] arr = new Exception().getStackTrace();
		for(int i=0;i<=arr.length-1;i++){
			System.out.println(arr[i].getClassName()+";"+arr[i].getMethodName()+";"+arr[i].getFileName());
		}
	}
}
public class App 
{
    public static void main( String[] args )
    {
        ThreadTest.TestString();
    }
}

     结果是:

test.ThreadTest;TestString;ThreadTest.java(当前方法和类)

test.App;main;App.java(调用该方法的方法和类)

测试B:

public class ThreadTest {

	public static void TestString(){
		StackTraceElement[] arr = Thread.currentThread().getStackTrace();
		for(int i=0;i<=arr.length-1;i++){
			System.out.println(arr[i].getClassName()+";"+arr[i].getMethodName()+";"+arr[i].getFileName());
		}
	}
}

App类同上,得到的结果是:

java.lang.Thread;getStackTrace;Thread.java(Thread的信息)

test.ThreadTest;TestString;ThreadTest.java(当前方法和类)

test.App;main;App.java(调用该方法的方法和类)

查看了下jdk的源码。

首先是Throwable的getStackTrace方法,代码如下:

public StackTraceElement[] getStackTrace() {
		return getOurStackTrace().clone();
	}

	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;
	}

再看下Thread的getStackTrace方法,代码如下:

public StackTraceElement[] getStackTrace() {
		if (this != Thread.currentThread()) {
			// check for getStackTrace permission
			SecurityManager security = System.getSecurityManager();
			if (security != null) {
				security.checkPermission(
					SecurityConstants.GET_STACK_TRACE_PERMISSION);
			}
			// optimization so we do not call into the vm for threads that
			// have not yet started or have terminated
			if (!isAlive()) {
				return EMPTY_STACK_TRACE;
			}
			StackTraceElement[][] stackTraceArray = dumpThreads(new Thread[] {this});
			StackTraceElement[] stackTrace = stackTraceArray[0];
			// a thread that was alive during the previous isAlive call may have
			// since terminated, therefore not having a stacktrace.
			if (stackTrace == null) {
				stackTrace = EMPTY_STACK_TRACE;
			}
			return stackTrace;
		} else {
			// Don't need JVM help for current thread
			return (new Exception()).getStackTrace();
		}
	}

在if语句里面因为   this != Thread.currentThread()是为true的,所以方法会执行else里面的语句

return (new Exception()).getStackTrace();

new Exception().getStackTrace();就是这句话让使用Thread的getStackTrace方法就有可能多打印一句java.lang.Thread;getStackTrace;Thread.java      

这也就是为什么使用

logger = LoggerFactory.getLogger(Thread.currentThread().getStackTrace()[1].getClassName());

会得不到正确的日志信息的原因了!

应该就是这样子了,为了验证我想的对不对,写了一个测试验证的例子,代码如下:

public class TestException {

	public static StackTraceElement[] getStackTrace() {
		return new Exception().getStackTrace();
	}
}
public class ThreadTest {

	public static void TestString(){
		StackTraceElement[] arr = TestException.getStackTrace();
		for(int i=0;i<=arr.length-1;i++){
			System.out.println(arr[i].getClassName()+";"+arr[i].getMethodName()+";"+arr[i].getFileName());
		}
	}
}
public class App 
{
    public static void main( String[] args )
    {
        ThreadTest.TestString();
    }
}

执行之后的结果是:

test.TestException;getStackTrace;TestException.java

test.ThreadTest;TestString;ThreadTest.java

test.App;main;App.java

解决办法很简单,

要么使用new Exception().getStackTrace()[1];

要么使用Thread.currentThread().getStackTrace()[2]。





`Throwable` 类是 Java 中用于表示程序运行时异常和错误的基本类。它是所有异常和错误的超类,包括 `Exception` 和 `Error`。`Throwable` 类提供了几个常用的方法,帮助开发者处理和跟踪这些异常: 1. **getMessage()**:返回当前异常或错误的消息描述。这个信息通常包含了发生异常的原因,如 "NullPointerException"。 2. **getStackTrace()**: 返回一个 `StackTraceElement[]` 对象数组,包含导致异常调用栈的所有详细信息。这对于调试非常有用。 3. **fillInStackTrace()**: 在某些情况下(如异常被重新抛出时),此方法会被自动调用以填充异常调用堆栈。虽然一般不需要手动调用,但了解其作用有助于理解异常流程。 4. **getCause()**: 如果存在嵌套的异常(如 `IOException` 可能是由 `FileNotFoundException` 引起的),此方法将返回引发当前异常的根本原因。 5. **printStackTrace()**: 当异常被捕获并打印时,会调用此方法显示异常堆栈追踪,这有助于定位问题发生的代码位置。 6. **toString()**: 返回一个字符串形式的异常描述,包含类名、消息以及堆栈追踪的简略版本。 7. **equals(Object obj)** 和 **hashCode()**: 这两个方法分别用于比较两个异常是否相同,以及为哈希表提供键值。 了解这些方法对于异常处理至关重要,它们可以帮助开发者有效地捕获、记录和报告错误。如果你计划创建自定义异常,也可能重写这些方法以提供更详细的上下文信息
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值