π Reading time: 2 minutes
New Saturday, new library, new pill!
You know that moment when you wonder whether your Mono gets straight to work or waits for the right time β without wasting resources? No? Well, if you're not a dev or you don't use WebFlux, of course not β it'd be pretty weird otherwise, eheh! But if you're curious, here's a really, really simple example to understand the difference between Mono.just() and Mono.fromCallable().
π The experiment
I compare two ways of creating a Mono to understand which one does the work first and which one puts it off until later.
class SampleTest014 {
@Test
void test_MonoJust_eagerEvaluation() {
final AtomicBoolean called = new AtomicBoolean(false);
// Mono.just eagerly evaluates its argument
final Mono<String> actualMono = Mono.just(computeValue(called));
assertTrue(called.get()); // computeValue has ALREADY been called
final String actual = actualMono.block();
assertEquals("computed", actual);
}
@Test
void test_MonoFromCallable_lazyEvaluation() {
final AtomicBoolean called = new AtomicBoolean(false);
// Mono.fromCallable defers computation until subscription
final Mono<String> actualMono = Mono.fromCallable(() -> computeValue(called));
assertFalse(called.get()); // computeValue NOT YET called
final String actual = actualMono.block();
assertTrue(called.get()); // NOW computeValue has been called
assertEquals("computed", actual);
}
// helper method to set the flag and return a fixed string
private String computeValue(final AtomicBoolean flag) {
flag.set(true);
return "computed";
}
}
π Analysis of the 1st test β MonoJust_eagerEvaluation()
The method receives the value right away, so the computeValue() function is called as soon as I create the Mono. The result is ready before I even subscribe!
π Analysis of the 2nd test β MonoFromCallable_lazyEvaluation()
Here, on the other hand, the function isn't called immediately, but only when the Mono is subscribed to β that is, at the moment of .block(). In practice, the work is deferred until the last possible moment.
π When should you use fromCallable()?
If you have potentially blocking operations such as reading the output of an external process with a BufferedReader, fromCallable() lets you defer everything until subscription. That way you avoid kicking off the operation too early and keep the reactive flow clean!
See you at the next pill! β