I need to asynchronously consume future value and then run logic X. In case of any exceptions, I also want to execute logic X. In a way, it is semantically akin to the finally
block.
I do not have a lot of hands-on experience with CompletableFuture
. But unless I'm mistaken, I would have to resort to ugly lambdas returning null
s. I hate returning null
s as well as curly braces (they impair code readability, imo).
This code tries to load data from a DB, then use it to fill a GUI table (a JTable
). In the meantime, a progress dialog is displayed. It should be disposed whenever the operation is completed, successfully or not. I changed the actual naming a little bit.
private CompletableFuture<Void> fillTableAsync() {
String title = "Loading table data...";
ProgressDialog progressDialog = new ProgressDialog(title);
CompletableFuture<Void> futureFill = CompletableFuture.supplyAsync(this::loadData)
.thenAccept(this::fillTable)
.thenRun(progressDialog::dispose)
.exceptionally(t -> {
progressDialog.dispose();
return null;
});
SwingUtilities.invokeLater(() -> progressDialog.setVisible(true));
return futureFill;
}
What I want:
.finallyRun(progressDialog::dispose);
or at least:
.thenRun(progressDialog::dispose)
.exceptionally(progressDialog::dispose);
While those options are not available, there may be some cleaner ways to do it that I'm not aware of.
How am I supposed to do it? Can I do it more cleanly?
Java 8. Guava. Apache (Commons, Collections).
Maybe you can write it like this:
private CompletableFuture<Void> fillTableAsync() {
String title = "Loading table data...";
ProgressDialog progressDialog = new ProgressDialog(title);
CompletableFuture<Void> futureFill = CompletableFuture.supplyAsync(this::loadData)
.thenAccept(this::fillTable)
.whenComplete((result, exception) -> progressDialog.dispose());
SwingUtilities.invokeLater(() -> progressDialog.setVisible(true));
return futureFill;
}