In the first snippet below, I would expect "ex" in the handle() method to be of type NoSuchElementException. To my surprise, the NoSuchElementException was wrapped in a CompletionException instead at runtime.
    CompletableFuture.failedFuture(new NoSuchElementException())
            .thenApply(s -> s) // transform the result
            .handle((response, ex) -> {
                if (ex instanceof NoSuchElementException) {
                    // translate the exception into another exception
                } else {
                    return response;
                }
            });
If I remove the call to thenApply() such as below, then ex would be of type NoSuchElementException. I would like to understand what happen in thenApply that led to ex being wrapped inside CompletionException.
        CompletableFuture.failedFuture(new NoSuchElementException())
            .handle((response, ex) -> {
                if (ex instanceof NoSuchElementException) {
                // translate the exception into another exception
                } else {
                    return response;
                }
            });