Why do we have to write it like so? Is creating an exception instance more expensive than creating a supplier instance?
var value = getOptional().orElseThrow(NullPointerException::new);
// instead of
var value = getOptional().orElseThrow(new NullPointerException());
.orElseThrow(NullPointerException::new)
is equivalent to () -> new NullPointerException()
.
That's a function which will only be invoked if the Optional is empty
public <X extends Throwable> T orElseThrow(Supplier<? extends X> exceptionSupplier) throws X {
if (value != null) {
return value;
} else {
throw exceptionSupplier.get(); // Only invoke on this path
}
}
The reason that's preferable to .orElseThrow(new NullPointerException())
is because of performance. When you pass a function, you are only create an exception on-demand, if you really need to throw it.
Creating most exceptions is expensive*, relatively speaking. The constructor will almost always create a stacktrace, and constructing the stacktrace is relatively slow*. Gathering the stacktrace is done within Throwable
's constructor.
public Throwable() {
fillInStackTrace();
}
There is a variant constructor which won't gather the stacktrace, but it's very rarely used.
They could have provided a second signature to allow people to choose between them, but it's likely that the signature you suggested would be frequently misused, resulting in worse performance.
* 'Expensive' and 'slow' are relative terms. Modern CPUs are fast. While it may be significantly slower than most normal operations, it's generally not going to be a bottleneck on most applications or anything like that.