Skip to content

Commit e9fe56f

Browse files
committed
Explain onComplete vs. onSuccess + onFailure
Simplify the code by replacing onComplete + if-ar.succeeded-else with either onComplete(res, e) or with other processing. Avoiding onComplete + if-ar.succeeded-else results in more concise and understandable code because it avoids the additional nesting of the if-else clause. Extend the `exampleFuture*` code to discuss all possibilities how onComplete and onSuccess/onFailure might be used. Remove unused exampleFuture2 from lines 173-186. A new exampleFuture2 is created in line 145.
1 parent 56a122a commit e9fe56f

File tree

2 files changed

+121
-100
lines changed

2 files changed

+121
-100
lines changed

vertx-core/src/main/asciidoc/futures.adoc

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,27 @@ You cannot interact directly with the result of a future, instead you need to se
1212
{@link examples.CoreExamples#exampleFuture1}
1313
----
1414

15+
Instead of using `onComplete` with `if (ar.succeeded()) { … } else { … }` you can use the `onSuccess` and `onFailure` handlers:
16+
17+
[source,$lang]
18+
----
19+
{@link examples.CoreExamples#exampleFuture2}
20+
----
21+
22+
Frequently the future variable can be avoided. Often the lambda parameter type is not needed by compiler and code readers, allowing to replace `(FileProps fileProps)` with `fileProps`. In a lambda code block with a single statement the semicolon and the curly braces can be removed. This yields a more concise code:
23+
24+
[source,$lang]
25+
----
26+
{@link examples.CoreExamples#exampleFuture3}
27+
----
28+
29+
`.onSuccess` and `.onFailure` can be combined into the two parameter method `.onComplete`. This is slightly faster and takes slightly less memory, but might be less readable:
30+
31+
[source,$lang]
32+
----
33+
{@link examples.CoreExamples#exampleFuture4}
34+
----
35+
1536
[CAUTION]
1637
====
1738
Do not confuse _futures_ with _promises_.

vertx-core/src/main/java/examples/CoreExamples.java

Lines changed: 100 additions & 100 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright (c) 2011-2019 Contributors to the Eclipse Foundation
2+
* Copyright (c) 2011-2025 Contributors to the Eclipse Foundation
33
*
44
* This program and the accompanying materials are made available under the
55
* terms of the Eclipse Public License 2.0 which is available at
@@ -22,14 +22,17 @@
2222
import io.vertx.core.json.JsonObject;
2323
import io.vertx.core.net.NetClient;
2424
import io.vertx.core.net.NetServer;
25+
import io.vertx.core.net.NetSocket;
2526
import io.vertx.core.net.SocketAddress;
2627
import io.vertx.core.spi.VertxMetricsFactory;
2728
import io.vertx.core.spi.VertxTracerFactory;
2829
import io.vertx.core.spi.cluster.ClusterManager;
2930
import io.vertx.core.transport.Transport;
3031

3132
import java.util.Arrays;
33+
import java.util.Objects;
3234
import java.util.concurrent.TimeUnit;
35+
import java.util.stream.Collectors;
3336

3437
/**
3538
* Created by tim on 08/01/15.
@@ -73,19 +76,17 @@ public void example7(Vertx vertx) {
7376
vertx.executeBlocking(() -> {
7477
// Call some blocking API that takes a significant amount of time to return
7578
return someAPI.blockingMethod("hello");
76-
}).onComplete(res -> {
77-
System.out.println("The result is: " + res.result());
78-
});
79+
})
80+
.onSuccess(result -> System.out.println("The result is: " + result));
7981
}
8082

8183
public void workerExecutor1(Vertx vertx) {
8284
WorkerExecutor executor = vertx.createSharedWorkerExecutor("my-worker-pool");
8385
executor.executeBlocking(() -> {
8486
// Call some blocking API that takes a significant amount of time to return
8587
return someAPI.blockingMethod("hello");
86-
}).onComplete(res -> {
87-
System.out.println("The result is: " + res.result());
88-
});
88+
})
89+
.onSuccess(result -> System.out.println("The result is: " + result));
8990
}
9091

9192
public void workerExecutor2(WorkerExecutor executor) {
@@ -127,7 +128,7 @@ public void clusteredVertxBuilder(VertxOptions options, ClusterManager clusterMa
127128
.buildClustered();
128129
}
129130

130-
public void exampleFuture1(Vertx vertx, Handler<HttpServerRequest> requestHandler) {
131+
public void exampleFuture1(Vertx vertx) {
131132
FileSystem fs = vertx.fileSystem();
132133

133134
Future<FileProps> future = fs.props("/my_file.txt");
@@ -142,6 +143,36 @@ public void exampleFuture1(Vertx vertx, Handler<HttpServerRequest> requestHandle
142143
});
143144
}
144145

146+
public void exampleFuture2(Vertx vertx) {
147+
FileSystem fs = vertx.fileSystem();
148+
149+
Future<FileProps> future = fs.props("/my_file.txt");
150+
151+
future
152+
.onSuccess((FileProps fileProps) -> {
153+
System.out.println("File size = " + fileProps.size());
154+
})
155+
.onFailure((Throwable e) -> {
156+
System.out.println("Failure: " + e.getMessage());
157+
});
158+
}
159+
160+
public void exampleFuture3(Vertx vertx) {
161+
FileSystem fs = vertx.fileSystem();
162+
163+
fs.props("/my_file.txt")
164+
.onSuccess(fileProps -> System.out.println("File size = " + fileProps.size()))
165+
.onFailure(e -> System.out.println("Failure: " + e.getMessage()));
166+
}
167+
168+
public void exampleFuture4(Vertx vertx) {
169+
FileSystem fs = vertx.fileSystem();
170+
171+
fs.props("/my_file.txt")
172+
.onComplete(fileProps -> System.out.println("File size = " + fileProps.size()),
173+
e -> System.out.println("Failure: " + e.getMessage()));
174+
}
175+
145176
public void promiseCallbackOrder(Future<Void> future) {
146177
future.onComplete(ar -> {
147178
// Do something
@@ -170,61 +201,56 @@ public void exampleFutureComposition1(Vertx vertx) {
170201
});
171202
}
172203

173-
public void exampleFuture2(Vertx vertx, Handler<HttpServerRequest> requestHandler) {
174-
FileSystem fs = vertx.fileSystem();
204+
public void exampleFutureComposition2(Vertx vertx) {
175205

176-
Future<FileProps> future = fs.props("/my_file.txt");
206+
FileSystem fs = vertx.fileSystem();
177207

178-
future.onComplete((AsyncResult<FileProps> ar) -> {
179-
if (ar.succeeded()) {
180-
FileProps props = ar.result();
181-
System.out.println("File size = " + props.size());
182-
} else {
183-
System.out.println("Failure: " + ar.cause().getMessage());
184-
}
185-
});
208+
Future<Void> future = fs
209+
.createFile("/foo")
210+
// When the file is created (fut1), execute this:
211+
.compose(v -> fs.writeFile("/foo", Buffer.buffer()))
212+
// When the file is written (fut2), execute this:
213+
.compose(v -> fs.move("/foo", "/bar"));
186214
}
187215

188-
public void exampleFutureAll1(HttpServer httpServer, NetServer netServer) {
216+
public Future<?> exampleFutureAll1(HttpServer httpServer, NetServer netServer) {
189217
Future<HttpServer> httpServerFuture = httpServer.listen();
190218

191219
Future<NetServer> netServerFuture = netServer.listen();
192220

193-
Future.all(httpServerFuture, netServerFuture).onComplete(ar -> {
194-
if (ar.succeeded()) {
195-
// All servers started
196-
} else {
221+
return Future.all(httpServerFuture, netServerFuture)
222+
.onFailure(e -> {
197223
// At least one server failed
198-
}
199-
});
224+
});
200225
}
201226

202227
public void exampleFutureAll2(Future<?> future1, Future<?> future2, Future<?> future3) {
203228
Future.all(Arrays.asList(future1, future2, future3));
204229
}
205230

206-
public void exampleFutureAny1(Future<String> future1, Future<String> future2) {
207-
Future.any(future1, future2).onComplete(ar -> {
208-
if (ar.succeeded()) {
209-
// At least one is succeeded
210-
} else {
231+
public Future<String> exampleFutureAny1(Future<String> future1, Future<String> future2) {
232+
return Future.any(future1, future2)
233+
.map(result -> // At least one is succeeded
234+
future1.succeeded() ? future1.result() : future2.result())
235+
.onFailure(e -> {
211236
// All failed
212-
}
213-
});
237+
});
214238
}
215239

216240
public void exampleFutureAny2(Future<?> f1, Future<?> f2, Future<?> f3) {
217241
Future.any(Arrays.asList(f1, f2, f3));
218242
}
219243

220-
public void exampleFutureJoin1(Future<?> future1, Future<?> future2, Future<?> future3) {
221-
Future.join(future1, future2, future3).onComplete(ar -> {
222-
if (ar.succeeded()) {
223-
// All succeeded
224-
} else {
225-
// All completed and at least one failed
226-
}
227-
});
244+
public Future<String> exampleFutureJoin1(Future<String> future1, Future<String> future2, Future<String> future3) {
245+
CompositeFuture compositeFuture = Future.join(future1, future2, future3);
246+
247+
return compositeFuture
248+
.map(x -> {
249+
// All completed, each is either succeeded or failed
250+
return compositeFuture.<String>list().stream()
251+
.filter(Objects::nonNull) // failed have null
252+
.collect(Collectors.joining(", "));
253+
});
228254
}
229255

230256
public void exampleFutureJoin2(Future<?> future1, Future<?> future2, Future<?> future3) {
@@ -294,6 +320,16 @@ public void start(Promise<Void> startPromise) throws Exception {
294320
}
295321
});
296322

323+
// Or
324+
future
325+
.onSuccess(x -> startPromise.complete())
326+
.onFailure(startPromise::fail);
327+
328+
// Or
329+
future
330+
.onComplete(x -> startPromise.complete(),
331+
startPromise::fail);
332+
297333
// Or
298334
future
299335
.<Void>mapEmpty()
@@ -334,28 +370,14 @@ public void example9(Vertx vertx) {
334370

335371
}
336372

337-
public void example10(Vertx vertx) {
338-
vertx
373+
public Future<String> example10(Vertx vertx) {
374+
return vertx
339375
.deployVerticle(new MyOrderProcessorVerticle())
340-
.onComplete(res -> {
341-
if (res.succeeded()) {
342-
System.out.println("Deployment id is: " + res.result());
343-
} else {
344-
System.out.println("Deployment failed!");
345-
}
346-
});
376+
.onSuccess(deploymentID -> System.out.println("Deployment id is: " + deploymentID));
347377
}
348378

349379
public void example11(Vertx vertx, String deploymentID) {
350-
vertx
351-
.undeploy(deploymentID)
352-
.onComplete(res -> {
353-
if (res.succeeded()) {
354-
System.out.println("Undeployed ok");
355-
} else {
356-
System.out.println("Undeploy failed!");
357-
}
358-
});
380+
vertx.undeploy(deploymentID);
359381
}
360382

361383
public void example12(Vertx vertx) {
@@ -516,83 +538,61 @@ public void configureBSDOptions(Vertx vertx, boolean reusePort) {
516538
vertx.createHttpServer(new HttpServerOptions().setReusePort(reusePort));
517539
}
518540

519-
public void tcpServerWithDomainSockets(Vertx vertx) {
541+
public Future<NetServer> tcpServerWithDomainSockets(Vertx vertx) {
520542
NetServer netServer = vertx.createNetServer();
521543

522544
// Only available when running on JDK16+, or using a native transport
523545
SocketAddress address = SocketAddress.domainSocketAddress("/var/tmp/myservice.sock");
524546

525-
netServer
547+
return netServer
526548
.connectHandler(so -> {
527-
// Handle application
549+
// Handle application
528550
})
529-
.listen(address)
530-
.onComplete(ar -> {
531-
if (ar.succeeded()) {
532-
// Bound to socket
533-
} else {
534-
// Handle failure
535-
}
536-
});
551+
.listen(address);
537552
}
538553

539-
public void httpServerWithDomainSockets(Vertx vertx) {
554+
public Future<HttpServer> httpServerWithDomainSockets(Vertx vertx) {
540555
HttpServer httpServer = vertx.createHttpServer();
541556

542557
// Only available when running on JDK16+, or using a native transport
543558
SocketAddress address = SocketAddress.domainSocketAddress("/var/tmp/myservice.sock");
544559

545-
httpServer
560+
return httpServer
546561
.requestHandler(req -> {
547562
// Handle application
548563
})
549-
.listen(address)
550-
.onComplete(ar -> {
551-
if (ar.succeeded()) {
552-
// Bound to socket
553-
} else {
554-
// Handle failure
555-
}
556-
});
564+
.listen(address);
557565
}
558566

559-
public void tcpClientWithDomainSockets(Vertx vertx) {
567+
public Future<NetSocket> tcpClientWithDomainSockets(Vertx vertx) {
560568
NetClient netClient = vertx.createNetClient();
561569

562570
// Only available when running on JDK16+, or using a native transport
563571
SocketAddress addr = SocketAddress.domainSocketAddress("/var/tmp/myservice.sock");
564572

565573
// Connect to the server
566-
netClient
567-
.connect(addr)
568-
.onComplete(ar -> {
569-
if (ar.succeeded()) {
570-
// Connected
571-
} else {
572-
// Handle failure
573-
}
574-
});
574+
return netClient
575+
.connect(addr);
575576
}
576577

577-
public void httpClientWithDomainSockets(Vertx vertx) {
578+
private Future<Void> process(Buffer buffer, String parameter) {
579+
return Future.succeededFuture();
580+
}
581+
582+
public Future<Void> httpClientWithDomainSockets(Vertx vertx) {
578583
HttpClient httpClient = vertx.createHttpClient();
579584

580585
// Only available when running on JDK16+, or using a native transport
581586
SocketAddress addr = SocketAddress.domainSocketAddress("/var/tmp/myservice.sock");
582587

583588
// Send request to the server
584-
httpClient.request(new RequestOptions()
589+
return httpClient.request(new RequestOptions()
585590
.setServer(addr)
586591
.setHost("localhost")
587592
.setPort(8080)
588593
.setURI("/"))
589-
.compose(request -> request.send().compose(HttpClientResponse::body))
590-
.onComplete(ar -> {
591-
if (ar.succeeded()) {
592-
// Process response
593-
} else {
594-
// Handle failure
595-
}
596-
});
594+
.compose(request -> request.send())
595+
.compose(HttpClientResponse::body)
596+
.compose(buffer -> process(buffer, "some parameter")); // Process response
597597
}
598598
}

0 commit comments

Comments
 (0)