Как отобразить только ошибку, а не трассировку стека вызовов? - PullRequest
0 голосов
/ 27 апреля 2019

Я проектирую простой игрушечный интерпретатор, и у меня есть свое собственное исключение, например, так:

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.

Как мне это сделать?

Ответы [ 2 ]

2 голосов
/ 27 апреля 2019

Краткий ответ: перехватить исключение и распечатать сообщение поле . Вы можете сделать это в блоке trycatch в функции верхнего уровня или (лучше) в UncaughtExceptionHandler .

Длинный скучный ответ:

Исключение будет передаваться из каждой функции вызывающей стороне до тех пор, пока оно не найдет ее с включающим блоком trycatch.

Таким образом, один из подходов состоит в том, чтобы поймать исключение самостоятельно, например:

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

Если вы используете каркас журналирования, вы можете использовать его вместо этого, конечно.

Если нет вложенного trycatch, он будет вызывать UncaughtExceptionHandler - или, если у потока его нет, его ThreadGroup или, если это не так, значение по умолчанию .

Если вы не укажете значение по умолчанию, системный вызовет метод printStackTrace () , который печатает сообщение об исключении и всю его обратную трассировку в стандартный поток ошибок - вот почему вы видите след показан в вопросе.

Таким образом, другой подход заключается в установке UncaughtExceptionHandler на одном из этих уровней, например ::

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

Это намного безопаснее, потому что это работает для всех потоков.

Если вы пишете простое приложение, которое использует только один поток, то может быть просто поймать исключение в вашем методе верхнего уровня. Но если вы пишете что-то, что использует GUI-инструментарий или веб-фреймворк, или использует сопрограммы или другую фреймворк, или запускаете какие-либо потоки вручную, то, вероятно, будут запущены другие потоки. Это имеет два эффекта:

  • Во-первых, у вас не будет доступа к методам верхнего уровня этих потоков, и вы не сможете перехватывать там исключения. Так что UncaughtExceptionHandler является единственным способом. (По умолчанию он самый безопасный, поскольку у вас, вероятно, не будет доступа ни к темам, ни к группам нитей.)

  • Во-вторых, хотя поток с исключением прекратит работу, другие потоки не будут. Таким образом, JVM не будет закрыта, и другие потоки будут продолжать работать, не подозревая. Это оставляет ваше приложение в несовместимом состоянии, что может иметь катастрофические последствия: вы можете получить задания, стоящие в очереди, но никогда не запускающиеся, или другие потоки, останавливающие ожидание данных, или запросы, оставшиеся без ответа, или вообще что-нибудь, в зависимости от состояния вашего приложения. структурированный и какой поток умер. А поскольку JVM продолжается, мониторы системного уровня или менеджеры служб не будут знать, что в этом нет ничего плохого.

Так что после регистрации исключения, в некоторых случаях для вашего обработчика может быть очень хорошей идеей завершить работу всего приложения.

(Кстати, третий подход заключается в использовании пользовательского Exception и переопределении его printStackTrace() метода для печати только сообщения. Но это не очень хорошая идея; он отрицает намерение этого метода, которое может вызвать все виды проблем для всего, что его использует.)

0 голосов
/ 27 апреля 2019

Используйте 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()); 
}
...