JShell执行StackWalker代码返回空字符串是否为错误?为何未抛出异常?
这不属于错误,是JShell特殊执行环境导致的结果
首先可以明确:你遇到的情况不是JShell或JVM的bug,而是JShell交互式执行模型带来的特殊行为。
为什么会返回空字符串?
要理解这个问题,得先搞清楚JShell的代码执行逻辑和StackWalker.getCallerClass()的行为:
- JShell的执行模型:当你在JShell里输入代码片段,它会被动态编译成一个合成类(由JShell内部编译器生成),然后由JShell的执行引擎调用这个类的方法来执行你的代码。整个调用栈的顶层是JShell的内部执行代码,而非你写的代码本身。
StackWalker.getCallerClass()的限制:这个方法的作用是返回调用当前方法的类,但有两个关键限制:- 如果调用者是由bootstrap类加载器加载的JDK核心类,方法会返回
null; - 如果调用栈深度不足以找到有效的用户级调用者,也会返回
null。
- 如果调用者是由bootstrap类加载器加载的JDK核心类,方法会返回
在你的代码场景中:
当你调用get()方法时,实际的调用者是JShell的执行引擎代码(属于JDK核心类,由bootstrap类加载器加载),所以getCallerClass()返回null。按道理调用null.getName()应该抛出NullPointerException,但你得到了空字符串,这很可能是JShell为了适配交互式环境做了特殊处理——比如它捕获了潜在的空指针异常,默认返回空字符串;或者在JShell 13.0.1版本中,生成的合成类的getName()方法被特殊处理为空。
为什么你期望抛出异常是合理的?
在普通Java应用中执行这段代码,你会得到预期的结果或异常:
比如在一个普通类中执行:
public class TestStackWalker { public static void main(String[] args) { String result = ((Supplier<String>)() -> StackWalker.getInstance(StackWalker.Option.RETAIN_CLASS_REFERENCE) .getCallerClass().getName() ).get() + "invisible"; System.out.println(result); } }
这段代码会输出TestStackWalkerinvisible,因为getCallerClass()会正确返回TestStackWalker类。如果在调用栈更上层是核心类的场景下,才会抛出空指针异常。
而JShell的交互式环境打破了普通Java程序的调用栈结构,才导致了这种不符合你预期的结果。
内容的提问来源于stack exchange,提问作者jukzi
相关产品推荐
相关产品推荐

