All objects have a toString() implementation. Because java.lang.Object itself (and Exception extends Throwable, and Throwable extends Object - all things eventually extend object) has this.
The Throwable class overrides the implementation of it with:
@Override public String toString() {
String s = getClass().getName();
String message = getLocalizedMessage();
return (message != null) ? (s + ": " + message) : s;
}
and getLocalizedMessage() is implemented as:
public String getLocalizedMessage() {
return getMessage();
}
whenever you 'append' an object to a string (with X + Y, where the X expression has type String and Y is anything) is shorthand for X.concat(Y.toString()). Thus, you're calling toString there. You did not override it, so you get Throwable's implementation of it, which invokes getLocalizedMessage - which you also didn't override, so that calls getMessage(), hence, you get your text. Twice.
Some lessons:
- Do not
System.out anything in exception constructors. The exception goes someplace and if it needs printing, where-ever it ends up will print it. If an exception ends up 'ending' your static void main(String[]) method, java will print it for you.
- The message should not end in punctuation (and definitely not an exclamation mark - it's an exception. That something went wrong is assumed, no need to yell about it), and should not repeat or consist of the exception type. That information is already available; the message exists for additional information. If you have nothing to add, then don't have a message. An exception named
NegativeNumberException should probably have the actual number as message, or possibly the param name. Something like:
public class NegativeNumberException extends Exception {
public NegativeNumberException(String msg) {
super(msg);
}
}
and then in your test method:
if (n < 0) throw new NegativeNumberException("n: " + n);
Overriding getMessage and returning some string constant is almost never correct. Messages should rarely be constants, as they are meant for detailing the specifics of the problem, not for generally explaining what the exception represents (write some javadoc for that, and only if the name of the exception is not sufficient to figure it out, hence, nothing needed here).