handle value by reactor with stream - java

I just want to do something like this by reactor
Object value=1;
List<Consumer>consumers=new ArrayList();
consumers.add(xx) .....
for (Consumer c : consumers)
{
if(c.consumer(value)){ // dosomething}
else return
}
How could i implement this by the reactive
Thanks

Use fromIterable to create a Flux that emits each element from the iterable list:
Flux.fromIterable(consumers)
and takeWhile to relay consumers while your predicate returns true:
Flux.fromIterable(consumers)
.takeWhile(c -> <your predicate>)
.flatMap(c -> dosomethingAsync())
.subscribe();

Related

How to buffer and group elements in Reactor Flux in Java

Given an infinite flux of objects, where each object has an ID, how can I use flux to create a buffered list of updates grouped by ID property (keeping the last emitted value)?
Thanks
Example
Obj(ID=A, V=1)
Obj(ID=A, V=2)
Obj(ID=B, V=3)
--- buffer -> I want to subscribe with a list of [Obj(ID=A, V=2), Obj(ID=B, V=3)]
Obj(ID=A, V=1)
Obj(ID=B, V=4)
Obj(ID=B, V=6)
Obj(ID=A, V=2)
--- buffer -> I want to subscribe with a list of [Obj(ID=B, V=6), Obj(ID=A, V=2)]
Obj(ID=B, V=1)
--- buffer -> I want to subscribe with a list of [Obj(ID=B, V=1)]
Something like the following would be perfect but it seems to wait the end of the flux in my tests instead of buffering.
flux
.buffer(Duration.ofMillis(2000))
.groupBy(Obj::getId)
.flatMap(GroupedFlux::getLast)
.collectToList()
.subscribe(this::printList);
It works with buffer and custom logic for grouping
public static void main(String[] args) {
flux.buffer(Duration.ofMillis(2000)).subscribe(this::groupList);
}
private void groupList(List<T> ts) {
Collection<T> values = ts.stream()
.collect(Collectors.toMap(T::getId, Function.identity(), (k, v) -> v))
.values();
System.out.println(values);
}
buffer will emit List<T>, therefore you could just use non-reactive java to group by. For example, java streams like in your example. Assuming your process function is reactive, you could continue the flow
flux
.buffer(Duration.ofMillis(2000))
.map(list ->
list.stream()
.collect(Collectors.toMap(Entry::getId, Function.identity(), (k, v) -> v)))
.flatMapIterable(Map::values)
.flatMap(obj -> process(obj));
I was able to achieve it with the reactive grouping
flux.window(Duration.ofMillis(2000))
.flatMap(window -> window.groupBy(Entry::getId)
.flatMap(GroupedFlux::last)
.collectList()
)
.subscribe(this::printList);

Convert List<Mono<String>> to Flux<String>

There are few question , but there answers are very specific to some code.
Generally, how to convert a Stream of Mono to Flux
List<Mono<String> listOfMono = stream()
.map( s -> { do something and return Mono<String> } )
.collect(Collectors.toList());
How to convert listOfMono object to Flux<String>
You can use fromIterable and then use flatMap to flatten the Mono
Transform the elements emitted by this Flux asynchronously into Publishers, then flatten these inner publishers into a single Flux through merging, which allow them to interleave.
Flux<String> result = Flux.fromIterable(listOfMono)
.flatMap(Function.identity());
If your input is a list of Monos you can simply do:
Flux.merge(listOfMono);
If your input is stream you can either do
stream()
.map( s -> { do something and return Mono<String> } )
.collect(Collectors.collectingAndThen(Collectors.toList(), Flux::merge));
OR
Flux.fromStream(stream())
.flatMap( s -> { do something and return Mono<String> } )
I'd personally prefer the last option as that is the most straighforward and idiomatic.

Java stream: Collect Stream<int[]> to List<int[]>

I try to get my head around java streams.
Atm I have this construct which does not work:
List<int[]> whiteLists = processes.stream()
.map(Process::getEventList)
.forEach(eventList -> eventList.stream()
.map(event -> event.getPropertie("whitelist"))
.map(propertie -> propertie.getIntArray())
.collect(Collectors.toList()));
}
The hierarchy is:
Process
Event
Property
Process::getEventList returns a list of Event objects
event.getPropertie("whitelist") returns a Property objects which hast the method getIntArray()
event.getPropertie() gives me an int-array.
How do I collect these array into a List of arrays?
Thanks!
You can't use forEach() as it takes a Consumer, meaning it will consume the stream, but can't return anything (so nothing to collect).
You need flatMap to stream the internal eventList as follows
List<int[]> whiteLists = processes.stream()
.flatMap(p -> p.getEventList().stream())
.map(event -> event.getPropertie("whitelist"))
.map(propertie -> propertie.getIntArray())
.collect(Collectors.toList());

