简体   繁体   English

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

[英]Java - overriding Object's toString() method, but I have to throw exceptions

I have run into an issue where I have to override Object's toString() method, but the original method doesn't throw any exceptions.我遇到了一个问题,我必须覆盖 Object 的 toString() 方法,但原始方法不会引发任何异常。 However, I am using some generic code that requires exceptions to be thrown.但是,我正在使用一些需要抛出异常的通用代码。

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();
}

This is part of FavoriteList.java.这是FavoriteList.java 的一部分。 These exceptions HAVE to be thrown.必须抛出这些异常。 If there is any way to somehow suppress these exceptions or catch them inside the method, that would be helpful.如果有任何方法可以以某种方式抑制这些异常或在方法中捕获它们,那将很有帮助。

In the end, my method header has to look like this:最后,我的方法标题必须如下所示:

public String toString()
{ content }

I don't care about the ending content of the method.我不在乎方法的结束内容。 As long as it compiles I am fine.只要它编译我就很好。 I just need to fix the header, but I can't find a way to fix it.我只需要修复标题,但我找不到修复它的方法。 Thank you very much in advance.非常感谢您提前。

First, throwing exceptions from toString() is a really bad idea.首先,从toString()抛出异常是一个非常糟糕的主意。 toString() is used in a lot of system software (eg debugger) to generate the representation of the object. toString()用于很多系统软件(例如调试器)来生成对象的表示。

The first preference would be to do something else, maybe create a different method that may throw, and in toString() call that method, catch the exception and produce replacement output such as第一个优先选择是做其他事情,可能创建一个可能抛出的不同方法,并在toString()调用该方法,捕获异常并产生替换输出,例如

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

If you feel that you really must throw, you can do this:如果你觉得你真的必须扔,你可以这样做:

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

This wraps a checked exception (derived from java.lang.Exception) in an unchecked exception (derived from java.lang.RuntimeException).这将受检异常(派生自 java.lang.Exception)包装在未经检查的异常(派生自 java.lang.RuntimeException)中。 No need to add a throws clause.无需添加throws子句。

Judging by the exceptions, I take it this is the offending line which might throw?:从例外情况来看,我认为这是可能抛出的违规行?:

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

If that's the case, you can handle that exception.如果是这种情况,您可以处理该异常。 I don't know precisely what fList is and I'm not familiar enough with Java to know if the compiler will be smart enough to know you've checked for it, but logically if the fList could be empty then I would check for that first:fList地知道fList是什么,我对 Java 不够熟悉,无法知道编译器是否足够聪明以知道您已经检查过它,但从逻辑fList ,如果fList可能为空,那么我会检查它第一的:

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

If the compiler still doesn't like that, you can take the pretty much the same approach with another try/catch.如果编译器仍然不喜欢那样,您可以对另一个 try/catch 采取几乎相同的方法。 Something like:就像是:

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

At that point the method really shouldn't be able to throw, since any exception would result in simply returning an empty string.那时该方法真的不应该抛出,因为任何异常都会导致简单地返回一个空字符串。 So the header shouldn't need the exception types listed.所以标题应该不需要列出的异常类型。

As a matter of personal preference I would recommend doing something with the exception when it's caught.根据个人喜好,我建议在被捕获时做一些例外的事情 At least logging it somewhere, even as a debug log and not necessarily an error.至少在某处记录它,即使是调试日志,也不一定是错误。 A blanket ignore on all possible exceptions isn't often the best of ideas in the long run.从长远来看,全面忽略所有可能的例外通常不是最好的想法。

There is a reason jdk doesn't throws CheckedException from toString(). jdk 不会从 toString() 中抛出 CheckedException 是有原因的。 This method is used at runtime, to populate the object.此方法在运行时用于填充对象。 They doesn't wanted any such code or business logic to be implemented in this method which can throw exception.他们不希望在此方法中实现任何此类可能引发异常的代码或业务逻辑。 No matter checked or unchecked.无论选中或未选中。

Referring to Single Responsibility Principle, toString() single responsibility is to iterate over object's attribute and populate them.参考单一职责原则, toString() 单一职责是迭代对象的属性并填充它们。

If any business logic you need to write then, it should be segregated in other method.如果您需要编写任何业务逻辑,则应将其隔离在其他方法中。 If you are needing to throw exception and specially checked exception from toString(), then you need to consider refactoring your code.如果您需要从 toString() 抛出异常和特别检查的异常,那么您需要考虑重构您的代码。

