最近我在GitHub上看到了以下代码:
private static String safeToString(Object obj) {
if (obj == null) return null;
try {
return obj.toString();
} catch (Throwable t) {
return "Error occured";
}
}
我从未在toString()
块中放置过try-catch
方法调用。但是现在,当我考虑它时,这可能是有道理的。例如,有人可能会在类中覆盖toString()
方法,而该方法可能会抛出运行时异常,例如NullPointerException
。因此,我们可以尝试捕获Exception
。但是为什么Throwable
呢?您认为这有意义吗?
答案 0 :(得分:2)
几乎没有充分的理由这样做。 contract of toString()并未表示允许从该方法引发异常。任何引发异常的代码都是残破的代码,这种异常需要公开和修复,而不是抑制。
在将某些“不良”对象从您无法控制的库转换为字符串的情况下,写catch (RuntimeExcepton e)
可能是适当的,但是这样的捕获应该伴随注释,详细说明为什么有必要,因为在通常情况下不需要。
撇开Rogue异常抛出toString方法,请注意Java已经至少有两种“安全”方式将可能为null的值转换为String:
Objects.toString(obj, null)
String.valueOf(obj)
...所以我会质疑safeToString方法是否应该存在。
答案 1 :(得分:1)
Throwable
是Exception
和Error
的父类。
尝试捕获Error
通常是一个坏主意,因为它被设计为不会被捕获。
捕获Throwable
只是捕获Exception
的过度实现和适得其反的版本。尽管如此,如果出于某种原因您创建了另一种Throwable
并希望与Exception
一起使用,那可能是一次尝试/捕获的方法块。并不是说这样做是一种干净的方法,但是它会起作用。
编辑TL; DR:在大多数情况下,捕获Exception
而不是Throwable
。
答案 2 :(得分:1)
在极少数情况下,您可能想捕获这样的错误。一般来说,这是一个坏主意,在这种情况下,这可能是有道理的,因为这通常是出于日志记录/调试的目的,而不是由应用程序直接使用。
我希望提供更多信息,例如
private static String safeToString(Object obj) {
if (obj == null) return null;
try {
return obj.toString();
} catch (Throwable t) {
return obj.getClass() + ".toString() threw " + t;
}
}
例如
class Element {
Object data;
Element e;
public String toString() {
return data + (e == null ? "" : e.toString());
}
}
Element e = new Element();
e.data = "hi";
e.e = e; // oops
System.out.println("e: " + safeToString(e)); // doesn't kill the thread or JVM.
答案 3 :(得分:0)
捕获任何Throwable
然后继续执行是不正确的,因为它包含Error
,这注定是致命的:
来自Javadocs:
Error
是Throwable
的子类,表示合理的应用程序不应尝试捕获的严重问题。大多数此类错误是异常情况。尽管ThreadDeath
错误是“正常”情况,但它也是Error
的子类,因为大多数应用程序都不应尝试捕获它。
也就是说,一些 Error
可以恢复(例如LinkageError
),而其他恢复得不是很多。
但是捕获 Exception
可能是一个有效的用例,例如在记录代码中,您不希望仅仅因为对toString()
的调用失败而导致执行中断:
private static String safeToString(Object obj) {
try {
return obj == null ? "null" : obj.toString();
} catch (Exception e) {
return "<exception: " + e + ">";
}
}