Based on post type i need to push item to observable list. So in case when if closure is not used (for example post.type != SomeType) my observable list is empty.
So due to that im receiving NoSuchElementException all the time from Single.zip
Here is my sample code
val observableList = mutableListOf<Single<Response>>()
if (post.type == SomeType) {
observableList.add(addNewObservable()) <-- adding API call to the lsit
}
return Single.zip(observableList) { arg -> arg } <-- Throws error NoSuchElementException
I figured that i can use for post type != SomeType :
observableList.add(Single.just(Response(""))
And this will work fine.
So is there a better solution for it? How can i avoid that error?
If your list can legitimately be empty, maybe you want a Maybe instead of Single. One way would be
val observableList = mutableListOf<Maybe<Response>>()
...
if (post.type == SomeType) {
observableList.add(addNewObservable().toMaybe())
}
...
return Maybe.zip(observableList) { arg -> arg }
Maybe.zip on an empty list should return a Maybe which completes immediately without emitting anything.
Or an alternate solution: just test if the list is empty before calling Single.zip.
It really depends on what behavior you want (except for not throwing an exception) in the first place.
You need to provide a check for emptiness beforehand. This can be done for an Observable or a Single.
public Observable<String> zipObservable(List<Observable<String>> strings) {
return strings.isEmpty()
? Observable.just("empty")
: Observable
.zip(strings, objects -> "non-empty");
}
public Single<String> zipSingle(List<Single<String>> strings) {
return strings.isEmpty()
? Single.just("empty")
: Single
.zip(strings, objects -> "non-empty");
}
Related
I have this bulider method:
public static QuoteDetails quoteDetailsForMA(String response) {
handleErrors(response);
try {
FullResponse quoteDetails = extractResponse(response);
Summary summary = summaryMA(quoteDetails);
List<PenaltyElement> penalties = retrievePenalties(quoteDetails);
return QuoteDetails.builder()
.priceSummary(summary)
.penalties(penalties)
.build();
} catch (Exception e) {
LOGGER.error(
"Exception thrown response: {}",
e.getMessage());
}
}
penalties may or may not be an empty list. If it is not empty I wish to execute the return statement as it currently is(with .penalties(penalties). However, If penalties is an empty list I wish to exclude it from my return. E.g. I wish to return this:
return QuoteDetails.builder()
.priceSummary(summary)
.build();
Is this possible and if so, how is it done?
The easiest technique is to make the .penalties(penalties)
method null and empty list tolerant.
Note, the authors of both of the other answers appear to love NullPointerExceptions.
Here is some example code (with assumptions):
private List<Penalty> penaltiesList;
public QuoteDetailsBuilder penalties(final List<Penalty> newValue)
{
if (CollectionUtils.isNotEmpty(newValue))
{
penaltiesList = newValue;
}
return this;
}
CollectionUtils is an apache utility for some null-safe collection functionality.
You can do it via the isEmpty() method to see if it's empty or not:
.penalties(penalties.isEmpty() ? null : penalties)
Two "obvious" solutions come to my mind:
The builder supports an empty list in the correct way. You could maybe implement your own builder to do that which is just a wrapper around the original and doesn't call the original method penalties if the parameter is an empty list.
Use if as you would regularly do for "conditional" handling:
QuoteDetailsBuilder builder = QuoteDetails.builder()
.priceSummary(summary);
if ((null != penalties) && !penalties.isEmpty()) {
builder = builder.penalties(penalties);
}
return builder.build();
(Of course in solution #2 the name of the builder class may vary depending on the implementation.)
I am using Java 11 and project Reactor (from Spring). I need to make a http call to a rest api (I can only make it once in the whole flow).
With the response I need to compute two things:
Check if a document exists in the database (mongodb). If it does not exists then create it and return it. Otherwise just return it.
Compute some logic on the response and we are done.
In pseudo code it is something like this:
public void computeData(String id) {
httpClient.getData(id) // Returns a Mono<Data>
.flatMap(data -> getDocument(data.getDocumenId()))
// Issue here is we need access to the data object consumed in the previous flatMap but at the same time we also need the document object we get from the previous flatMap
.flatMap(document -> calculateValue(document, data))
.subscribe();
}
public Mono<Document> getDocument(String id) {
// Check if document exists
// If not create document
return document;
}
public Mono<Value> calculateValue(Document doc, Data data) {
// Do something...
return value;
}
The issue is that calculateValue needs the return value from http.getData but this was already consumed on the first flatMap but we also need the document object we get from the previous flatMap.
I tried to solve this issue using Mono.zip like below:
public void computeData(String id) {
final Mono<Data> dataMono = httpClient.getData(id);
Mono.zip(
new Mono<Mono<Document>>() {
#Override
public void subscribe(CoreSubscriber<? super Mono<Document>> actual) {
final Mono<Document> documentMono = dataMono.flatMap(data -> getDocument(data.getDocumentId()))
actual.onNext(documentMono);
}
},
new Mono<Mono<Value>>() {
#Override
public void subscribe(CoreSubscriber<? super Mono<Value>> actual) {
actual.onNext(dataMono);
}
}
)
.flatMap(objects -> {
final Mono<Document> documentMono = objects.getT1();
final Mono<Data> dataMono = objects.getT2();
return Mono.zip(documentMono, dataMono, (document, data) -> calculateValue(document, data))
})
}
But this is executing the httpClient.getData(id) twice which goes against my constrain of only calling it once. I understand why it is being executed twice (I subscribe to it twice).
Maybe my solution design can be improved somewhere but I do not see where. To me this sounds like a "normal" issue when designing reactive code but I could not find a suitable solution to it so far.
My question is, how can accomplish this flow in a reactive and non blocking way and only making one call to the rest api?
PS; I could add all the logic inside one single map but that would force me to subscribe to one of the Mono inside the map which is not recommended and I want to avoid following this approach.
EDIT regarding #caco3 comment
I need to subscribe inside the map because both getDocument and calculateValue methods return a Mono.
So, if I wanted to put all the logic inside one single map it would be something like:
public void computeData(String id) {
httpClient.getData(id)
.map(data -> getDocument(data).subscribe(s -> calculateValue(s, data)))
.subscribe();
}
You do not have to subscribe inside map, just continue building the reactive chain inside the flatMap:
getData(id) // Mono<Data>
.flatMap(data -> getDocument(data.getDocumentId()) // Mono<Document>
.switchIfEmpty(createDocument(data.getDocumentId())) // Mono<Document>
.flatMap(document -> calculateValue(document, data)) // Mono<Value>
)
.subscribe()
Boiling it down, your problem is analogous to:
Mono.just(1)
.flatMap(original -> process(original))
.flatMap(processed -> I need access to the original value and the processed value!
System.out.println(original); //Won't work
);
private static Mono<String> process(int in) {
return Mono.just(in + " is an integer").delayElement(Duration.ofSeconds(2));
}
(Silly example, I know.)
The problem is that map() (and by extension, flatMap()) are transformations - you get access to the new value, and the old one goes away. So in your second flatMap() call, you've got access to 1 is an integer, but not the original value (1.)
The solution here is to, instead of mapping to the new value, map to some kind of merged result that contains both the original and new values. Reactor provides a built in type for that - a Tuple. So editing our original example, we'd have:
Mono.just(1)
.flatMap(original -> operation(original))
.flatMap(processed -> //Help - I need access to the original value and the processed value!
System.out.println(processed.getT1()); //Original
System.out.println(processed.getT2()); //Processed
///etc.
);
private static Mono<Tuple2<Integer, String>> operation(int in) {
return Mono.just(in + " is an integer").delayElement(Duration.ofSeconds(2))
.map(newValue -> Tuples.of(in, newValue));
}
You can use the same strategy to "hold on" to both document and data - no need for inner subscribes or anything of the sort :-)
I have a REST Controller
#GetMapping("/getByClientId/{clientId}")
public ResponseEntity<Optional<List<EquityFeeds>>> getByClientId(#PathVariable("clientId") final String clientId) {
Optional<List<EquityFeeds>> cId = Optional.ofNullable(equityFeedsService.findByClientId(clientId));
System.out.println("Client Id: "+cId);
if(cId.isPresent()) {
return ResponseEntity.ok(cId);
} else {
cId.orElseThrow(() -> new ClientIdNotFoundException(clientId));
}
return ResponseEntity.ok(cId);
}
Service Class Code:
public List<EquityFeeds> findByClientId(String clientId) {
List<EquityFeeds> cId = equityFeedsRedisRepositoryImpl.findByClientId(clientId);
System.out.println("In EquityFeedService "+cId);
return cId;
}
Impl. Code (REDIS):
public List<EquityFeeds> findByClientId(String clientId) {
return (List<EquityFeeds>) listOperations.range(clientId, 0, -1);
}
Issue:
1) When the getClientId is called using a REST Controller and the clientId is not present in the REDIS Cache then:
Service class Code returns: In EquityFeedService []
The REST Controller returns: Client Id: Optional[[]]
In the REST Controller the code goes inside the if loop and displays nothing on the screen since the List is empty i.e.
if(cId.isPresent()) {
return ResponseEntity.ok(cId);
}
Why? Why cId.isPresent() returns true and the code goes inside the if loop. Ideally the code should go inside the else loop and throw an Exception since the List is empty. This is happening in case of List only it seems as my other method which has a return type of POJO doesn't have this issue.
Please help me understand this behavior and what should be done to fix this.
cId.isPresent() return true because
List<EquityFeeds> is not null , it's empty list
if(!cId.get().isEmpty()) {
return ResponseEntity.ok(cId);
} else {
throw new ClientIdNotFoundException(clientId);
}
The reason the Optional.isPresent returns true is that there is an actual value - an empty List. The Optional checks whether the value it holds is a null or not, nothing else. The isPresent checks whether the value is present inside the Optional, not inside the List itself.
So you have to treat Optional a bit different. Moreover, don't use Optional like that as substitution to the if-else constructs.
Here is a way to go:
return cId.filter(Predicate.not(List::Empty)) // if the list is not empty
.map(ResponseEntity::ok) // create a response
.orElseThrow(() -> // or else throw an exception
new ClientIdNotFoundException(clientId));
By the way, you don't want to return Optional wrapped inside the ResponseEntity. Unwrap it and return the List itself. If it is empty or null was already handled and the exception would be thrown first.
return cId.filter(Predicate.not(List::Empty))
.map(Optional::get) // exctract from the Optional
.map(ResponseEntity::ok)
.orElseThrow(() -> new ClientIdNotFoundException(clientId));
So I have a method which returns an Vavr Try:
public Try<Result> request() {...}
request comes from a source which I cannot modify. Currently, I flatmap over the result from request and depending if the Result has an error return a Try with an exception or a success with the data from the Result:
public Try<Data> fetchData() {
return request().flatMap(result -> {
if (result.hasError()) {
return Try.failure(new FailedRequestException());
} else {
return Try.success(result.data());
}
});
}
What I want is in some places where fetchData is used first do something with the data if the Try is a success and if it is a failure, log an error if the error is a FailedRequestException, else, do something else with the exception, something like the following:
fetchData().andThen(data -> ...).onFailure(ex -> {
if (ex instanceOf FailedRequestException) {
log.error("Could not fetch data: " + ex.getMessage());
} else {
// Do something with the exception
...
}
});
My problem with this approach is that fetchData returns a Try so the caller cannot know that a FailedRequestException is part of the possible failures. I can let fetchData return a Try<Either<FailedRequestException, Data>> but this doesn't feel right either. Is there any way to do the above in a more elegant way? I also tried using the Match and Case but the Case expects a Function as handler and not a Consumer.
To sum up: you actually have 3 scenarios (success, failure with FailedRequestException, any other failure). This sounds like a job for pattern matching! Let's make the code as visible and expressive as the business requirement :)
Match(fetchData()).of(
Case($Success($()), data -> doStuff(data)),
Case($Failure($(instanceOf(FailedRequestException.class))), fre -> logFreAndReturnValue(fre)),
Case($Failure($()), e -> doSomethingWithOtherException(e))
);
FWIW, you can rewrite your fetchData implementation as such:
Try(request())
.mapFailure(Case($(), ignored -> new FailedRequestException()))
.map(Result::data);
As a rule of thumb, try to stick to using flatMap when the context (Success or Failure) may change. In your current fetchData implementation a success remains a success, a failure remains a failure, so it is a mapping between the input and the output, hence use map family of functions.
Cheers!
When using external iteration over an Iterable we use break or return from enhanced for-each loop as:
for (SomeObject obj : someObjects) {
if (some_condition_met) {
break; // or return obj
}
}
How can we break or return using the internal iteration in a Java 8 lambda expression like:
someObjects.forEach(obj -> {
//what to do here?
})
If you need this, you shouldn't use forEach, but one of the other methods available on streams; which one, depends on what your goal is.
For example, if the goal of this loop is to find the first element which matches some predicate:
Optional<SomeObject> result =
someObjects.stream().filter(obj -> some_condition_met).findFirst();
(Note: This will not iterate the whole collection, because streams are lazily evaluated - it will stop at the first object that matches the condition).
If you just want to know if there's an element in the collection for which the condition is true, you could use anyMatch:
boolean result = someObjects.stream().anyMatch(obj -> some_condition_met);
A return in a lambda equals a continue in a for-each, but there is no equivalent to a break. You can just do a return to continue:
someObjects.forEach(obj -> {
if (some_condition_met) {
return;
}
})
This is possible for Iterable.forEach() (but not reliably with Stream.forEach()). The solution is not nice, but it is possible.
WARNING: You should not use it for controlling business logic, but purely for handling an exceptional situation which occurs during the execution of the forEach(). Such as a resource suddenly stops being accessible, one of the processed objects is violating a contract (e.g. contract says that all the elements in the stream must not be null but suddenly and unexpectedly one of them is null) etc.
According to the documentation for Iterable.forEach():
Performs the given action for each element of the Iterable until all elements have been processed or the action throws an exception... Exceptions thrown by the action are relayed to the caller.
So you throw an exception which will immediately break the internal loop.
The code will be something like this - I cannot say I like it but it works. You create your own class BreakException which extends RuntimeException.
try {
someObjects.forEach(obj -> {
// some useful code here
if(some_exceptional_condition_met) {
throw new BreakException();
}
}
}
catch (BreakException e) {
// here you know that your condition has been met at least once
}
Notice that the try...catch is not around the lambda expression, but rather around the whole forEach() method. To make it more visible, see the following transcription of the code which shows it more clearly:
Consumer<? super SomeObject> action = obj -> {
// some useful code here
if(some_exceptional_condition_met) {
throw new BreakException();
}
});
try {
someObjects.forEach(action);
}
catch (BreakException e) {
// here you know that your condition has been met at least once
}
Below you find the solution I used in a project. Instead forEach just use allMatch:
someObjects.allMatch(obj -> {
return !some_condition_met;
});
Update with Java 9+ with takeWhile:
MutableBoolean ongoing = MutableBoolean.of(true);
someobjects.stream()...takeWhile(t -> ongoing.value()).forEach(t -> {
// doing something.
if (...) { // want to break;
ongoing.setFalse();
}
});
Either you need to use a method which uses a predicate indicating whether to keep going (so it has the break instead) or you need to throw an exception - which is a very ugly approach, of course.
So you could write a forEachConditional method like this:
public static <T> void forEachConditional(Iterable<T> source,
Predicate<T> action) {
for (T item : source) {
if (!action.test(item)) {
break;
}
}
}
Rather than Predicate<T>, you might want to define your own functional interface with the same general method (something taking a T and returning a bool) but with names that indicate the expectation more clearly - Predicate<T> isn't ideal here.
You can use java8 + rxjava.
//import java.util.stream.IntStream;
//import rx.Observable;
IntStream intStream = IntStream.range(1,10000000);
Observable.from(() -> intStream.iterator())
.takeWhile(n -> n < 10)
.forEach(n-> System.out.println(n));
For maximal performance in parallel operations use findAny() which is similar to findFirst().
Optional<SomeObject> result =
someObjects.stream().filter(obj -> some_condition_met).findAny();
However If a stable result is desired, use findFirst() instead.
Also note that matching patterns (anyMatch()/allMatch) will return only boolean, you will not get matched object.
I have achieved by something like this
private void doSomething() {
List<Action> actions = actionRepository.findAll();
boolean actionHasFormFields = actions.stream().anyMatch(actionHasMyFieldsPredicate());
if (actionHasFormFields){
context.addError(someError);
}
}
}
private Predicate<Action> actionHasMyFieldsPredicate(){
return action -> action.getMyField1() != null;
}
You can achieve that using a mix of peek(..) and anyMatch(..).
Using your example:
someObjects.stream().peek(obj -> {
<your code here>
}).anyMatch(obj -> !<some_condition_met>);
Or just write a generic util method:
public static <T> void streamWhile(Stream<T> stream, Predicate<? super T> predicate, Consumer<? super T> consumer) {
stream.peek(consumer).anyMatch(predicate.negate());
}
And then use it, like this:
streamWhile(someObjects.stream(), obj -> <some_condition_met>, obj -> {
<your code here>
});
int valueToMatch = 7;
Stream.of(1,2,3,4,5,6,7,8).anyMatch(val->{
boolean isMatch = val == valueToMatch;
if(isMatch) {
/*Do whatever you want...*/
System.out.println(val);
}
return isMatch;
});
It will do only operation where it find match, and after find match it stop it's iteration.
public static void main(String[] args) {
List<String> list = Arrays.asList("one", "two", "three", "seven", "nine");
AtomicBoolean yes = new AtomicBoolean(true);
list.stream().takeWhile(value -> yes.get()).forEach(value -> {
System.out.println("prior cond" + value);
if (value.equals("two")) {
System.out.println(value);
yes.set(false);
}
});
//System.out.println("Hello World");
}
What about this one:
final BooleanWrapper condition = new BooleanWrapper();
someObjects.forEach(obj -> {
if (condition.ok()) {
// YOUR CODE to control
condition.stop();
}
});
Where BooleanWrapper is a class you must implement to control the flow.
I would suggest using anyMatch. Example:-
return someObjects.stream().anyMatch(obj ->
some_condition_met;
);
You can refer this post for understanding anyMatch:-
https://beginnersbook.com/2017/11/java-8-stream-anymatch-example/