【问题标题】:Java - overriding Object's toString() method, but I have to throw exceptionsJava - 覆盖对象的 toString() 方法,但我必须抛出异常
【发布时间】:2019-11-18 19:04:39
【问题描述】:

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

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

【问题讨论】:

  • 看起来你已经用那个空的catch块抑制了异常,不是吗?为什么他们不得不toString()抛出?
  • 我试图用那个空的 catch 块来压制它们,但它不起作用。如果我删除它,我最终不得不抛出 EmptyList 和 InvalidPosition 异常。
  • 看起来fList.first() 抛出了该异常,但它不是try/catch 块的一部分...为什么?
  • 您应该发布您说您使用的generic code,并提供有关您在那里抛出的异常的一些详细信息。他们是检查/未检查的异常吗?

标签: java


【解决方案1】:

首先,从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 子句。

【讨论】:

  • 在 toString() 中,您建议在 catch 子句中吞下异常并返回错误字符串。这只会隐藏异常并让代码继续。以后很难弄清楚你的代码为什么会失败。
  • 我对这里的答案有一些疑问stackoverflow.com/questions/58807130/…
【解决方案2】:

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

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

此时该方法确实不应该抛出,因为任何异常都会导致简单地返回一个空字符串。所以标题不应该需要列出的异常类型。

根据个人喜好,我建议做一些事情,但被捕获时除外。至少在某处记录它,即使是调试日志,也不一定是错误。从长远来看,对所有可能的例外情况一概忽略通常不是最好的主意。

【讨论】:

  • 我尝试了这些方法,但它们似乎不起作用。不过还是感谢您的建议!
  • @JRoge:你能详细说明你尝试了什么以及它是如何失败的吗? “我试过”和“似乎不起作用”对问题的描述不是很有帮助。
  • 我尝试将 if(fList.first() == null) 抛出异常,并将其余部分放入 ELSE 块中,但没有成功。我尝试了另一种方法,使用 try and catch 语句,就像您的第二个建议一样,它奏效了。非常感谢您的宝贵时间!
  • 好吧,如果fList.first() 可能引发异常,而您在try 之外调用它,那么可能会引发异常。这正是我们要解决的问题。
【解决方案3】:

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

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

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

如果您覆盖它,则无法从 toString() 抛出已检查的异常。 创建一个抛出该异常的方法并从 toString() 调用该方法并捕获该异常并将其包装在未经检查的异常中,

throw new IllegalStateException()throw new RuntimeException().

【讨论】:

    【解决方案4】:

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

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

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

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

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

    【讨论】:

      【解决方案5】:

      如果您确实需要在不使用 trycatch 包围代码的情况下引发异常

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

      【讨论】:

        【解决方案6】:

        您可以将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();
        }
        

        编辑:记录异常。

        【讨论】:

        • 谢谢!我尝试过类似的方法,它奏效了。感谢您的意见!
        • 它可以帮助解决问题,但是:一般来说,捕获异常并吞下它并不是一个好主意。至少,记录一下!
        猜你喜欢
        • 2014-09-16
        • 2010-10-15
        • 1970-01-01
        • 1970-01-01
        • 2018-01-10
        • 1970-01-01
        • 2023-03-21
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多