# Mono.just() vs Mono.defer() vs Mono.fromSupplier() vs Mono.create()

In 
Mono
Published 2022-09-23

This tutorial explains the creation of Monos with Mono.just(), Mono.defer(), Mono.fromSupplier(), Mono.create() and the differences between them.

Mono.just() : emits an element (or nothing) when the 1st subscriber subscribe to it. We have an eager generation (the next subscribers will receive the same value).

Mono.defer() : emits an element (or nothing) when the 1st subscriber subscribe to it. We have a lazy generation. (the next subscribers could receive the values, and that depends on the implementation). The implementation acts as a wrapper of Mono.just().

Mono.fromSupplier() : emits an element (or nothing) when the 1st subscriber subscribe to it. We have a lazy generation. (the next subscribers could receive new values, and that depends on the implementation). We need to provide the element (which is not a Mono) which will be emitted (generally we have a method call).

Mono.create() : emits an element (or nothing) when the 1st subscriber subscribe to it. We have a lazy generation. (the next subscribers could receive new values, and that depends on the implementation). This implementation helps us to create more complex code, by letting us throw an errors or emitting the stream value.

Take a look at the following example created with Spring Boot 3.0, maven in Kotlin:

DemoMonoApplication.java
package com.example.demo1

import org.springframework.boot.autoconfigure.SpringBootApplication
import org.springframework.boot.runApplication
import reactor.core.publisher.Mono
import reactor.core.publisher.MonoSink
import java.io.IOException
import java.time.LocalDateTime

@SpringBootApplication
class DemoMonoApplication

suspend fun main(args: Array<String>) {
	runApplication<Demo1Application>(*args)

	fun successfulRemoteCall(): LocalDateTime {
		Thread.sleep(1000)
		println("Getting the response ...")
		return LocalDateTime.now()
	}

	// Mono.just()
	fun monoJust(): Mono<LocalDateTime> = Mono.just(successfulRemoteCall())
	val monoJust = monoJust()
	println("")
	println(">>> Mono.just() <<<")
	monoJust.subscribe({print("monoJust/ 1st subscription: "); println(it)})
	monoJust.subscribe({print("monoJust/ 2nd subscription: "); println(it)})

	// Mono.defer()
	fun monoDefer(): Mono<LocalDateTime> =	Mono.defer { monoJust() }
	val monoDefer = monoDefer()
	println("")
	println(">>> Mono.defer() <<<")
	monoDefer.subscribe({print("monoDefer/ 1st subscription: "); println(it)})
	monoDefer.subscribe({print("monoDefer/ 2nd subscription: "); println(it)})

	// Mono.fromSupplier()
	fun monoFromSupplier(): Mono<LocalDateTime> = Mono.fromSupplier { successfulRemoteCall() }
	val monoFromSupplier = monoFromSupplier()
	println("")
	println(">>> Mono.fromSupplier() <<<")
	monoFromSupplier.subscribe({print("monoFromSupplier/ 1st subscription: "); println(it)})
	monoFromSupplier.subscribe({print("monoFromSupplier/ 2nd subscription: "); println(it)})

   // Mono.create()
	println("")
	println(">>> Mono.create() 1 <<<")
	fun getAnyString1(): String {
		return "My String"
	}

	fun getAnyString2(): String {
		throw IllegalArgumentException("An error as occurred for no reason.");
	}

	val monoCreate1 = Mono.create<String?> { sink: MonoSink<String?> ->
		//
		try {
			println("SOME CODE could be here ...")
			var var1 = getAnyString1();
			sink.success(var1)
		} catch (e: Exception) {
			sink.error(IOException("File path is invalid"))
		}
	}
	monoCreate1.subscribe({print("monoCreate1/ 1st subscription: "); println(it)})
	monoCreate1.subscribe({print("monoCreate1/ 2nd subscription: "); println(it)})

	println("")
	println(">>> Mono.create() 2 <<<")
	val monoCreate2 = Mono.create<String?> { sink: MonoSink<String?> ->
		//
		try {
			println("SOME CODE could be here ...")
			var var1 = getAnyString2();
			sink.success(var1)
		} catch (e: Exception) {
			// We throw an exception
			sink.error(IOException("File path is invalid"))
		}
	}
	monoCreate2.subscribe({print("monoCreate1/ 1st subscription: "); println(it)})
}

When we run this code we receive the following output:

Getting the response ...

>>> Nano.just() <<<
monoJust/ 1st subscription: 2023-09-23T09:26:19.457888700
monoJust/ 2nd subscription: 2023-09-23T09:26:19.457888700

>>> Nano.defer() <<<
Getting the response ...
monoDefer/ 1st subscription: 2023-09-23T09:26:20.475227600
Getting the response ...
monoDefer/ 2nd subscription: 2023-09-23T09:26:21.488765

>>> Nano.fromSupplier() <<<
Getting the response ...
monoFromSupplier/ 1st subscription: 2023-09-23T09:26:22.492847600
Getting the response ...
monoFromSupplier/ 2nd subscription: 2023-09-23T09:26:23.510062300

>>> Nano.create() 1 <<<
SOME CODE could be here ...
monoCreate1/ 1st subscription: My String
SOME CODE could be here ...
monoCreate1/ 2nd subscription: My String

>>> Nano.create() 2 <<<
SOME CODE could be here ...
2023-09-23T09:26:23.514+03:00 ERROR 8748 --- [           main] reactor.core.publisher.Operators         : Operator called default onErrorDropped

reactor.core.Exceptions$ErrorCallbackNotImplemented: java.io.IOException: File path is invalid