如何只显示错误而不显示调用堆栈跟踪?

How to display only the error and not the call stack trace?

我正在设计一个简单的玩具解释器,我有一个像这样的自定义异常:

class ValError(varName: String) : Exception("$varName is val, cannot reassign.")

问题是,当它被抛出时,它会像这样打印出整个调用堆栈跟踪:

ValError: foo is val, cannot reassign.
    at com.github.me.dynamik.interpreter.Environment.get(Environment.kt:62)
    at com.github.me.dynamik.interpreter.TreeWalker.visitVariableExpr(TreeWalker.kt:154)
    at com.github.me.dynamik.expressions.VariableExpr.evaluateBy(Expression.kt:57)

但我只希望它打印出第一行

ValError: foo is val, cannot reassign.

我该如何完成?

简短回答:捕获异常,并打印其 message field.  You can do this in a trycatch block in your top-level function, or (better) in an UncaughtExceptionHandler

无聊的回答:

一个异常将从每个函数传递给它的调用者,直到它找到一个包含 trycatch 块的异常。

所以一种方法是自己捕获异常,例如:

fun main() {
    try {
        // All your top-level code here…
    } catch (x: Exception) {
        System.err.println(x.message)
    }
}

如果您使用的是日志记录框架,当然可以使用它。

如果没有封闭的trycatch,它会调用线程的UncaughtExceptionHandler — or, if the thread doesn't have one, its ThreadGroup's one, or failing that, the default one.

如果您不提供默认的,系统会调用它的 printStackTrace() 方法,该方法将异常消息及其所有回溯打印到标准错误流——这就是为什么您会看到显示的跟踪在问题中。

所以另一种方法是在其中一个级别设置 UncaughtExceptionHandler,例如:

Thread.setDefaultUncaughtExceptionHandler { t, x ->
    System.err.println(x.message)
}

这样更安全,因为它适用于所有线程。

如果您正在编写一个仅使用单线程的简单应用程序,那么可以直接在顶级方法中捕获异常。但是,如果您正在编写使用 GUI 工具包或 Web 框架的东西,或者使用协程或其他执行框架,或者手动启动任何线程,那么很可能还有其他线程 运行ning。这有两个影响:

  • 首先,您将无权访问这些线程的顶级方法,因此您将无法在那里捕获异常。所以 UncaughtExceptionHandler 是唯一的方法。 (默认的是最安全的,因为您可能无法访问线程,甚至无法访问所涉及的线程组。)

  • 其次,虽然出现异常的线程会停止运行ning,但任何其他线程都不会。因此 JVM 不会关闭,其他线程将继续 运行ning,而不会察觉。这会使您的应用程序处于不一致状态,这可能是灾难性的:您最终可能会遇到作业排队但从未 运行,或其他线程停止等待数据,或请求未得到答复,或几乎任何事情都取决于您的应用程序的结构如何以及哪个线程死亡。而且由于 JVM 继续运行,系统级监视器或服务管理器不会知道有什么问题。

因此,在记录异常后,在某些情况下,您的处理程序关闭整个应用程序可能是个好主意。

(顺便说一句,第三种方法是使用自定义 Exception 并重写其 printStackTrace() 方法以仅打印消息。但这不是一个好主意;它违背了它的意图方法,这可能会导致使用它的任何东西出现各种问题。)

使用 try..catch

科特林

try {
  // perform tasks
    throw ValError("x")
} catch (e: ValError) {
    println(e.message)
}

Java

try{
    // perform task
    throw new ValError("x")
}
catch(ValError e){
     System.out.println(e.getMessage()); 
}