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

时间:2017-02-02 20:18:55

标签: java

我遇到了一个问题,我必须覆盖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 }

我不关心方法的结束内容。只要它编译我很好。我只需要修复标题,但我无法找到修复它的方法。 非常感谢你提前。

6 个答案:

答案 0 :(得分:2)

首先,从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.RuntimeException派生)中包装已检查的异常(从java.lang.Exception派生)。无需添加throws子句。

答案 1 :(得分:0)

从例外情况来看,我认为这是可能引发的违规行?:

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 "";
}

此时该方法实际上不能抛出,因为任何异常都会导致只返回一个空字符串。所以标题不应该是列出的异常类型。

作为个人喜好的问题,我建议在遇到某事时将其除外。至少将其记录在某个地方,即使是作为调试日志,也不一定是错误。从长远来看,对所有可能的例外进行全面忽视并不是最好的想法。

答案 2 :(得分:0)

您可以将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){}
    return str.toString();
}

答案 3 :(得分:0)

如果您确实需要引发异常而又不用trycatch包围代码

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

答案 4 :(得分:0)

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

参考单一职责原则,toString()的单一职责是遍历对象的属性并填充它们。

如果您需要编写任何业务逻辑,则应将其隔离在其他方法中。如果需要从toString()引发异常和经过特殊检查的异常,则需要考虑重构代码。

如果要重写toString(),则无法从它引发抛出Checked异常。 创建一个引发该异常的方法,并从toString()调用该方法,并捕获该异常并将其包装在未经检查的异常中,

throw new IllegalStateException()throw new RuntimeException()

答案 5 :(得分:0)

因此,RuntimeException有一个用途。运行时异常要么是致命错误(无法使用户继续),要么是非常频繁的操作,例如Arithmetic operation或说equalshashcode。 考虑一下hashcode开始引发名为HashCalculationException的异常的情况。它将对HashMap的用户产生什么影响,他们每次在get上调用putMap时都必须捕获异常。 而且,JDK随附的这些功能的实现是异常证明,以便维护与其他JDK组件的完整性,并且JDK希望开发人员能够保持相同。 这是您第一个问题的答案。

现在,您是否应该抛出未经检查的异常? 这是我的看法。按照指南,使用toString对Java对象本身进行序列化是一个坏主意。 toString应该由记录器或任何其他单向处理程序使用,在这种情况下,您打印的内容与完整性没有任何区别。 想象一下,您开始使用toString生成的输出而不是序列化,并编写了自己的方法来从中创建新对象。您的对象正在保存大量数据。并且您进入了一种情况,您的呼叫者不小心开始在日志中打印该对象...想象一下它将执行的String连接数量,而性能却受到打击。

所以我在这种情况下的建议是 摆脱toString(如果用于序列化)。这不是该方法的目的。 为此创建一个单独的方法。做到这一点相当容易,就像在方法签名中添加新的异常然后使用它一样。

您总是可以抛出Unchecked异常并在以后捕获它,但强烈建议不要这样做。这是失败的目的。 未经检查的异常是为了避免而不是捕获

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