I have these two methods which call an async API and return a Mono<Boolean> if a value exists. I am returning a random boolean value for the sake of this example,
private Mono<Boolean> checkFirstExists() {
// Replacing actual API call here
return Mono.just(Boolean.FALSE);
}
private Mono<Boolean> checkSecondExists() {
// Replacing actual API call here
return Mono.just(Boolean.TRUE);
}
Now, I have another method that should combine the results of these two methods and simply return a boolean if either checkFirstExists or checkSecondExists is true.
private boolean checkIfExists() {
// Should return true if any of the underlying method returns true
final Flux<Boolean> exists = Flux.concat(checkFirstExists(), checkSecondExists());
return exists.blockFirst();
}
What's the best way of doing this? Mono.zip maybe? Any help would be great.
Mono.zip is the correct approach for awaiting completion of multiple async operations before continuing. Something like this should work:
return Mono.zip(checkFirstExists(), checkSecondExists(), (first, second) -> first && second);
Or if a list is provided instead:
private boolean checkIfExists()
{
return allTrue(Arrays.asList(checkFirstExists(), checkSecondExists())).blockOptional().orElseThrow(() -> new IllegalStateException("Invalid State"));
}
private Mono<Boolean> allTrue(List<Mono<Boolean>> toAggregate)
{
return mergeMonos(toAggregate).map(list -> list.stream().allMatch(val -> val));
}
#SuppressWarnings("unchecked")
private <T> Mono<List<T>> mergeMonos(List<Mono<T>> toAggregate)
{
return Mono.zip(toAggregate, array -> Stream.of(array).map(o -> (T) o).collect(Collectors.toList()));
}
Unrelated Note:
In general, it is worth keeping the operation async as long as possible when constructing reactive flows. It may be worth having the 'checkIfExists' function return a Mono instead of blocking.
Related
I try to make a code more compact by coding a helper method, because the code is very repetitive.
The code consists of:
call a command (remote ssh, or local command, this part is not interesting for my question)
check if it was a success
if not, stop here and return the return code to the calling method (i.e. return cr;)
if success, continue with another command
I tried to create a helper method that do all that. If the command execution is a failure, it will return an Optional<Integer> of the return code. If it works as expected, it returns a Optional.empty().
My question is how to do something like that:
public void topMethod()
{
int cr = execCmds();
... do stuff with cr ...
}
private int execCmds()
{
executeCmd("my command").ifPresent(cr -> return cr);
executeCmd("my next command").ifPresent(cr -> return cr);
....
return 0;
}
As you can see, I want to stop the flow if the return code is meaningful. If not it must continue. Is there a way to do that? (Something concise.)
For information, the return cr is invalid in the ifPresent lambda method.
Use Optional.or()
Optional.or() was introduced with JDK 9, and expects a Supplier of Optional.
In a nutshell, method or() checks whether the Optional on which it is applied is empty, and if that's the case it replaces it with another optional. otherwise, if value is present, it would return the same optional (i.e. Supplier passed as an argument wouldn't be executed, functions are evaluated lazily).
public void topMethod() {
int cr = execCmds();
// do something with cr
}
private int execCmds() {
return executeCmd("my command")
.or(() -> executeCmd("my next command"))
.or(...) // more alternatives
.orElse(0);
}
public Optional<Integer> executeCmd(String command) {
return // something;
}
Stream of Suppliers
Another option would be to create a Stream of Supplier of Optional.
It can be useful if you're using JDK 8 (and therefor can't use or), or if executeCmd() returns an OptionalInt which lacks method or().
Stream would process each Supplier lazily, one at a time, and As well as in the previous solution each executeCmd() invocation would occur only if needed (if the previous command failed to provide the result).
Here's how it can be implemented:
public void topMethod() {
int cr = execCmds();
// do something with cr
}
private int execCmds() {
return Stream.<Supplier<OptionalInt>>of(
() -> executeCmd("my command"),
() -> executeCmd("my next command")
// ...
) // Stream<Supplier<OptionalInt>>>
.map(Supplier::get) // Stream<<OptionalInt>>
.filter(OptionalInt::isPresent) // Stream<<OptionalInt>>
.mapToInt(OptionalInt::getAsInt) // IntStream
.findFirst() // OptionalInt
.orElse(0);
}
public OptionalInt executeCmd(String command) {
return // something;
}
Would chaining your commands with or work? Something like
private int execCmds()
{
return executeCmd("command one")
.or(() -> executeCmd("command two")
.or(() -> executeCmd("command three")
.orElse(0);
}
I am using the Single RxJava object and I want to run a void method in the critical path of the async workflow but return the previous result.
For example, I have something like:
Single<Integer> method() {
Single<Integer> value = Single.just(10);
return value.<RxJava Method>(Consumer<Integer> or Runnable<Integer>);
}
method().blockingGet();
returns
> 10
The stuff I do in Consumer<Integer> or Runnable<Integer>, I want to make sure happens before I return the value 10. Is there a built in method in Single for this?
ie: I am just wondering if there is a cleaner way to portray:
Single<Integer> method() {
Single<Integer> value = Single.just(10);
return value.map(result -> {
// call void method
return result;
});
}
method().blockingGet();
I understand you can't return from a ifPresent() so this example does not work:
public boolean checkSomethingIfPresent() {
mightReturnAString().ifPresent((item) -> {
if (item.equals("something")) {
// Do some other stuff like use "something" in API calls
return true; // Does not compile
}
});
return false;
}
Where mightReturnAString() could return a valid string or an empty optional. What I have done that works is:
public boolean checkSomethingIsPresent() {
Optional<String> result = mightReturnAString();
if (result.isPresent()) {
String item = result.get();
if (item.equals("something") {
// Do some other stuff like use "something" in API calls
return true;
}
}
return false;
}
which is longer and does not feel much different to just checking for nulls in the first place. I feel like there must be a more succinct way using Optional.
I think all you're looking for is simply filter and check for the presence then:
return result.filter(a -> a.equals("something")).isPresent();
How about mapping to a boolean?
public boolean checkSomethingIfPresent() {
return mightReturnAString().map(item -> {
if (item.equals("something")) {
// Do some other stuff like use "something" in API calls
return true; // Does not compile
}
return false; // or null
}).orElse(false);
}
While #nullpointer and #Ravindra showed how to merge the Optional with another condition, you'll have to do a bit more to be able to call APIs and do other stuff as you asked in the question. The following looks quite readable and concise in my opinion:
private static boolean checkSomethingIfPresent() {
Optional<String> str = mightReturnAString();
if (str.filter(s -> s.equals("something")).isPresent()) {
//call APIs here using str.get()
return true;
}
return false;
}
A better design would be to chain methods:
private static void checkSomethingIfPresent() {
mightReturnFilteredString().ifPresent(s -> {
//call APIs here
});
}
private static Optional<String> mightReturnFilteredString() {
return mightReturnAString().filter(s -> s.equals("something"));
}
private static Optional<String> mightReturnAString() {
return Optional.of("something");
}
The ideal solution is “command-query separation”: Make one method (command) for doing something with the string if it is present. And another method (query) to tell you whether it was there.
However, we don’t live an ideal world, and perfect solutions are never possible. If in your situation you cannot separate command and query, my taste is for the idea already presented by shmosel: map to a boolean. As a detail I would use filter rather than the inner if statement:
public boolean checkSomethingIfPresent() {
return mightReturnAString().filter(item -> item.equals("something"))
.map(item -> {
// Do some other stuff like use "something" in API calls
return true; // (compiles)
})
.orElse(false);
}
What I don’t like about it is that the call chain has a side effect, which is not normally expected except from ifPresent and ifPresentOrElse (and orElseThrow, of course).
If we insist on using ifPresent to make the side effect clearer, that is possible:
AtomicBoolean result = new AtomicBoolean(false);
mightReturnAString().filter(item -> item.equals("something"))
.ifPresent(item -> {
// Do some other stuff like use "something" in API calls
result.set(true);
});
return result.get();
I use AtomicBoolean as a container for the result since we would not be allowed to assign to a primitive boolean from within the lambda. We don’t need its atomicity, but it doesn’t harm either.
Link: Command–query separation on Wikipedia
By the way if you really want to get value from Optional, use:
Optional<User> user = service.getCurrentUset();
return user.map(User::getId);
I have a sequence of methods that I need to run sequentially, using the result of each method as a parameter in the next. However, I also check that the result of each method is "good" before calling the next method (if it's "bad" then I exit the method early. The methods return an empty Optional if they were not successful.
Is there a refactoring that I can perform to improve the code? Chain of Responsibility feels a little overboard.
private boolean isSequenceSuccessful() {
Optional<byte[]> result1 = doSomething();
if (!result1.isPresent()) {
return false;
}
Optional<byte[]> result2 = doAnotherThing(result1.get());
if (!result2.isPresent()) {
return false;
}
Optional<byte[]> result3 = doSomethingElse(result2.get());
if (!result3.isPresent()) {
return false;
}
return doMoreStuff(result3.get());
}
I don't want to use Exceptions to control the flow of the method because that's a code smell (I expect to sometimes get "bad" results).
You can write it shorter using Optional and mapping:
private boolean isSequenceSuccessful() {
return Optional.of(doSomething())
.flatMap(result1 -> doAnotherThing(result1))
.flatMap(result2 -> doSomethingElse(result2))
.map(result3 -> doMoreStuff(result3))
.orElse(false);
}
Or using method references even shorter:
private boolean isSequenceSuccessful2() {
return Optional.of(doSomething())
.flatMap(this::doAnotherThing)
.flatMap(this::doSomethingElse)
.map(this::doMoreStuff)
.orElse(false);
}
It depends what you prefer. If you want to keep the intermediate result variables use the lambda version.
Since the methods doAnotherThing and doSomethingElse do return an Optional<byte[]>, Optional.flatMap is needed to continue the mapping. Otherwise you could change the return type of these methods to return byte[] solely. Then you would use Optinal.map only, which would be more consistent.
The mapping will only be performed as long as a value is present in the Optional. If all mappings could be applied the value of the last is returned as result. Otherwise the processing will fail fast and bypass all remainig mappings to the last statement orElse and return it's value. This is false according to your code.
You could use the map method:
private boolean isSequenceSuccessful() {
Optional<byte[]> result = doSomething().map(this::doAnotherThing)
.map(this::doSomethingElse);
if (result.isPresent()) return doMoreStuff(result.get());
else return false;
}
Look at the template pattern which I sometimes refer to as the pizza pattern because it is analogous to making a pizza. (eg. createDough(), putIngredients(), bake(), package(), deliver()). This might apply to your case. There are several examples and implementations out there but pick and choose which applies best to you. In your example above, I would create an abstract class and create concrete classes/implementations. Example to give you an idea:
public abstract class SequenceChecker {
// ...
public boolean isSequenceSuccessful() {
Optional<byte[]> result1 = doSomething();
Optional<byte[]> result2 = doAnotherThing(result1);
Optional<byte[]> result3 = doSomethingElse(result2);
return doMoreStuff(result3);
}
protected abstract boolean doMoreStuff(Optional<byte[]> result);
protected abstract Optional<byte[]> doSomethingElse(Optional<byte[]> result);
protected abstract Optional<byte[]> doAnotherThing(Optional<byte[]> result);
protected abstract Optional<byte[]> doSomething();
// ...
}
Use Optional::flatMap.
private boolean isSequenceSuccessful() {
Optional<Boolean> result = doSomething()
.flatMap(this::doAnotherThing)
.flatMap(this::doSomethingElse)
.map(this::doMoreStuff);
return result.isPresent() ? result.get() : false;
}
I want my code to repeat a certain asynchronous operation until this operation is successful (i.e. until it returns true).
At the moment I'm using the following workaround:
Supplier<Observable<Boolean>> myOperation = () -> {
// do something useful and return 'true' if it was successful
// NOTE: GENERATING A RANDOM NUMBER IS JUST AN EXAMPLE HERE
// I WANT TO RUN AN ASYNCHRONOUS OPERATION (LIKE PINGING A SERVER
// OR THE LIKE) AND RETRY IT UNTIL IT SUCCEEDS.
System.out.println("Try");
return Observable.just(Math.random() > 0.9);
};
final Throwable retry = new IllegalStateException();
Observable.<Boolean>create(subscriber -> {
myOperation.get().subscribe(subscriber);
}).flatMap(b -> b ? Observable.just(b) : Observable.error(retry))
.retryWhen(exceptions -> exceptions.flatMap(exception -> {
if (exception == retry) {
return Observable.timer(1, TimeUnit.SECONDS);
}
return Observable.error(exception);
}))
.toBlocking()
.forEach(b -> {
System.out.println("Connected.");
});
It works well and prints out something like this:
Try
Try
...
Try
Connected.
The code does what I want, but it doesn't look very elegant. I'm sure there must be a better way. Maybe by using a custom Operator?
Does anybody know how to achieve the same thing in RxJava but in a more readable manner and without the artificial Throwable?
Not enough time, so this is going to be by memory...
public class Randomizer implements Iterable<Double>, Iterator<Double> {
public Iterator<Double> getIterator() {return this;}
public boolean hasNext() {return true;}
public Double next() {return Math.random();}
}
...
Observable.from(new Randomizer())
.takeWhile(value -> value < 0.99);
// or takeUntil(value -> value > 0.99); can't remember their differences.
OTOH if you need to do something more complex, look into Observable.defer() and / or a BehaviorSubject.
Edit: Now there's a bit more time to read your post, you could try something like this:
Observable.defer(() -> createConnectionObservable())
.retry((count, err) -> {
if(count>9) return false;
if(!(err instanceof IOException)) return false;
return true;
})
Keep in mind that if you use Retrofit you shouldn't need defer(), as retrofit will re-initiate the call when a new subscription happens.