### Question:
FutureUtils { public static CompletableFuture<Void> runAfterwards(CompletableFuture<?> future, RunnableWithException runnable) { return runAfterwardsAsync(future, runnable, Executors.directExecutor()); }  static CompletableFuture<T> retry(
			final Supplier<CompletableFuture<T>> operation,
			final int retries,
			final Executor executor); static CompletableFuture<T> retryWithDelay(
			final Supplier<CompletableFuture<T>> operation,
			final int retries,
			final Time retryDelay,
			final Predicate<Throwable> retryPredicate,
			final ScheduledExecutor scheduledExecutor); static CompletableFuture<T> retryWithDelay(
			final Supplier<CompletableFuture<T>> operation,
			final int retries,
			final Time retryDelay,
			final ScheduledExecutor scheduledExecutor); static CompletableFuture<T> retrySuccesfulWithDelay(
		final Supplier<CompletableFuture<T>> operation,
		final Time retryDelay,
		final Deadline deadline,
		final Predicate<T> acceptancePredicate,
		final ScheduledExecutor scheduledExecutor); static CompletableFuture<T> orTimeout(CompletableFuture<T> future, long timeout, TimeUnit timeUnit); static CompletableFuture<Void> runAfterwards(CompletableFuture<?> future, RunnableWithException runnable); static CompletableFuture<Void> runAfterwardsAsync(CompletableFuture<?> future, RunnableWithException runnable); static CompletableFuture<Void> runAfterwardsAsync(
		CompletableFuture<?> future,
		RunnableWithException runnable,
		Executor executor); static CompletableFuture<Void> composeAfterwards(
			CompletableFuture<?> future,
			Supplier<CompletableFuture<?>> composedAction); static ConjunctFuture<Collection<T>> combineAll(Collection<? extends CompletableFuture<? extends T>> futures); static ConjunctFuture<Void> waitForAll(Collection<? extends CompletableFuture<?>> futures); static ConjunctFuture<Void> completeAll(Collection<? extends CompletableFuture<?>> futuresToComplete); static CompletableFuture<T> completedExceptionally(Throwable cause); static CompletableFuture<T> supplyAsync(SupplierWithException<T, ?> supplier, Executor executor); static FiniteDuration toFiniteDuration(Time time); static Time toTime(FiniteDuration finiteDuration); static CompletableFuture<T> toJava(Future<T> scalaFuture);  }### Answer:
@Test public void testRunAfterwards() throws Exception { final CompletableFuture<Void> inputFuture = new CompletableFuture<>(); final OneShotLatch runnableLatch = new OneShotLatch(); final CompletableFuture<Void> runFuture = FutureUtils.runAfterwards( inputFuture, runnableLatch::trigger); assertThat(runnableLatch.isTriggered(), is(false)); assertThat(runFuture.isDone(), is(false)); inputFuture.complete(null); assertThat(runnableLatch.isTriggered(), is(true)); assertThat(runFuture.isDone(), is(true)); runFuture.get(); }
@Test public void testRunAfterwardsExceptional() throws Exception { final CompletableFuture<Void> inputFuture = new CompletableFuture<>(); final OneShotLatch runnableLatch = new OneShotLatch(); final FlinkException testException = new FlinkException("Test exception"); final CompletableFuture<Void> runFuture = FutureUtils.runAfterwards( inputFuture, runnableLatch::trigger); assertThat(runnableLatch.isTriggered(), is(false)); assertThat(runFuture.isDone(), is(false)); inputFuture.completeExceptionally(testException); assertThat(runnableLatch.isTriggered(), is(true)); assertThat(runFuture.isDone(), is(true)); try { runFuture.get(); fail("Expected an exceptional completion"); } catch (ExecutionException ee) { assertThat(ExceptionUtils.stripExecutionException(ee), is(testException)); } }