What is the different between the following two executions?
Mono.justOrEmpty(someFunction())
.doOnNext(() -> doSomeTask()).subscribe();
Mono.fromCallable(() -> someFunction())
.doOnNext(() -> doSomeTask()).subscribe();
With Mono.fromCallable, the Callable is called lazily only when the resulting Mono is subscribed to.
(you can even rewrite your snippet to Mono.fromCallable(this::someFunction) if someFunction doesn't take any parameter)
With Mono.justOrEmpty, the value is captured immediately by the operator for future emission. So in effect here the someFunction() method is called immediately at construction.
Note that both of these variants will correctly deal with someFunction() returning null (unlike Mono.just(...)). In that case, the resulting Mono will simply complete (onComplete signal without onNext).
Note also that if the method is blocking and long running, it might be an antipattern in both cases. See https://projectreactor.io/docs/core/release/reference/#faq.wrap-blocking
Basically using Mono.fromCallable() Callable emits the resulting value as Mono. Mono.justOrEmpty() only emits the specified item as Mono if it exists.
In the official docs justOrEmpty and fromCallable are described as follows:
Mono.justOrEmpty()
Create a new Mono that emits the specified item if non null otherwise only emits onComplete.
Mono.fromCallable()
Create a Mono producing its value using the provided Callable. If the Callable resolves to null, the resulting Mono completes empty.
If you need more detailed information about Mono, you can check the official documentation.
With Mono.fromCallable, someFunction will be called when a subscription is made.
private static Integer someFunction() {
System.out.println("calling someFunction");
return 1;
}
public static void main(String[] args) {
Mono<Integer> mono = Mono.fromCallable(ReactorApp2::someFunction)
.doOnNext(System.out::println);
System.out.println("Subscribing...");
mono.subscribe();
mono.subscribe();
}
/*
Subscribing...
calling someFunction
1
calling someFunction
1
*/
With Mono.justOrEmpty, someFunction will be called only once.
private static Integer someFunction() {
System.out.println("calling someFunction");
return 1;
}
public static void main(String[] args) {
Mono<Integer> mono = Mono.justOrEmpty(someFunction())
.doOnNext(System.out::println);
System.out.println("Subscribing...");
mono.subscribe();
mono.subscribe();
}
/*
calling someFunction
Subscribing...
1
1
*/
Related
I have a bit more complex use case in Spring Gateway which is based on WebFlux and I ran into small issue with Mono usage. Long story short, my switchIfEmpty is called even if not required. I prepared small example which allows me to reproduce this problem:
public class ReactiveTest {
#Test
void test1() {
isOdd(2)
.flatMap(this::onNotEmpty)
.switchIfEmpty(Mono.defer(this::onEmpty))
.block();
}
Mono<String> isOdd(Integer number) {
return number % 2 != 0 ? Mono.just("Yes") : Mono.empty();
}
Mono<Void> onNotEmpty(String value) {
System.out.println("Value uppercased " + value.toUpperCase());
return Mono.empty();
}
Mono<Void> onEmpty() {
System.out.println("Value not present, this shouldn't been called if value was odd");
return Mono.empty();
}
}
I hope this is pretty self-explanatory, but just to be safe:
isOdd(Integer number) may produce Mono with data or empty Mono
I expect onNotEmpty to be called only if previous Mono had data
I expect onEmpty to be called only if isOdd produced empty Mono
Unfortunatelly, both onNotEmpty and onEmpty are called all the time, regardless if I pass odd or even number to isOdd.
How can I make sure that onEmpty is called only when isOdd produced Mono.empty()?
The onNotEmpty(String value) method is always returning Mono.empty(), meaning that .switchIfEmpty(Mono.defer(this::onEmpty)) will always be call either because isOdd(2) is already an empty Mono or because onNotEmpty(String value) method was called and returned an empty Mono.
In order to avoid this, you need to change your onNotEmpty(String value) method to return something else than an empty Mono.
Additionally, please avoid using block() since this defeats the whole purpose of using Spring WebFlux by blocking the thread waiting for something to be emitted by the reactive chain.
It's a simplified function.
It keeps returning 0 while I expect this to return 5. How come?
public int accessKey() {
a = 0;
mSubscription = mAccountManager.getLoginPassword()
.flatMap(loginPassword -> mServerAPI
.getProfilesList((new BaseRequest(
loginPassword.getLogin(),
loginPassword.getPassword(),
ClientGetter.getClientFromManager(),
CodeSnippets.getSha256(ClientGetter.getClientFromManager()))
)))
.doOnNext(profilesListe -> mProfilesList = profilesListe.getItems())
.observeOn(AndroidSchedulers.mainThread())
.subscribeOn(Schedulers.io())
.subscribe(new Subscriber<BaseResponse>() {
#Override
public void onCompleted() {
a =5;
}
return a; }
It's because of the asynchronous or non blocking behaviour , Normally during the scenarios of API calls fetching some data from database ,these behaviours we handle asynchronously,because otherwise your application will get stuck This post will help you to solve this matter. Refer this
you're executing an asynchronous operation here. your code doesn't execute "top down" here but will be executed on a different thread - Rxjava shifts this entire operation over to another thread and then returns the result to the thread specified, but this doesn't happen immediately. by the time your subscribe code has executed (we don't know when that will be) your return statement has already executed.
you could try change your code to something like this (just as an idea, i don't have any code similar to yours to create a working example):
return mAccountManager.getLoginPassword()
.flatMap(loginPassword -> mServerAPI
.getProfilesList((new BaseRequest(
loginPassword.getLogin(),
loginPassword.getPassword(),
ClientGetter.getClientFromManager(),
CodeSnippets.getSha256(ClientGetter.getClientFromManager()))
)))
.doOnNext(profilesListe -> mProfilesList = profilesListe.getItems())
.observeOn(AndroidSchedulers.mainThread())
.subscribeOn(Schedulers.io())
this means that your method will now return an observable, which you can then subscribe on and subscribe to those changes where they are used.
this means that the signature of your method will have to change to support this new return type and the calling method will have to subscribe to this observable.
you describe your question as a simplified function, but I'll give you an even simpler (complete) example:
public Observable<Integer> foo() {
return Observable.just(5);
}
public void usage(){
Disposable disposable = foo().subscribeOn(something).observeOn(something).subscribe(
//inside this subscribe, like you'd normally do, you'd find the result of 5
)
...
//handle disposable
}
I used the Callback interface method and it worked! Many thanks
I have a method that sends asynchronously a list of messages. Each send returns ApiFuture<String> (GCP version of Guava's ListenableFuture). I need this method to return one Future<Boolean>, so I
Create a list dependency on each ApiFuture<String>
Transform the resulting ApiFuture<List<String>> to a Future<Boolean> using ApiFutures.transform method
ApiFuture< List < String > > allSentFuture = ApiFutures.allAsList(futures);
return ApiFutures.transform(allSentFuture, val -> {
return true;
},
Executors.newCachedThreadPool()
);
My question is: what is the value of val argument of the lambda above if one or more of the original futures are failed/cancelled? Is the lambda even called in this case?
Thanks!
ApiFuture<V> forms a monad over the type V, and transform applies a function to the encapsulated value of type V. If the ApiFuture<V> does not contain a V value because it is failed or cancelled, then the transformed future is the same.
If you want to handle failures due to exceptions, you can use ApiFutures.catching() to produce an alternative result (e.g. Boolean.FALSE) instead.
If you want to transform cancellation into a successful value, I believe you would need to use ApiFuture.addListener directly, and have the listener complete a SettableApiFuture which you return. Then the listener (which will get called when the source future is cancelled) can check isCancelled to detect this case, or can catch and handle the CancellationException.
For example:
/**
* Adapt an iterable of {#link ApiFuture} instances into a single {#code ApiFuture}.
*/
static <T> ApiFuture<Boolean> adaptFutures(Iterable<ApiFuture<T>> futures) {
final SettableApiFuture<Boolean> result = SettableApiFuture.create();
final ApiFuture<List<T>> allFutures = ApiFutures.allAsList(futures);
allFutures.addListener(
() -> {
if (allFutures.isCancelled()) {
result.set(Boolean.FALSE);
return;
}
try {
allFutures.get();
result.set(Boolean.TRUE);
} catch (ExecutionException | InterruptedException ex) {
// Maybe log something here?
//
// Note that InterruptedException is actually impossible here
// because we're running in the listener callback, but the API
// still marks it as potentially thrown by .get() above.
//
// So if we reach here it means that the allAsList future failed.
result.set(Boolean.FALSE);
}
},
// Not normally safe, but we know our listener runs fast enough
// to run inline on the thread that completes the last future.
Runnable::run);
return result;
}
can someone let me know how the below program works internally:
public class Main {
public static void main(String[] args) {
Consumer<String> c = (x) -> System.out.println(x.toLowerCase());
c.andThen(c).andThen(c).accept("Java2s.com");
}
}
Did you look at the code of andThen?
default Consumer<T> andThen(Consumer<? super T> after) {
Objects.requireNonNull(after);
return (T t) -> { accept(t); after.accept(t); };
}
It's creating a new Consumer for each call to andThen, finally at the end invoking the accept method (which is the only abstract one).
How about a different approach:
Consumer<String> first = x -> System.out.println(x.toLowerCase());
Consumer<String> second = y -> System.out.println("aaa " + y);
Consumer<String> result = first.andThen(second);
Running this code is not going to produce anything, since you have not invoked accept anywhere just yet.
On the other hand, you can see what happens when calling accept on each other:
Consumer<String> result = first.andThen(second);
first.accept("Java"); // java
second.accept("Java"); // aaa Java
System.out.println("---------");
result.accept("Java"); // java, aaa Java
andThen returns a composition of this Consumer with the next one.
the documentation Consumer#andThen says:
Returns a composed Consumer that performs, in sequence, this operation followed by the after operation. If performing either operation throws an exception, it is relayed to the caller of the composed operation. If performing this operation throws an exception, the after operation will not be performed.
which means your consumer will be accepted 3 times, like as:
v--- 1. c.accept("Java2s.com");
c.andThen(c).andThen(c).accept("Java2s.com");
^ ^
| |
| 3. c.accept("Java2s.com");
|
2. c.accept("Java2s.com");
Suppose I have the following RxJava code (which accesses a DB, but the exact use case is irrelevant):
public Observable<List<DbPlaceDto>> getPlaceByStringId(final List<String> stringIds) {
return Observable.create(new Observable.OnSubscribe<List<DbPlaceDto>>() {
#Override
public void call(Subscriber<? super List<DbPlaceDto>> subscriber) {
try {
Cursor c = getPlacseDb(stringIds);
List<DbPlaceDto> dbPlaceDtoList = new ArrayList<>();
while (c.moveToNext()) {
dbPlaceDtoList.add(getDbPlaceDto(c));
}
c.close();
if (!subscriber.isUnsubscribed()) {
subscriber.onNext(dbPlaceDtoList);
subscriber.onCompleted();
}
} catch (Exception e) {
if (!subscriber.isUnsubscribed()) {
subscriber.onError(e);
}
}
}
});
}
Given this code, I have the following questions:
If someone unsubscribes from the observable returned from this method (after a previous subscription), is that operation thread-safe? So are my 'isUnsubscribed()' checks correct in this sense, regardless of scheduling?
Is there a cleaner way with less boilerplate code to check for unsubscribed states than what I'm using here? I couldn't find anything in the framework. I thought SafeSubscriber solves the issue of not forwarding events when the subscriber is unsubscribed, but apparently it does not.
is that operation thread-safe?
Yes. You are receiving an rx.Subscriber which (eventually) checks against a volatile boolean that is set to true when the subscriber's subscription is unsubscribed.
cleaner way with less boilerplate code to check for unsubscribed states
The SyncOnSubscribe and the AsyncOnSubscribe (available as an #Experimental api as of release 1.0.15) was created for this use case. They function as a safe alternative to calling Observable.create. Here is a (contrived) example of the synchronous case.
public static class FooState {
public Integer next() {
return 1;
}
public void shutdown() {
}
public FooState nextState() {
return new FooState();
}
}
public static void main(String[] args) {
OnSubscribe<Integer> sos = SyncOnSubscribe.createStateful(FooState::new,
(state, o) -> {
o.onNext(state.next());
return state.nextState();
},
state -> state.shutdown() );
Observable<Integer> obs = Observable.create(sos);
}
Note that the SyncOnSubscribe next function is not allowed to call observer.onNext more than once per iteration nor can it call into that observer concurrently. Here are a couple of links to the SyncOnSubscribe implementation and tests on the head of the 1.x branch. It's primary usage is to simplify writing observables that iterate or parsing over data synchronously and onNext downstream but doing so in a framework that supports back-pressure and checks if unsubscribed. Essentially you would create a next function which would get invoked every time the downstream operators need a new data element onNexted. Your next function can call onNext either 0 or 1 time.
The AsyncOnSubscribe is designed to play nicely with back pressure for observable sources that operate asynchronously (such as off-box calls). The arguments to your next function include the request count and your provided observable should provide an observable that fulfills data up to that requested amount. An example of this behavior would be paginated queries from an external datasource.
Previously it was a safe practice to transform your OnSubscribe to an Iterable and use Observable.from(Iterable). This implementation gets an iterator and checks subscriber.isUnsubscribed() for you.