Checked exception can't be thrown from toString() if you are overriding it.如果您要覆盖它,则不能从 toString() 抛出已检查的异常。 Create a method that throws that exception and invoke that method from toString() and catch that exception and wrap it in unchecked exception,创建一个抛出该异常的方法并从 toString() 调用该方法并捕获该异常并将其包装在未经检查的异常中,

throw new IllegalStateException() or throw new RuntimeException() . throw new IllegalStateException()throw new RuntimeException()

So, There is a purpose for RuntimeException .因此, RuntimeException是有目的的。 Runtime exceptions are either Fatal errors, which cannot let users to continue, or those are very frequent operations like Arithmetic operation or say equals or hashcode .运行时异常要么是致命错误,无法让用户继续,要么是非常频繁的操作,例如Arithmetic operation或者说equalshashcode Consider a case if hashcode started throwing an exception called HashCalculationException .考虑一种情况,如果hashcode开始抛出一个名为HashCalculationException的异常。 What will be the impact of it on the users of HashMap, every time they call get or put on Map they have to catch an exception.它对HashMap的用户有什么影响,每次在Map上调用getput都必须捕获一个异常。 Moreover, the implementations of these functions that are provided with JDK are exception proof, in order to maintain the integrity with other JDK components, and JDK expects developer to maintain the same.而且,JDK 提供的这些功能的实现都是异常证明的,以保持与其他 JDK 组件的完整性,并且 JDK 期望开发人员保持相同。 Here it comes the answer to your first question.这里是你的第一个问题的答案。

Now, Should you throw an unchecked exception?现在,你应该抛出一个未经检查的异常吗? This is my take on it.这是我的看法。 As per the guideline, using toString for serialization of a Java object itself a bad idea.根据指南,使用toString序列化 Java 对象本身是一个坏主意。 toString is supposed to be used by loggers, or any other one-way handlers, where what you print doesn't make any difference from the point of integrity. toString应该由记录器或任何其他单向处理程序使用,您打印的内容与完整性没有任何区别。 Imagine you started using output generated by toString instead of serialization, and wrote your own method for create a new object out of it.想象一下,您开始使用由toString生成的输出而不是序列化,并编写了自己的方法来从中创建一个新对象。 Your object is holding huge data.您的对象正在保存大量数据。 and you entered in a situation where your caller accidentally started printing the object in logs... Imagine the amount of String concatenations it would do, and performance hit you get.并且您进入了一种情况,您的调用者不小心开始在日志中打印对象......想象一下它会执行多少字符串连接,并且性能会受到影响。

So my suggestion in such scenario would be Get rid of toString if it's used to serialization.所以我在这种情况下的建议是去掉toString如果它用于序列化。 Its not the purpose of that method.它不是该方法的目的。 Create a separate method for the same.为其创建一个单独的方法。 Its fairly easy to do the same, just like adding a new exception in the method signature, and then use it.做同样的事情相当容易,就像在方法签名中添加一个新的异常,然后使用它一样。

You can always throw Unchecked exception and catch it later, but it's strongly discouraged.您始终可以抛出 Unchecked 异常并稍后捕获它,但强烈建议不要这样做。 it defeat's the purpose.它失败的目的。 Unchecked exceptions are meant for avoiding, not catching未经检查的异常是为了避免,而不是捕捉

More reference, please read our discussion about RuntimeException here - https://stackoverflow.com/a/58455577/4675277更多参考,请在此处阅读我们关于 RuntimeException 的讨论 - https://stackoverflow.com/a/58455577/4675277

Catch the exceptions EmptyListException, InvalidPositionException whith catch, and print de message in the console. 捕获异常EmptyListException,InvalidPositionException,并在控制台中输出消息。

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

     //here
     catch(EmptyListException, InvalidPositionException e){
       System.out.println(e.getMessage());}
    }
    return str.toString();
   }

The exception EmptyListException is by first(); EmptyListException异常是由first();引起的。 and InvalidPositionException by Position>; 和InvalidPositionException通过Position>; you have to catch the exception since you are a class client. 因为您是班级客户,所以必须捕获异常。

If you really need to throw an exception without surrounding your code with a try and catch如果你真的需要抛出异常而不用trycatch包围你的代码

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

You can put your try block outside the for loop.您可以将try块放在for循环之外。 On order to catch the exception thrown in fList.first() .为了捕获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();
}

Edit: logging the exception.编辑:记录异常。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM