使异常更具信息性

时间:2011-11-15 14:51:25

标签: java exception-handling clojure

有没有办法让Java Exceptions更具信息性?

例如,从ClassCastException docs:

中获取此代码
Object x = new Integer(0);
System.out.println((String)x);

Java会给我一个ClassCastException,其中包含“无法将Integer类型转换为String”的消息。我怎么能说:“不能将整数 0 强制转换为字符串”? 如果我试图将一个字符串“foo”强制转换为Person,那么就说:“不能将String foo 强制转换为Person”?因此,我试图投射的物体的价值。

我能以某种方式用更有用的信息替换标准的ClassCastException,所以我不必介绍很多try / catch-blocks?子类化当然是一种选择,但是我必须引入大量的try / catch-blocks。

我问的原因实际上是因为另一种编译语言编译成了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编译器的情况下为学习环境注入这些新的Exceptions会很高兴。它可以通过捕获这些类型的异常来解决REPL级别。如果可以通过一些漂亮的技术,我仍然很好奇。

8 个答案:

答案 0 :(得分:6)

这个问题在最新的Clojure Conj中讨论过,并且通常被认为是在编译器中可以使用的东西。事实上,为了改善堆栈痕迹,你可以做很多事情,但请放心,你并不是唯一一个寻求改善这一点的人。

编译器很有可能使解析树可用于构建工具,以使人们能够创建能够解释堆栈跟踪并打印更有意义的消息的工具,尽管这些事情需要时间。

答案 1 :(得分:4)

你的问题没有意义。也许给出一个更好的例子。与您尝试做的远程类似的唯一事情是使用面向方面的编程框架(例如AspectJ)拦截异常。您可以将一个例外替换为另一个例外,但可能无法让您实际访问未能在示例中投射的对象。

答案 2 :(得分:3)

在编辑问题之前输入了这个答案,并提到了Clojure。

使用自定义静态方法将其转换为类似CastUtil.castString()的字符串。在此方法中,您可以在尝试强制转换之前检查类型,并抛出包含值的信息性异常。

为了更容易使用这种新方法,您还可以使用import static:

import static myutil.CastUtil.*;

然后在您的代码中,您可以编写castString(someObject)

答案 3 :(得分:2)

您可以使用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");
}

答案 4 :(得分:2)

Clojure中有两个名为clojure.stacktraceclj-stacktrace的框架,它们用于增强打印堆栈跟踪时看到的消息。看看下面的例子。

这是clojure repl中的正常堆栈跟踪:

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)

答案 5 :(得分:2)

除非您使用自定义JVM,否则不能。

当在运行时发生类转换时,JVM负责实例化ClassCastException,填写其消息并抛出它。在HotSpot中,消息构造部分是用C ++实现的;请参阅sharedRuntime.cpp第1479行中的方法generate_class_cast_message(这是OpenJDK 6;代码在JDK 7中稍作重组,但原理保持不变)。

答案 6 :(得分:1)

抓住它并随信息再次抛出。

try {

} catch(ClassCastException ex) {
    throw new ClassCastException("Your own message here!");
}

答案 7 :(得分:0)

可以修改Clojure以生成代码,该代码在尝试执行强制转换之前检查此条件,然后为您提供更多信息。