concurrent/src/main/java/io/airlift/concurrent/MoreFutures.java
public static <V, E extends Exception> V getFutureValue(Future<V> future, Class<E> exceptionType)
            throws E
    {
        requireNonNull(future, "future is null");
        requireNonNull(exceptionType, "exceptionType is null");

        try {
            return future.get();
        }
        catch (InterruptedException e) {
            Thread.currentThread().interrupt();
            throw new RuntimeException("interrupted", e);
        }
        catch (ExecutionException e) {
            Throwable cause = e.getCause() == null ? e : e.getCause();
            propagateIfPossible(cause, exceptionType);
            throw new RuntimeException(cause);
        }
    }
public static <V, E extends Exception> V getFutureValue(Future<V> future, Class<E> exceptionType)
            throws E
    {
        requireNonNull(future, "future is null");
        requireNonNull(exceptionType, "exceptionType is null");

        try {
            return future.get();
        }
        catch (InterruptedException e) {
            Thread.currentThread().interrupt();
            throw new RuntimeException("interrupted", e);
        }
        catch (ExecutionException e) {
            Throwable cause = e.getCause() == null ? e : e.getCause();
            propagateIfPossible(cause, exceptionType);
            throw new RuntimeException(cause);
        }
    }
Waits for the value from the future. If the future is failed, the exception
is thrown directly if it is an instance of the specified exception type or
unchecked, or it is wrapped in a RuntimeException. If the thread is
interrupted, the thread interruption flag is set and the original
InterruptedException is wrapped in a RuntimeException and thrown.