How to flatten a stream of Single<R>

I have this code
public Stream<PaymentEntity> getPayments(List<String> paymentIds) {
return paymentIds.stream()
.flatMap(id -> paymentsRepository.getById(id))
}
paymentsRepository.getById(id) is returning Single<PaymentEntity>
But i got compile time error
no instance(s) of type variable(s) R exist so that
Single conforms to Stream
Edit, to anyone asking about Single http://reactivex.io/documentation/single.html
You can use
return paymentIds.stream()
.map(id -> paymentsRepository.getById(id).toBlocking().value());
Or in rxjava 2 you can use :
return paymentIds.stream()
.map(id -> paymentsRepository.getById(id).blockingGet());
After comment I think you can go with this solution :
List<PaymentEntity> result = new ArrayList<>();
paymentIds.forEach(id -> paymentsRepository.getById(id).toObservable().subscribe(result::add));
return result.stream();
Alternate solution:
public Stream<PaymentEntity> getPayments(List<String> paymentIds) {
return Observable.fromIterable(paymentIds)
.flatMapSingle(id -> paymentsRepository.getById(id))
.toList()
.blockingGet()
.stream();
}
You can wait until the current Single in the lambda signals a success value using .blockingGet():
return paymentIds.stream()
.map(id -> paymentsRepository.getById(id).blockingGet());
Or you can wait until all the reactive chain signals a success value in this way:
return Observable.fromIterable(paymentIds)
.flatMapSingle(paymentsRepository::getById)
.toList()
.blockingGet()
.stream();
Consider also to use Flowable: unlike Observable, it supports backpressure strategy.

RxJava: dynamically create Observables and send the final resut as Observable

I am using RxJava in which I want to dynamically create a number of Observables based on some condition. Once I'm done with creating, I want to do some processing on the different values returned by the observables and then send as a single Observable to which I can subscribe on. Here is how my code is :
List<String> valueList = ....
List<Observable<String>> listOfObservables = new ArrayList<Observable<String>>();
for(int i =; i <valueList.size(); i++){
listOfObservables.add(new SomeClass.doOperation(valueList(i)));
// SomeClass.doOperation will return an Observable<String>
}
return Observable.merge(listOfObservables);
But here , I want to do some operation on the values emitted by different Observables in the listOfObservable and finally return it as a single Observable<String>
Like in Observable.zip() , I can do this like
return Observable.zip(observable1, observable2, (string1, string2) -> {
// joining final string here
return string1 + string2;
But I know the number of arguments here. Please let me know how I can achieve this.
Use the zip overload that takes a variable number of arguments, it has a signature of
<R> Observable<R> zip(Iterable<? extends Observable<?>> ws,
FuncN<? extends R> zipFunction)
Example usage:
List<String> valueList = ....
return Observable.from(valueList)
.map(string -> SomeClass.doOperationThatReturnsObservable(string))
.toList()
.flatMap(listOfObs -> Observable.zip(listOfObs, (Object[] results) -> {
// do something with the strings in the array.
return Arrays.stream(results)
.map(Object::toString)
.collect(Collectors.joining(","));
}));

Categories