1

I am trying to add throws clause to a toString method but the compiler says:

Exception IllegalAccessException is not compatible with throws clause in Object.toString()

Here is my code:

public class NF {

    private final Long id;
    private final String name;

    public static class Builder {
        private Long id = null;
        private String name = null;

        // setters of id and name

        public NF build() {
            return new NF(this);
        }
    }

    public NF(Builder b) {
        this.id = b.id;
        this.name = b.name;
    }

    public String toString() throws IllegalArgumentException, IllegalAccessException {
        Field[] fields = this.getClass().getDeclaredFields();
        String toString = "";
        for (Field f : fields) {
            String name = f.getName();
            Object value = f.get(this); // throws checked exceptions
            if (value != null)
                toString += name.toUpperCase() + ": " + value.toString() + "%n";
        }
        return String.format(toString);
    }

}

Why can't I add throws to toString?

  • 1
    Simply because the `Object` method doesn't throw one. Imagine that you have `Object o = new NF();`. How the compiler should know that `o.toString()` could throw an exception since the method declared doesn't ? – AxelH Jan 07 '18 at 13:07
  • 3
    Adding a checked exception to an overridden method breaks its contract. – Henry Jan 07 '18 at 13:09
  • If I'm not mistaken, `toString()` is rather a debugging aid to provide a way to quickly inspect an object's content. As such, it should not change program flow in any significant way, which is the reason why it must not throw. – Ulrich Eckhardt Jan 07 '18 at 13:09
  • You can't add new checked exception when you are overriding method. Lets say we have `Parent p = new Child();`. If we could add new exceptions to lets say `someMethod` then when invoking `p.someMethod()` compiler will make us catch and handle *only* exceptions declared in Parent class to be thrown, but this way we can skip potential exceptions added in Child class so it would be big security flaw. – Pshemo Jan 07 '18 at 13:10
  • Overridden methods can throw Exceptions, so long as the method being overridden also throws the same Exceptions. You can't introduce new Exceptions. This is based on Liskov substitution principle (see-https://en.wikipedia.org/wiki/Liskov_substitution_principle) – Nithin Jan 07 '18 at 13:23

1 Answers1

3

When you override a method, you can't throw checked exceptions that are not sub-classes of exceptions that already appear in the throws clause of the overridden method. Otherwise you break the contract of the overridden method.

Since Object's toString doesn't throw any checked exceptions, any class that overrides toString() can't throw checked exceptions in that method. You must catch these exceptions internally.

Note that IllegalArgumentException is a RuntimeException exception, so you can still throw it (you don't have to specify it in a throws clause).

On the other hand, IllegalAccessException is a checked exception, so you must handle it internally.

public String toString() {
    Field[] fields = this.getClass().getDeclaredFields();
    String toString = "";
    for (Field f : fields) {
        try {
            String name = f.getName();
            Object value = f.get(this);
            if (value != null)
                toString += name.toUpperCase() + ": " + value.toString() + "%n";
        }
        catch (IllegalAccessException ex) {
            // either ignore the exception, or add something to the output
            // String to indicate an exception was caught
        }
    }
    return String.format(toString);
}
Eran
  • 387,369
  • 54
  • 702
  • 768