8

I have run into an issue where I have to override Object's toString() method, but the original method doesn't throw any exceptions. 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. 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.

JRoge
  • 101
  • 1
  • 7
  • 5
    It looks like you're already suppressing exceptions with that empty catch block, aren't you? Why do they *have* to be thrown by `toString()`? – David Feb 02 '17 at 20:20
  • I tried to suppress them with that empty catch block, but it doesnt work. If i remove it, I just end up with having to throw the EmptyList and InvalidPosition exceptions. – JRoge Feb 02 '17 at 20:24
  • 1
    Looks like `fList.first()` throws that exception, but it isn't part of the `try/catch` block ... why? – Tom Feb 02 '17 at 20:29
  • you should post your `generic code` that you say you use and also give some details about the exceptions you throw there. are they checked/unchecked exception? – Daniel Puiu Feb 02 '17 at 20:30
  • http://stackoverflow.com/questions/28972893/what-is-exception-wrapping-in-java –  Feb 02 '17 at 20:32
  • Possible duplicate of [What is exception wrapping in Java?](http://stackoverflow.com/questions/28972893/what-is-exception-wrapping-in-java) –  Feb 02 '17 at 20:49

6 Answers6

15

First, throwing exceptions from toString() is a really bad idea. toString() is used in a lot of system software (e.g. debugger) to generate the representation of the object.

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

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). No need to add a throws clause.

  • In toString(), you suggested to swallow exceptions in catch clause and return an error string. That will just hide the exception and let the code continue. It will be hard to figure out why your code failed later. – Erran Morad Nov 11 '19 at 18:49
  • I have some questions about this answer over here https://stackoverflow.com/questions/58807130/throwing-exception-from-tostring-method – Erran Morad Nov 11 '19 at 18:57
2

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:

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. 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.

David
  • 208,112
  • 36
  • 198
  • 279
  • I tried these approaches, but they don't seem to work. Thank you for your suggestions though! – JRoge Feb 02 '17 at 20:34
  • @JRoge: Can you elaborate on what you tried and how it failed? "I tried" and "don't seem to work" aren't very helpful descriptions of the problem. – David Feb 02 '17 at 20:35
  • I tried to put an if(fList.first() == null) throw an exception, and the rest into the ELSE block, but it didn't work. I tried another approach with a try and catch statement much like your second suggestion and it worked. Thank you very much for your time! – JRoge Feb 02 '17 at 20:41
  • Well, if `fList.first()` might throw an exception, and you're calling it outside of a `try`, then an exception might be thrown. That's exactly the problem we were here to solve. – David Feb 02 '17 at 20:42
0

There is a reason jdk doesn't throws CheckedException from toString(). 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.

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.

Checked exception can't be thrown from toString() if you are overriding it. Create a method that throws that exception and invoke that method from toString() and catch that exception and wrap it in unchecked exception,

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

0

So, There is a purpose for 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. Consider a case if hashcode started throwing an exception called 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. 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. 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 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. Imagine you started using output generated by toString instead of serialization, and wrote your own method for create a new object out of it. 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. 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. 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

Anand Vaidya
  • 1,374
  • 11
  • 26
-1

If you really need to throw an exception without surrounding your code with a try and catch

@override
public String toString(){
     if(...)throw new IllegalStateException("list is empty");
     else if(...)throw new IllegalStateException("position is invalid"); 
     return ...;
}
linker
  • 821
  • 1
  • 8
  • 20
-2

You can put your try block outside the for loop. On order to catch the exception thrown in 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.

alayor
  • 4,537
  • 6
  • 27
  • 47
  • Thank you! I've tried a similar approach and it worked. Your input is appreciated! – JRoge Feb 02 '17 at 20:43
  • It could help to solve the problem, but: generally speaking, it's not a good idea to just catch the exception and swallow it. At least, log it! – Janos Vinceller Nov 14 '19 at 17:21