Asynchronous Programming in Java

You might also like

Download as pdf or txt
Download as pdf or txt
You are on page 1of 1

Sign in Get started

— T O QUIT OR NOT T O QUIT ? — T OP 50 S T ORIES WRIT ERS HERE ARE YOU CURIOUS ?

You have 2 free stories left this month. Sign up and get an extra one for free.

Asynchronous Programming In Java


Rohan Aggarwal Follow
Jun 19 · 7 min read

Asynchronous programming is a programming


paradigm that facilitates fast and responsive
user interfaces. The asynchronous programming
model in Java provides a consistent
programming model to write programs that
support asynchrony.

Why Asynchronous programming


Asynchronous programming provides a non-blocking, event-driven
programming model. This programming model leverages the multiple
cores in your system to provide parallelization by using multiple CPU
cores to execute the tasks, thus increasing the application’s throughput.

In Java, there are many ways to achieve asynchronous programming or


reactive programming like using RxJava, project Reactor, vertX, etc

Here we will discuss the project Reactor using the spring web-Flux
module.

Spring webFlux module


Spring Framework 5 includes a new spring-webFlux module. We will
achieve the asynchronous services using spring webFlux. It exposes 2
major API types: Flux and Mono. These API works on the concept of
subscriber and publisher. Flux and Mono are publishers.

Difference between Flux and Mono


Mono can publish almost 1 result i.e either 0 or 1 whereas a flux can
publish 0 to infinite results.

let's discuss them 1 by 1

Dependencies

<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-webflux</artifactId>
</dependency>

Flux
Flux can publish 0 or more values. It can of any type.

Flux creation methods


1. Flux.just()
Use this method when we have to pass comma-separated values.

Flux<Integer> primaryFlux = Flux.just(1, 2, 3, 4);

2. Flux.fromIterable()
This method is used when we have an instance of an iterable like list, set.

List<String> list = Arrays.asList("foo", "bar", "foobar");


Flux<String> stringFlux = Flux.fromIterable(list);

3. Flux.range()
This method is used to create a publisher of numbers.

Flux.range(4,4); // it will give 4,5,6,7 as output

4. Flux.empty()
This method is used to create an empty flux

Flux<Integer> empty = Flux.empty();

5. Flux.error()
This method is used to publish some error response.

Flux.error(new Exception("Something went wrong"));

6. Flux.duration()
This method emits long values starting from 0 in the given duration

Flux.interval(Duration.ofMillis(1000));

These are the most commonly used flux creation methods. There are
few more like fromArray, fromStream, create, etc

Mono creation methods


Mono.just()
Just like we have this method in Flux we have just() method in Mono. The
only difference is we can pass only 1 value to it

Mono<Integer> mono = Mono.just(1);

Mono.empty()
Same as Flux this method is used to create empty Mono. Usually comes
when we don't want to return null, we can return empty Mono.

Mono<Object> empty = Mono.empty();

Mono.error()
It will publish an exception.

Mono<Object> exception = Mono.error(new Exception("Something went


wrong"));

Mono.from()
This is used to create a new publisher from the existing one

Flux<Integer> primaryFlux = Flux.just(1, 2, 3, 4);


Mono<Integer> mono = Mono.from(primaryFlux);

Mono.justOrEmpty()
This method can take Optional value or direct value. In case of optional
value, it will return value if Optional is not null else only emit
onComplete In case of direct value it will return the value or emit
onComplete if null is passed

Mono<Object> justOrEmptyMono1 =
Mono.justOrEmpty(Optional.ofNullable(null));
Mono<Integer> justOrEmptyMono2 =
Mono.justOrEmpty(Optional.ofNullable(1));
Mono<Integer> justOrEmptyMono3 = Mono.justOrEmpty(1);
Mono<Object> justOrEmptyMono4 = Mono.justOrEmpty(null);

There are many more methods to create Mono like


*Mono.fromCallable(), Mono.fromRunnable(), Mono.fromFuture() etc.

Subscribing publishers
A publisher can only publish value when someone subscribe to it. When
we subscribe to any publisher, we can get 1 of three results

i) response

ii) error

iii) completion indication

And a subscriber has 3 methods to handle these results

onNext()

onError()

onComplete()

onNext() method is called when any success response emits from the
publisher. The OnError() method is called when an error response emits
from the publisher. The onComplete() method gets called in the end
when there are no more values left to emit. Its a kind of indicator to tell
subscriber that subscription is completed.

