Combine two streams and call method - java

I have a problem how to stream asynchornously and call a method,
e.g.
List<User> users = List.of(user1, user2, user3);
List<Workplace> worklpaces = List.of(workplace1,workplace2,workplace3)
It's always the same users.size == workplaces.size
we have a function mapping
public List<UserWithWorkplace> combineUserWithWorkplaceAndType(List<User> users,List<Workplace>
worklpaces, Type someRandomtype) {
//here is the problem it wont it should be get
//List<UserWithWorkplace>.size == users.size == workplaces.size
return users.stream().flatMap(user ->
worklpaces.stream()
.map(worklpace -> mapping(user,worklpace, someRandomtype)))
.toList()
}
private UserWithWorkplace mapping( User user, Workplace workplace,Type someRandomtype){
//cominging and returning user with workplace
}
How to achieve that result?

Assuming you want to create pairs of (user, workplace) from two separate users an workplaces streams, this operation is normally called "zipping".
Guava library provide Streams.zip(Stream, Steam, Function) method for this. In your case the code would look like:
Stream<UserWithWorkplace> zipped = Streams.zip(
users.stream(),
worklpaces.stream(),
(u, w) -> this.mapping(u, w, someRandomtype));
However your example code uses List and not Stream to represent data. I'm not sure if you have to use Java streams for this, a simple for loop with i index might be easier.

What you're describing is a zipping operation.
If using Google Guava, you can do this to combine them:
Streams.zip(users.stream(), workplaces.stream(), (user, workplace) -> mapping(user, workplace, someType))
You can also find some other implementations of this operation described here

Related

How to assert on the existence of a certain value in an array

