Java - 覆盖对象的 toString() 方法,但我必须抛出异常



我遇到了一个问题,我必须重写Object的toString()方法,但原始方法没有抛出任何异常。然而,我使用的是一些需要抛出异常的泛型代码。

public String toString() throws EmptyListException, InvalidPositionException
{
Position<Entry<E>> current = fList.first();
StringBuilder str = new StringBuilder();
for(int i = 0; i < size(); i++)
{
try
{
str.insert(str.length(), current.element().toString() + " ");
current = fList.next(current);
}
catch(Exception e){}
}
return str.toString();
}

这是FavoriteList.java的一部分。必须抛出这些异常。如果有任何方法可以以某种方式抑制这些异常或在方法中捕获它们,那将是有帮助的。

最后,我的方法头必须看起来像这样:

public String toString()
{ content }

我不在乎这个方法的结尾内容。只要它编译,我就没事。我只需要修复头部,但我找不到修复它的方法。事先非常感谢。

首先,从toString()抛出异常是个非常糟糕的主意。toString()在许多系统软件(例如调试器)中用于生成对象的表示。

第一个偏好是做其他事情,可能创建一个可能抛出的不同方法,并在toString()中调用该方法,捕获异常并产生替换输出,如

super().toString() + " threw " + exception.toString();

如果你觉得你真的必须投球,你可以这样做:

try
{
str.insert(str.length(), current.element().toString() + " ");
current = fList.next(current);
}
catch(Exception e){
throw new IllegalStateExcception(super.toString(), e);
}

这将一个已检查的异常(派生自java.lang.exception)包装在一个未检查的异常中(派生自java.lang.RuntimeException)。无需添加throws子句。

根据异常判断,我认为这是可能抛出的违规行:

Position<Entry<E>> current = fList.first();

如果是这种情况,您可以处理该异常。我不知道fList到底是什么,我对Java也不够熟悉,不知道编译器是否足够聪明,知道你已经检查过了,但从逻辑上讲,如果fList可能是空的,那么我会首先检查:

if (/* check for an empty or null fList */) {
return "";
}
// the rest of your code

如果编译器仍然不喜欢这样,那么您可以使用与另一个try/catch几乎相同的方法。类似于:

try {
// the rest of your code
} catch (Exception e) {
return "";
}

在这一点上,该方法真的不应该抛出,因为任何异常都会导致返回一个空字符串。因此,标头不应该需要列出异常类型。

根据个人喜好,我建议做的事情,除非它被捕获。至少把它记录在某个地方,即使是调试日志,也不一定是错误。从长远来看,完全忽略所有可能的例外情况往往不是最好的想法。

jdk不从toString()抛出CheckedException是有原因的。此方法在运行时用于填充对象。他们不希望在这种方法中实现任何这样的代码或业务逻辑,因为这种方法可能会引发异常。无论是否检查。

参考单一责任原则,toString()的单一责任是迭代对象的属性并填充它们。

若您需要编写任何业务逻辑,那个么它应该在其他方法中隔离。如果您需要从toString()抛出异常和经过特殊检查的异常,那么您需要考虑重构代码。

如果您正在重写被检查的异常,则不能从toString()中抛出该异常。创建一个抛出该异常的方法,并从toString()调用该方法,捕获该异常并将其包装在未检查的异常中

throw new IllegalStateException()throw new RuntimeException()

所以,RuntimeException是有目的的。运行时异常要么是无法让用户继续的致命错误,要么是非常频繁的操作,如Arithmetic operationequalshashcode。假设hashcode开始抛出一个名为HashCalculationException的异常。它会对HashMap的用户产生什么影响,每次他们在Map上调用getput时,都必须捕获一个异常。此外,JDK提供的这些功能的实现是防异常的,以保持与其他JDK组件的完整性,JDK希望开发人员保持相同。你的第一个问题的答案来了。

现在,你应该抛出一个未检查的异常吗?这是我的看法。根据指导原则,使用toString序列化Java对象本身是个坏主意。toString应该由记录器或任何其他单向处理程序使用,在这些单向处理程序中,打印的内容与完整性没有任何区别。想象一下,您开始使用toString生成的输出而不是序列化,并编写了自己的方法来创建一个新的对象。您的对象包含大量数据。而您进入的情况是,您的调用者意外地开始在日志中打印对象。。。想象一下它将要进行的字符串串联数量,以及您获得的性能打击。

因此,在这种情况下,我的建议是如果toString用于序列化,请将其删除。这不是那种方法的目的为相同的创建一个单独的方法。这样做相当容易,就像在方法签名中添加一个新的异常,然后使用它一样

您总是可以抛出Unchecked异常,然后再捕获它,但强烈建议不要这样做。失败就是目的未选中的异常是为了避免,而不是捕获

更多参考,请阅读我们关于RuntimeException的讨论-https://stackoverflow.com/a/58455577/4675277

如果您真的需要在不使用trycatch包围代码的情况下抛出异常

@override
public String toString(){
if(...)throw new IllegalStateException("list is empty");
else if(...)throw new IllegalStateException("position is invalid"); 
return ...;
}

您可以将try块放在for循环之外。为了捕获fList.first()中抛出的异常。

public String toString() throws EmptyListException, InvalidPositionException
{
try
{
Position<Entry<E>> current = fList.first();
StringBuilder str = new StringBuilder();
for(int i = 0; i < size(); i++)
{
str.insert(str.length(), current.element().toString() + " ");
current = fList.next(current);
}
}
catch(Exception e){
e.printStackTrace()
}
return str.toString();
}

编辑:记录异常。

最新更新