flux.subscribe(
onNext(),
onError(),
onComplete()
);

OnError() and onComplete() are terminator methods means once they get
called, the subscription ends.

Flux<Integer> integerFlux = Flux.just(1,2,3,4);

integerFlux.subscribe(
(x) -> System.out.println(x),
error -> System.out.println("Error : " + error),
() -> System.out.println("Subscription completed")
);

In the above example onNext() method will be called 4 times and


onComplete() once. There is no error that is why onError will not get
called.

Flux<Object> primaryFlux =
Flux.just(1, 2, 3, 4, new Exception("Something went wrong"));

primaryFlux.subscribe(
(x) -> System.out.println(x),
error -> System.out.println("Error : " + error),
() -> System.out.println("Subscription completed")
);

In this example onNext() will get called 4 times and onError() will get
called once. Subscription got cancelled after onError() method so
onComplete() will not get called.

So from the above example, we can conclude that only one of onError()
and onComplete() can get called in any subscription.

Intermittent functions
These are the functions which take the values from the publisher and
perform some functions on it before passing it to a subscriber.

Let's discuss a few of them.

1. map
This method is used to transform the values from a publisher (Flux or
mono) before passing it to a subscriber.

Flux<Integer> fluxWithError = Flux.range(11, 4)


.map(x -> {
if (x < 40) {
return x * x;
} else {
throw new RuntimeException("Value too large" + x);
}
});

fluxWithError.subscribe(
System.out::println,
error -> System.out.println("Error : " + error),
() -> System.out.println("Subscription completed")
);

// Output :
// 121
// 144
// 169
// 196
// Subscription completed

1. buffer
We can use it in 2 ways: 1st with buffer size and 2nd with time duration

In the case of buffer size, we can set the number of values that we want
to emit at 1 time.

Flux<Integer> integerFlux = Flux.just(1,2,3,4);

integerFlux
.buffer(2)
.subscribe(x-> System.out.println(x)); // [[1, 2], [3, 4]]

Here we defined buffer size as 2. So it keeps adding values in the buffer


and only emits when it reached the buffer size.

In case of buffer duration, the publisher publishes values in every


specified time duration

Flux<Integer> integerFlux = Flux.just(1,2,3,4);

integerFlux
.buffer(Duration.ofMillis(5000))
.subscribe(x-> System.out.println(x)); // [1,2,3,4]

It will emit all the values in 1 go because before 5000 ms it added all the
values in the buffer. Let say if we are getting 2 values in every 5000ms, So
the response will be like

// [[1, 2], [3, 4]]

2. doOnEach()
This method is used to check all the values of the publisher before
passing it to the subscriber

Flux.just(1,2,3,4)
.doOnEach(x -> System.out.println(x.get()))
.subscribe(x -> System.out.println("subscriber value" + x));

Output :

1
subscriber value1
2
subscriber value2
3
subscriber value3
4
subscriber value4
null // In case when OnComplete runs the value of x is 0
is printed when we did x.get()

with this method, we can check which all method will get called and how
many times

Flux.just(1,2,3,4)
.doOnEach(x -> System.out.println(x.getType()))
.subscribe(x -> System.out.println("subscriber value" + x));

output :

onNext
subscriber value1
onNext
subscriber value2
onNext
subscriber value3
onNext
subscriber value4
onComplete

3. log()
This method is used for the logging purpose

Flux.just(1,2,3,4)
.log()
.subscribe(x -> System.out.println("subscriber value" + x));

output on the console :

2020-05-28 20:56:43.767 INFO 10658 --- [or-http-epoll-2]


reactor.Flux.Array.2 : | onSubscribe([Synchronous
Fuseable] FluxArray.ArraySubscription)
2020-05-28 20:56:43.768 INFO 10658 --- [or-http-epoll-2]
reactor.Flux.Array.2 : | request(unbounded)
2020-05-28 20:56:43.768 INFO 10658 --- [or-http-epoll-2]
reactor.Flux.Array.2 : | onNext(1)
subscriber value1
2020-05-28 20:56:43.768 INFO 10658 --- [or-http-epoll-2]
reactor.Flux.Array.2 : | onNext(2)
subscriber value2
2020-05-28 20:56:43.768 INFO 10658 --- [or-http-epoll-2]
reactor.Flux.Array.2 : | onNext(3)
subscriber value3
2020-05-28 20:56:43.768 INFO 10658 --- [or-http-epoll-2]
reactor.Flux.Array.2 : | onNext(4)
subscriber value4
2020-05-28 20:56:43.768 INFO 10658 --- [or-http-epoll-2]
reactor.Flux.Array.2 : | onComplete()