class Configuration { String name, String type }
Configuration[] configurations = ..
I want to put a assert check to see if the array contains a certain value in the name field (say name="Any"). We are currently looping the array to check this, what would be an elegant way
Using the Streams API:
assertTrue(Arrays.stream(configurations).anyMatch(c -> "Any".equals(c.name));
Another slight variation using the Streams API and a method reference:
assertTrue(Arrays
.stream(configurations)
.map(c -> c.name)
.anyMatch("ValueToLookFor"::equals));
Use AssertJ:
assertThat(configurations).extracting(Configuration::getName).contains("Any");
or you may prefer:
assertThat(configurations).anyMatch(c -> "Any".equals(c.name));

What is the top first use case you think of, when you see the 'flatMap' method in someone else's code?

Sorry for some kind of theoretical question, but I'd like to find a way of quick reading someone else's functional code, building chain of methods use templates.
For example:
Case 1.
When I see use of .peek method or .wireTap from Spring Integration, I primarily expect logging, triggering monitoring or just transitional running external action, for instance:
.peek(params ->
log.info("creating cache configuration {} for key class \"{}\" and value class \"{}\"",
params.getName(), params.getKeyClass(), params.getValueClass()))
or
.peek(p ->
Try.run(() -> cacheService.cacheProfile(p))
.onFailure(ex ->
log.warn("Unable to cache profile: {}", ex.toString())))
or
.wireTap(sf -> sf.handle(msg -> {
monitoring.profileRequestsReceived();
log.trace("Client info request(s) received: {}", msg);
Case 2.
When I see use of .map method or .transform from Spring Integration, I understand that I'm up to get result of someFunction(input), for instance:
.map(e -> GenerateTokenRs.builder().token(e.getKey()).phoneNum(e.getValue()).build())
or
.transform(Message.class, msg -> {
ErrorResponse response = (ErrorResponse) msg.getPayload();
MessageBuilder builder = some tranforming;
return builder.build();
})
Current case.
But I don't have such a common view to .flatMap method.
Would you give me your opinion about this, please?
Add 1:
To Turamarth: I know the difference between .map and .flatMap methods. I actively use both .map, and .flatMap in my code.
But I ask community for theirs experience and coding templates.
It always helps to study the signature/javadoc of the streamish methods to understand them:
The flatMap() operation has the effect of applying a one-to-many transformation to the elements of the stream, and then flattening the resulting elements into a new stream.
So, typical code I expect, or wrote myself:
return someMap.values().stream().flatMap(Collection::stream)
The values of that map are sets, and I want to pull the entries of all these sets into a single stream for further processing here.
In other words: it is about "pulling out things", and getting them into a stream/collection for further processing.
I've found one more use template for .flatMap.
Let's have a look at the following code:
String s = valuesFromDb
.map(v -> v.get(k))
.getOrElse("0");
where Option<Map<String, String>> valuesFromDb = Option.of(.....).
If there's an entry k=null in the map, then we'll get null as a result of code above.
But we'd like to have "0" in this case as well.
So let's add .flatMap:
String s = valuesFromDb
.map(v -> v.get(k))
.flatMap(Option::of)
.getOrElse("0");
Regardless of having null as map's value we will get "0".

How to handle possible empty value in chains without null (no model tricks)?

I'm trying to add the RX Android pack library on a previous MVC project, wherein I'm trying to handle values from API responses to the Activity controller, passing by some controller that would do some additional operations on it.
The possibilities are that the value may be empty/optional/null by the API, in that case the controller would try to get the value from a cache storage, that also may be in the same condition, and finally pass it to the controller, where, depending the value, it would do some initing operation, or trying to make another API call with same mechanism, check that response, and then choose how to init the activity.
Example code (signatures are wrong)
In API:
Maybe<User> getUser(){
//...
}
In Controller:
Single<User> getUser(){
return API.getUser().switchIfEmpty(() -> Cache.getUser());
}
In Activity:
Disposable d = getUser().subscribe(user -> { if(user != null) init(user); else checkGuest(); } );
//...
void checkGuest(){
Disposable d = getGuest().subscribe(guest -> { init(guest) } );
}
All of this would be incredibly cool and smooth, except for a consideration, RX Java cannot handle null values. We may say that since Java 8 where are trying to get over null values in favor of Optional values (really?!?!?), so the Empty/Maybe pattern would be appropriate.
So, let's try this...
In API:
Maybe<User> getUser(){
//...
}
In Controller:
Single<User> getUser(){
return API.getUser().switchIfEmpty(() -> Cache.getUser()).switchIfEmpty(() -> ???);
}
In Activity:
Disposable d = getUser().subscribe(user -> { if(user != ???) init(user); else checkGuest(); } );
//...
void checkGuest(){
Disposable d = getGuest().subscribe(guest -> { init(guest) } );
}
I want to say that I hate and cannot accept at all to modify my models to add kind of additional attribute that would signs the instance as a Rx nulled instance, also because, this is an absolute violation of integrity, as of in any other method would be mandatory to check for that attribute, with a looooot of boilerplate.
Solutions:
1 I'm trying to handle this just by using single, and custom exception conditional checking in subscribe's error callable to decide where to proceed to next method in chain propagation, mixing functional and reactive programming.
2 I would have to modify my models, and use the RX Nulled instances in place of our beloved null values, but of course, also because I'm using Realm, and I can't even use polymorphism, and also, it violates integrity as said before.
3 Ideally, I would like to preserve the chain pattern and by using Maybe be able to execute a chain path if a previous value is Empty or another chain path if the value is not.
I would be happy if someone would feel like to front on the option 3, that would be the one that made me say "WOW" on the first time I seen a ReactiveX example.
After some searching, I found that eventually the best solution is in fact to... hold fast... to use Java 8 Optional!
First, this allows to keep the good old universal null like check pattern as always, so that we can't really need to forget about it, but also, to go on with the new technologies developments and so to conform to the new standard as we like to, and so to follow the new Java specifications as they come out.
This is also a "not" backward compatibility break, as in Android we can rely on some backporting dependencies to enable this before API level 24.
// support for optionals
compile "net.sourceforge.streamsupport:streamsupport:1.5.1"
And moreover, this permits to use chained operations, conditionality, ReactiveX and a Single value as we coders prefer to.
public Single<Optional<Model>> getMyModel(boolean offlineFallback) {
return apiInterface.getModel()
.map( model -> {
if( model.isPresent() ){
MyModel serverMyModel = model.get();
MyModel savedMyModel = databaseRepository.getMyModel();
if( serverMyModel != savedMyModel ){
serverMyModel.setMyAttribute(true);
databaseRepository.saveMyModel( serverMyModel );
}
return java8.util.Optional.ofNullable( serverMyModel );
}else{
if(offlineFallback){
MyModel MyModel = databaseRepository.getMyModel();
if(MyModel != null){
return java8.util.Optional.ofNullable(MyModel);
}
}
return Optional.empty();
}
});
}
Isn't this nice?

What should be used in Flux/Mono to join couple items

In JS promises you can use
Promise.join
But I couldn't find such solution for Flux/Mono. What is best practice when you deal with the different item then have to use them together later?
That depends on how you want to combine them.
Sequentially? Use Flux.concat
All in parallel? Use Flux.zip
If you expect only one result, Mono.zipWith might work for you.
There is a good number of 'merging operators'
zip, concat, merge, combineLatest are the main three.
Zip allows you to combine streams, where the items will be grouped in a 1-to-1 relationship within the stream. That is why you lost the last element.
When you are not sure about how numerous each stream will be and how often it will feed events you can use concat (add the other stream on the end of the first one), merge (where items are placed on the final stream in order of appearence from both streams), or combine latest (to mutate the two last events of each stream into something else).
Your case sounds like a merge to me.
After some changes, my code looks like this
public Mono<Item> createItem(final #NonNull String userName, String description, String[] tags,
#NonNull Flux<ImageDTO> photos) {
val item = initItem(userName);
item.setDescription(description);
if (null != tags) {
item.getTags().addAll(Arrays.asList(tags));
}
return photos.flatMap(photo -> imageService.storeImage(photo.getStream(), photo.getExt()))
.reduce(item, (item1, photoIri) -> {
item1.getPhotos().add(photoIri);
return item1;
})
.flatMap(itemRepository::save)
.flatMap(createdItem -> {
val itemHistory = getHistoryForCreatedItem(userName, createdItem);
return itemHistoryRepository.save(itemHistory).then(Mono.just(createdItem));
});
}
Currently I don't like:
.reduce(item, (item1, photoIri) ->
.then(Mono.just(createdItem))

Project Reactor composing Flux.zip()

I have been trying to learn Project Reactor 3.0 with this small application. I am struggling to compose a Flux.zip() function for combining variables to a Movie object. In Reactor it seems like the return type is a Flux<Tuple5<>>. In RxJava2 it returns a Function5<>.
RxJava2
Single<Movie> movie = Single.zip(getDesc(id), getCategory(id), getName(id), getRating(id),
(Function5<Integer, String, String, String, Double, Object>) (desc, cat, name, rating) ->
new Movie(id.blockingGet(), name, desc, cat, rating)).cast(Movie.class);
Reactor
Flux<Tuple5<Integer, String, String, String, Double>> tuple =
Flux.zip(id, getDesc(id), getCategory(id), getName(id), getRating(id));
Instead of returning a Flux<Tuple5<>> I want to return a Tuple5<> or something else to create the movie just like RxJava. I do not want to subscribe to the Tuple since I am trying to return this in Spring Web Reactive. I temporarily solved it by subscribing, but I was wondering if it is possible to do the same as RxJava.
The example in this video on timestamp 1:07:54, shows it was possible in an old version.
Any solutions or suggestions are welcome!
The RxJava solution doesn't return the Movie directly, but a Single<Movie>. Reactor has a simplified zip that returns a Tuple, but that RxJava signature is comparable to Flux<Tuple5>.
So what you want is a Flux<Movie>. zip has an overload that takes a Function<Object[], V> as the first parameter: that lets you specify into which object V the values from the zipped sources are to be combined. The function will be applied with an array of these values as input, and must return the value to be emitted in the resulting Flux<V>, in your case a Movie.
Yes,Zip can be used. It waits for sources to emit an element and combine them in Tuples. Like below publishers are emitting first name, last name and dept. which is being combined to form User flux.
Flux<String> fnameFlux = Flux.just("Ramesh","Amit","Vijay");
Flux<String> lnameFlux = Flux.just("Sharma","Kumar","Lamba");
Flux<String> deptFlux = Flux.just("Admin","IT","Acc.");
Flux<User> userFlux = Flux.zip(fnameFlux, lnameFlux, deptFlux)
.flatMap(dFlux ->
Flux.just(new User(dFlux.getT1(), dFlux.getT2(), dFlux.getT2())));
userFlux.subscribe(x -> System.out.println(x));

Categories