Exercises
In these exercises, you’ll practice some of the concepts taught in this module.
First, either create a new Java project, adding the reactor-bom
and reactor-core
dependencies to your build file (Maven or Gradle) or use the stub you can find at: https://github.com/eh3rrera/project-reactor-course/tree/main/02/before/reactor-demo-exercises.
I’ll give you the instructions (and sometimes hints) so you can put all the code together in the main
method of a class and observe the output.
Here you can find the solution for the coding exercises: https://github.com/eh3rrera/project-reactor-course/tree/main/02/after/reactor-demo-exercises.
Exercise 1
This exercise will test your knowledge of the Mono.justOrEmpty method. You’ll create a simple application that demonstrates its usage with two Optional
values.
- Create a class named
Exercise01
with amain
method. - Create two
Optional
variables, one with a value and one empty. - Use the
Mono.justOrEmpty
method to create twoMono
instances, one for eachOptional
. - Subscribe to both
Mono
instances and print the results using the following code:monoWithValue.subscribe( element -> System.out.println("Mono with value - Value: " + element), error -> System.err.println("Mono with value - Error: " + error.getMessage()), () -> System.out.println("Mono with value complete") ); monoEmpty.subscribe( element -> System.out.println("Mono empty - Value: " + element), error -> System.err.println("Mono empty - Error: " + error.getMessage()), () -> System.out.println("Mono empty complete") );
- Run the
Exercise01
class and analyze the output. Which ones of the above print statements are executed? Why?
Exercise 2
In this exercise, you will create a Publisher
that emits more than one value and use the Mono.fromDirect method to convert it to a Mono
.
- Given the following class:
import org.reactivestreams.Publisher; import reactor.core.publisher.Mono; public class Exercise02 { public static void main(String[] args) { // Create a simple Publisher Publisher<Integer> publisher = createPublisher(); // Convert the Publisher to a Mono using fromDirect() Mono<Integer> mono = Mono.fromDirect(publisher); // Subscribe to the Mono mono.subscribe( value -> System.out.println("Received: " + value), error -> System.err.println("Error: " + error), () -> System.out.println("Completed") ); } private static Publisher<Integer> createPublisher() { // TODO: Create a Flux publisher that emits two values return null; } }
- Implement the
createPublisher()
method so that it creates and returns aFlux
that emits two elements. - Run the
Exercise02
class and analyze the output. Does it compile and run correctly? How many elements are printed? Why?
Exercise 3
In this exercise, you will create a CompletableFuture
that emits a value and use the Mono.fromFuture method to convert it to a Mono
.
- First, create a class named
Exercise03
with amain
method. - Add the following method to the class (also adding the corresponding
import
statements):private static CompletableFuture<String> createCompletableFuture() { ExecutorService executor = Executors.newSingleThreadExecutor(); return CompletableFuture.supplyAsync(() -> "Hi!", executor); }
- With the instance returned by this method, create a
Mono
in themain
method, and subscribe to it to print the value wrapped in theCompletableFuture
instance. - Run the
Exercise03
class and see the output.
Note: In a real-world application the executor service of the method createCompletableFuture
must be properly shut down. One option is creating the executor service in the main
method, passing it as an argument of createCompletableFuture
, and shut it down after the Mono
completes.
Exercise 4
In this exercise, you will create a Supplier
that provides a Publisher
and use the Flux.defer method to lazily instantiate the Publisher
every time a subscription is made on the resulting Flux
.
- First, create a class named
Exercise04
with amain
method. - Add the following method to the class (also adding the corresponding
import
statement):private static Supplier<Publisher<String>> createPublisherSupplier() { return () -> Flux.just("Current time: " + System.currentTimeMillis()); }
- In the
main
method, create aFlux
using the supplier returned by the above method. - Subscribe to the
Flux
and print the value emitted. - Once again, subscribe to the
Flux
and print the value emitted. - Run the
Exercise04
class and analyze the output. Does it throw an exception when you subscribe the second time? Why or why not?
Exercise 5
In this exercise, you will create a simple Flux
that emits values and use the subscribe(CoreSubscriber<? super T> actual) method to subscribe to the Flux
using a custom BaseSubscriber
.
- Given the following classes:
import org.reactivestreams.Publisher; import reactor.core.publisher.Mono; public class Exercise05 { public static void main(String[] args) { // Create a simple Flux that emits values Flux<Integer> flux = Flux.just(1, 2, 3); // Create a custom BaseSubscriber CustomBaseSubscriber<Integer> customSubscriber = new CustomBaseSubscriber<>(); // Subscribe to the Flux using the custom BaseSubscriber flux.subscribe(customSubscriber); } } class CustomBaseSubscriber<T> extends BaseSubscriber<T> { }
- Implement the methods of the class
CustomBaseSubscriber
so that when you run the classExercise05
, it prints the following:Subscribed Received: 1 Received: 2 Received: 3 Completed
Hint:
CustomBaseSubscriber
has to override the methods:hookOnSubscribe
,hookOnNext
,hookOnError
, andhookOnComplete
.