It will log all the methods called in the subscriber with the order in which
they get called.

4. delayElement()
This method is used to delay the emission of value from the publisher for
the given time

Flux.just(1,2,3,4)
.delayElements(Duration.ofMillis(5000))
.subscribe(x -> System.out.println("subscriber value" + x));

It will print 1 value on console 4 times in every 5 sec

5. subscribeOn()
By default, the whole subscription process works in the main thread
which subscribes to the publisher. We can change that using
subscribeOn() method

Flux.just(1,2,3,4)
.subscribeOn(Schedulers.parallel())
.subscribe(x -> System.out.println("subscriber value" + x));

6. blockFirst()
This method subscribes to the flux and returns the first element or null if
no value is present. This is usually used for testing

AtomicLong cancelCount = new AtomicLong();

Flux.range(1, 10)
.doOnCancel(cancelCount::incrementAndGet)
.blockFirst();

assertThat(cancelCount.get()).isEqualTo(1);

7. blockLast()
This method subscribes to the flux and returns the last element or null if
no value is present. This is also usually used for testing

AtomicLong cancelCount = new AtomicLong();

Flux.range(1, 10)
.doOnCancel(cancelCount::incrementAndGet)
.blockFirst();

assertThat(cancelCount.get()).isEqualTo(10);

8. timeout()
Propagate a TimeoutException as soon as no item is emitted within the
given Duration from the previous emission (or the subscription for the
first item).

Flux.just(1,2,3,4)
.timeout(Duration.ofMillis(1000))
.subscribe(x -> System.out.println("subscriber value" + x));

9. bufferUntilChanged()
This method adds the values into the buffer until they are the same and
emits them when it receives some other value.

Flux.just(1,1,2,2,3,4)
.bufferUntilChanged()
.subscribe(x -> System.out.println("subscriber value" + x));

output :

subscriber value[1, 1]
subscriber value[2, 2]
subscriber value[3]
subscriber value[4]

10. cache
This method is used to cache the values emitted from the publisher. we
can pass the count as a parameter, how many last emitted values we
want to cache. So when any other subscriber subscribes to it, there won't
be any need to go to the publisher.

Flux<Integer> flux = Flux.just(1, 1, 2, 2, 3, 4)


.cache(2);

flux.subscribe(System.out::println);

flux.subscribe(System.out::println);

This method is useful when we have a publisher with infinite values. And
we want to keep track of at least a few previously emitted values as well.

There are many many more methods present in Flux and Mono. For
whole list, you can refer to

https://projectreactor.io/docs/core/release/api/reactor/core/publisher
/Flux.html

https://projectreactor.io/docs/core/release/api/reactor/core/publisher
/Mono.html

Sign up for Top Stories


By T he Startup

A newsletter that delivers The Startup's most popular stories to your inbox once a
month. Take a look

Your email Get this newsletter

By signing up, you will create a Medium account if you don’t already have one. Review our Privacy Policy for more
information about our privacy practices.

Java Asynchronous Asynchronous Programming Project Reactor Flux And Mono

66 claps

WRIT T EN BY

Rohan Aggarwal Follow

Full stack developer

The Startup Follow

Medium's largest active publication, followed by +687K


people. Follow to join our community.

More From Medium

Analog Input Processing Flutter Interview Making accessible T he Exhausted


Pat Wilson Questions and Answers, tagged PDFs with Prince Programmer
Q1 2020 Bruce Lawson Meriam Kharbat in Better
Artur Rymarz in Better Programming
Programming

Fun with array rotations Create and Deploy an Sepia Development Log Build your First React
Sachin Malhotra in AWS Lambda Function #1 —Beautiful Single Page App
HackerNoon.com for Data Collection with Environments and Tom in T he Startup
the AWS CLI Better Movement
Conor Aspell in T he Startup Emmett Boudreau in Chi
Media

Discover Medium Make Medium yours Become a member


Welcome to a place where words matter. On Medium, Follow all the topics you care about, and we’ll deliver the Get unlimited access to the best stories on Medium — and
smart voices and original ideas take center stage - with no best stories for you to your homepage and inbox. Explore support writers while you’re at it. Just $5/month. Upgrade
ads in sight. Watch

About Help Legal

You might also like