what's the differences between Supplier<X> and Supplier<? extends X>

559 views Asked by At

In "Optional" source code, I found this function:

public <X extends Throwable> T orElseThrow(Supplier<? extends X> exceptionSupplier) throws X {
    if (value != null) {
        return value;
    } else {
        throw exceptionSupplier.get();
    }
}

My question is if I change the function to this, it looks like working same

public <X extends Throwable> T orElseThrow(Supplier<X> exceptionSupplier) throws X {
    if (value != null) {
        return value;
    } else {
        throw exceptionSupplier.get();
    }
}

Anyone know the reason?

1

There are 1 answers

0
Andy Turner On BEST ANSWER

Consider this method:

void example() throws IOException {
  throw new FileNotFoundException();
}

This declares that it throws the general IOException, but concretely throws a more specific exception, FileNotFoundException.

Same with orElseThrow: by accepting an upper-bounded supplier, it can throw a more specific exception type.

The difference is irrelevant in most cases, because you can always catch/throws a more general exception type. A case where I can think it may make a difference is when you are accepting the Supplier as a parameter:

<X extends IOException> void example(Supplier<? extends X> exceptionSupplier)
    throws IOException {  // Note IOException, not X.
  Optional.empty().orElseThrow(exceptionSupplier);
}

You can invoke this with either of the following suppliers as the argument:

Supplier<IOException> s1 = IOException::new;
Supplier<FileNotFoundIOException> s2 = FileNotFoundIOException::new;

but you couldn't do the latter without the upper bound on Supplier<? extends X>.