Search code examples
javawildcardoption-typesupplier

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


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?


Solution

  • 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>.