Is there any way to use both FailableFunction and Function lambdas into a single .map chaining stream?
Function<String, Organization> hook = (id) -> this.organizationRepository.findById(id).get();
FailableFunction<Organization, Organization, MpiException> failableSave = (r) -> this.organizationRepository.save(r);
List<String> ids;
Failable.stream(ids)
.map(hook)
.map(failableSave)
.collect(Collectors.toList());
I'm getting:
The method map(FailableFunction<String,R,?>) in the type Streams.FailableStream is not applicable for the arguments (Function<String,Organization>)
Problem here is that sometimes I need to use Function and other times I need to use FailableFunction.
Any ideas about how to use them into same stream mapping chaining?
Maybe not the most elegant solution, but since nobody else came up with something:
You could use a method reference to implicitly convert a Function into a FailableFunction:
Failable.stream(ids)
.map(hook::apply)
.map(failableSave)
.collect(Collectors.toList());
Related
new Vavr user here.
I am trying to pattern match a tuple of options to execute a statements if both of them are Some, in Scala I would have done this with:
val maybeThis: Option[String] = ???
val maybeThat: Option[String] = ???
(maybeThis, maybeThat) match {
case (Some(dis), Some(that)) => ???
case _ => ???
}
In Java, I am trying this approach:
Tuple2<Option<String>, Option<String>> tuple = new Tuple2<>(Option.of(...), Option.of(...));
return Match(tuple).of(
Case($Tuple2($Some($(instanceOf(String.class))), $Some($(instanceOf(String.class)))),
(someThis, someThat) -> methodWhichEatsTwoStrings(someThis.get(), someThat.get())),
Case($(), t -> run(() -> {
throw new NullPointerException(...);
})));
However, with this implementation the compiler complains that it was expecting Some<Object> instead of Some<String>, same error happens if I omit the $(instanceOf(String.class) in the pattern.
I am moderately sure this is merely a problem of proper syntax, yet I am struggling to find the correct documentation.
Where am I wrong?
Thanks
There's a vavr API construct called for comprehension that tries to mimic Scala's for comprehensions to the extent that it's possible to do in Java. With that construct you could solve your problem quite elegantly. See the For overload for handling two Options for more details. Here's an example code snippet:
String methodWhichEatsTwoStrings(String v1, String v2) {
return v1 + v2; //combine the two values in some way
}
...
Option<String> option1 = Option.some("value1");
Option<String> option2 = Option.some("value2");
String combined = For(option1, option2)
.yield((v1, v2) -> methodWhichEatsTwoStrings(v1, v2))
.getOrElseThrow(() -> new NullPointerException("reasons"));
Of course, you could use Option wrapping values of different types for option1 and option2, or combine multiple options, not just two. You could also use a different type for the return value of the yield function as well. I used String everywhere for the sake of simplicity and to conform to your original example.
I would like to add that I would try to avoid throwing NullPointerException in case one or both of the options are empty. Maybe try to use another vavr data type like Either to represent such an error case?
During some reactive programming in Java using project reactor library, I stumbled upon a pattern for which I'm wondering if there is out of box support?
So I want the code below:
Mono.just("hello")
.flatMap(hello -> reactiveAction(hello).thenReturn(hello))
..
.;
to be turned into something like:
Mono.just("hello")
.coolOperation(this::reactiveAction)
..
.;
I can not use doOnNext because what I want to do inside reactiveAction is not side effect.
and reactive action is:
Mono<Integer> reactiveAction(String text){
return ....
}
Have you considered Mono#delayUntil?
Mono.just("hello")
.delayUntil(hello -> reactiveAction(hello))
..
.;
I can't find built-in solution, but you could create utility function:
public static <T> Function<Mono<T>, Publisher<T>> coolOperation(
Function<T, Mono<?>> companionMonoFunction) {
return originalMono -> originalMono
.flatMap(t -> companionMonoFunction.apply(t)
.thenReturn(t));
}
And now you can use it with transform or transformDeffered:
Mono.just("hello")
.transform(coolOperation(this::reactiveAction))
...;
But for me it doesn't look much prettier :)
EDIT: see #bsideup answer, looks like delayUntil could fit the bill.
My original answer as an alternative suggestion:
I don't think there is any baked-in syntactic sugar to do this, as the "perform an async operation that depends on the original onNext" is the very definition of flatMap. We actually added the thenReturn(foo) as syntactic sugar over .then(Mono.just(foo)).
If you want to further shorten the code, offer an alternative to reactiveAction that also returns the original value:
Mono<String> reactiveActionBackground(String text){
return reactiveAction(text).thenReturn(text);
}
which can then be invoked directly on flatMap rather than through transform:
Mono.just("hello")
.flatMap(this::reactiveActionBackground);
Is there a way to simplify filter using stream?
Or for it to be shorter or optimized? I'm not quite sure if using a for loop would be better to use in this scenario.
I'm just trying to separate the failed and the success messages using the failedIds.
Here is my code
List<Message> successMessages = messageList.stream()
.filter(message -> !failedMessageIds.contains(message.getId()))
.collect(Collectors.toList());
List<Message> failedMessages = messageList.stream()
.filter(message -> failedMessageIds.contains(message.getId()))
.collect(Collectors.toList());
Thank you!
You may use groupingBy collector here. This solution passes over the collection only once. Also make sure to use a Set for failedMessageIds.
Map<Boolean, List<Message>> messagesByStateMap = messageList.stream()
.collect(Collectors.groupingBy(m -> !failedMessageIds.contains(m.getId())));
List<Message> successMessages = messagesByStateMap.get(true);
A much better approach would be to use the partitioningBy collector as stated in the following comment since your classifier function is a just a Predicate.
Map<Boolean, List<Message>> messagesByStateMap = messageList.stream()
.collect(Collectors.partitioningBy(m -> !failedMessageIds.contains(m.getId())));
However, since the use of streams has sparked some controversy, here's the equivalent iterative solution using Java 8.
for (Message message : messageList)
messagesByStateMap.computeIfAbsent(!failedMessageIds.contains(message.getId()),
unused -> new ArrayList<>())
.add(message);
First I need to check if data is present in list then get else set default or empty value on a Java 8 stream.
Currently I am using below code without isPresent but I dont know how to use isPresent in java8.
I am trying something below which is not perfect:
String isScheme = (this.mapProgramApproaches.stream().findFirst().isPresent())? this.mapProgramApproaches.stream().findFirst().get().getIsScheme().toString() : "0";
Where as mapProgramApproaches this is set.
Don't use isPresent() (it makes no sense to run the Stream pipeline twice).
You can use map to map the value of the Optional to the required String, and then
use orElse() to return a default value when the Optional value is not present:
String isScheme = this.mapProgramApproaches.stream()
.findFirst()
.map(o->o.getIsScheme().toString())
.orElse("0");
Maybe you are looking for something like this:
String isScheme = this.mapProgramApproaches.stream()
.findFirst()
.map(p -> p.getIsScheme().toString())
.orElse("0");
I'm not sure about context in which you are doing this, but I suppose that you would like to check whether some object is scheme and then do something with that. In that case I would suggest implement it like this:
List<String> mapProgramApproaches = new ArrayList<>();
mapProgramApproaches.stream()
.filter(this::isScheme)
.findFirst()
.ifPresent(this::doYourCode)
.orElse(defaultValue);
It will make your code cleaner. And will help to avoid additional conditionals!
I have some data stored in a JPA Repository that I am trying to process. I would like to be able to use Java 8 Streams to do so, but can not figure out how to get the required information. This particular 'Entity' is actually only for recovery, so it holds items that would need to be processed after something like a power-fail/restart.
Using pre-Java 8 for-loops the code would look like:
List<MyEntity> deletes = myEntityJpaRepository.findByDeletes();
for (MyEntity item : deletes) {
String itemJson = item.getData();
// use a Jackson 'objectMapper' already setup to de-serialize
MyEventClass deleteEvent = objectMapper.readValue(itemJson, MyEventClass.class);
processDelete(deleteEvent, item.getId());
}
The problem arises from the two parameter method called at the very end. Using Streams, I believe I would do:
// deletes.stream()
// .map(i -> i.getData())
// .map(event -> objectMapper.readValue(event, MyEventClass.class))
// .forEach(??? can't get 'id' here to invoke 2 parameter method);
I have a solution (without Streams) that I can live with. However I would think this problem comes up a lot, thus my question is: IN GENERAL, is there a way using Streams to accomplish what I am trying to do?
Why not a Pair return on your map operation:
.map(i -> new Pair<>(i.getData(), i.getId()))
.map(pair -> new Pair<>(objectMapper.readValue(pair.getLeft(), MyEventClass.class), pair.getRight())
.forEach(p -> processDelete(pair.getLeft(), pair.getRight()))
I did not compile this, so there might be minor things to fix. But in general, you would need a Holder to pass your objects to the next stage in such a case. Either a Pair or some type or even a array.
Why not doing it simply this way?
deletes.forEach(item ->
processDelete(objectMapper.readValue(item.getData(), MyEventClass.class),
item.getId()));
This is a start at least, I guess it is dependent on why you want to use stream and how much you want to make it more functional
List<MyEntity> deletes = myEntityJpaRepository.findByDeletes();
deletes.stream().foreach(item -> {
String itemJson = item.getData();
// use a Jackson 'objectMapper' already setup to de-serialize
MyEventClass deleteEvent = objectMapper.readValue(itemJson, MyEventClass.class);
processDelete(deleteEvent, item.getId());
});