Сделайте исключения более информативными - PullRequest
11 голосов
/ 15 ноября 2011

Есть ли способ сделать исключения Java более информативными?

Например, возьмите этот код из документации ClassCastException:

Object x = new Integer(0);
System.out.println((String)x);

Java даст мне исключение ClassCastException с сообщением типаMsgstr "Невозможно привести что-то типа Integer к строке".Как я могу заставить его сказать: «Не могу вместо этого привести Integer 0 к строке»?И если бы я попытался наложить Строку "foo" на Лица, чтобы он сказал: "Не могу привести Строку foo к Лицу"?Итак, со значением объекта, который я пытался привести.

Могу ли я как-то заменить стандартное ClassCastException на более информативное, , поэтому мне не нужно вводить много блоков try / catch?Подклассы - это, конечно, вариант, но тогда мне придется ввести много блоков try / catch.

Причина, по которой я спрашиваю, на самом деле из-за другого языка программирования, который компилируется в JVM, Clojure.

В Clojure новички часто допускают эту ошибку:

(def my-list ("foo" "bar"))

Это приводит к сообщению об ошибке:

java.lang.String cannot be cast to clojure.lang.IFn

Это было бы очень полезно для начинающихчтобы увидеть что-то вроде:

java.lang.String "foo" cannot be cast to clojure.lang.IFn

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

Было бы неплохо иметь возможность внедрить эти новые исключения в учебную среду, фактически не переписывая Clojure Compiler.Это может быть решено на уровне REPL путем перехвата этих исключений.Тем не менее мне любопытно, если это возможно с некоторыми изящными методами.

Ответы [ 8 ]

6 голосов
/ 16 ноября 2011

Эта проблема обсуждалась в последней версии Clojure Conj и обычно принимается за что-то для работы в компиляторе. По факту вы не можете многое сделать для улучшения трассировки стека, но будьте уверены, что вы не единственный, кто стремится улучшить это.

Существует большая вероятность того, что компилятор сделает дерево разбора доступным для инструментов сборки, чтобы позволить людям создавать инструменты, которые смогут интерпретировать трассировки стека и печатать более значимые сообщения, хотя эти вещи потребуют времени.

4 голосов
/ 15 ноября 2011

Ваш вопрос на самом деле не имеет смысла.Возможно, приведите лучший пример.Единственное, что удаленно похоже на то, что вы пытаетесь сделать, это перехват исключений с помощью Aspect-Oriented Programming Framework (например, AspectJ).Вы можете заменить одно исключение другим, но, вероятно, не дадите вам возможности фактически получить доступ к объекту, который не был приведен, как в вашем примере.

3 голосов
/ 15 ноября 2011

Этот ответ был напечатан до того, как вопрос был отредактирован, и Clojure был упомянут.

Создайте собственный статический метод для приведения к строке, такой как CastUtil.castString (). В этом методе вы можете проверить тип перед попыткой приведения и сгенерировать информативное исключение, содержащее значение.

Чтобы упростить использование этого нового метода, вы также можете использовать статический импорт, например:

import static myutil.CastUtil.*;

Тогда в своем коде вы можете написать castString(someObject)

2 голосов
/ 17 ноября 2011

Вы не можете, если не используете пользовательскую JVM.

Когда приведение класса происходит во время выполнения, JVM несет ответственность за создание экземпляра ClassCastException, заполнение его сообщения и его выдачу.В HotSpot часть создания сообщений реализована на C ++;см. метод generate_class_cast_message в sharedRuntime.cpp , строка 1479 (это OpenJDK 6; код был немного реорганизован в JDK 7, но принцип остается тем же).

2 голосов
/ 16 ноября 2011

В Clojure есть две платформы, называемые clojure.stacktrace и clj-stacktrace , они используются для улучшения сообщений, которые вы видите при печати трассировки стека.Посмотрите на приведенный ниже пример.

Вот обычная трассировка стека в ответе clojure:

user=> (java.util.Date. "foo")
java.lang.IllegalArgumentException (NO_SOURCE_FILE:0)

Улучшенная трассировка стека:

user=> (use 'clojure.stacktrace)
nil
user=> (print-stack-trace *e 5)
clojure.lang.Compiler$CompilerException: java.lang.IllegalArgumentException (NO_SOURCE_FILE:0)
 at clojure.lang.Compiler.eval (Compiler.java:4658)
    clojure.core/eval (core.clj:2035)
    clojure.main$repl__7403$read_eval_print__7415.invoke (main.clj:183)
    clojure.main$repl__7403.doInvoke (main.clj:200)
    clojure.lang.RestFn.invoke (RestFn.java:426)
2 голосов
/ 15 ноября 2011

Вы можете окружить свой блок кода с помощью try / catch:

Object x = new Integer(0);
try {
  System.out.println((String)x);
} catch (ClassCastException e) {
  throw new ClassCastException("Can't cast the Integer " + x + " to a String");
}
1 голос
/ 15 ноября 2011

Поймай и брось снова со своим сообщением.

try {

} catch(ClassCastException ex) {
    throw new ClassCastException("Your own message here!");
}
0 голосов
/ 15 ноября 2011

Clojure можно изменить, чтобы генерировать код, который проверяет это условие перед тем, как попытаться выполнить приведение, а затем выдает более информативное сообщение.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...