Why is throws part of the method signature
Asked Answered
W

3

10

Why throws, on a method, is part of its signature? It seems strange to include it. Here is an example where it is in the way:

@Overide
public void foo() {
    throw new UnsupportedOperationException();
}

If anyone were to see this method from the outside, they might try to use it without knowing that it is not supported. They would only learn it on trying to run the code.

However, if they could do something like this they would know by looking at the method that it is not supported and if UnsupportedOperationException was not extending RuntimeException, they would get a compilation error. EDIT1: But this is not possible because throws is part of the signature so override will not work.

@Overide
public void foo() throws UnsupportedOperationException {
    throw new UnsupportedOperationException();
}

This question concerns Java's design, so I know that it might be hard to answer without one of the people that work on it drops by and answers it, but I was hoping that maybe this question has been asked to them before or that there might be an obvious reason to have it this way to explain why.

Wurster answered 7/10, 2015 at 11:34 Comment(6)
You seem to be answering your own question here? It's on the signature because now you (and the compiler) know the code will throw the exception and that it needs to be handled?Pagan
Unchecked exceptions and the conditions when they're thrown should be documented in javadoc. This paradigm is used in built-in Java libraries and is suggested by multiple books, e.g. Effective Java to name one. Declaring them in the signature is, as you correctly noted, not required by the compiler.Echinoid
What you are questioning is whether to throws an unchecked exception or not. For starts your method use the @Override which indicates that it should follow the contract (abstract or interface) but for unchecked exceptions you are not obligated to do so. Whether you chose to throw it or not always follow the good pratice as @danstahr mentioned, add it on the javadoc.Fenland
Unchecked exceptions are typically used for problems that can happen almost everywhere. Think of NullPointerException or ArrayIndexOutOfBoundsException. I would not want to include them in each and every method signature.Mayle
About declaring RuntimeExceptions being thrown also see #8396829Unknown
side note: method signature contains method name + list of parameters. so it is better to say: Why is throws part of the method declarationWinnah
T
9

The throws part does not indicate that the method is required to throw the mentioned exception(s), not even at particular occasions. It only tells that the function is allowed to do so.

Including throws UnsupportedOperationException will consequently not mean that the method is unsupported. Besides the UnsupportedOperationException is a RuntimeException so a method may throw that anyway.

Now for the reason one would require it in the signature of the method, it boils down to the ability to have checked exceptions at all. For the compiler to be able to decide if a method can only throw the specified exceptions it must be able to decide that the methods that it calls can't throw uncaught exceptions.

This means for example that overriding a method means that you can't add exceptions that might be thrown, otherwise you would break the possibility to verify that a method that calls that method can't throw anything else than it has specified. The other way around would be possible (but I'm not sure if Java supports that), overriding a method that may throw with one that may not throw.

So for example:

class B {
    int fubar(int) throws ExceptionA {
    }

    int frob(int) throws ExceptionA {
         return fubar(int);
    }
}

class D extends B {
    int fubar(int) throws ExceptionB {
    }
}
    

Now frob is specified to possibly throw only ExceptionA, but in calling this.fubar it would open the possibility that something else is thrown, but fubar is defined to possibly only throw ExceptionA. That's why the D.fubar is an invalid override since that would open up the possibility that this.fubar actually throws ExceptionB and the compiler wouldn't be able to guarantee that frob doesn't throw ExceptionB.

Theotokos answered 7/10, 2015 at 12:8 Comment(0)
B
2

Java has two different types of exceptions: checked Exceptions and unchecked Exceptions.

Unchecked exceptions are subclasses of RuntimeException and you don't have to add a throws declaration. All other exceptions have to be handled in the method body, either with a try/catch statement or with a throws declaration.

Example for unchecked exceptions: IllegalArgumentException that is used sometimes to notify, that a method has been called with illegal arguments. No throws needed.

Example for checked exceptions: IOException that some methods from the java.io package might throw. Either use a try/catch or add throws IOException to the method declaration and delegate exception handling to the method caller.

Bibcock answered 15/1, 2017 at 20:46 Comment(0)
T
2

One thing which no one has mentioned is a very important answer to your question:

Why throws, on a method, is part of its signature?

that throws, is NOT part of the method signature.

JLS 8.4.2. Method Signature makes it quite clear, that:

Two methods or constructors, M and N, have the same signature if they have the same name, the same type parameters (if any) (§8.4.4), and, after adapting the formal parameter types of N to the type parameters of M, the same formal parameter types.


If anyone were to see this method from the outside, they might try to use it without knowing that it is not supported.

That's exactly the main reason, why throws is designed in a way to be checked at compile-time for all Checked Exceptions - clients of the method will be aware what this method may possibly throw.


Checked Exceptions are enforced to be either handled or specified to be thrown (but this specification is NOT part of the method signature).

Unchecked Exceptions do not have to be either handled or specified to be thrown, and Oracle's tutorial are good at explaining - why:

Runtime exceptions represent problems that are the result of a programming problem, and as such, the API client code cannot reasonably be expected to recover from them or to handle them in any way. Such problems include arithmetic exceptions, such as dividing by zero; pointer exceptions, such as trying to access an object through a null reference; and indexing exceptions, such as attempting to access an array element through an index that is too large or too small.

Tripos answered 17/11, 2021 at 16:40 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.