Chain methods to convert from Optional->List->List in Java - java

I have an Optional object that contains a list. I want to map each object in this list to another list, and return the resulting list.
That is:
public List<Bar> get(int id) {
Optional<Foo> optfoo = dao.getById(id);
return optfoo.map(foo -> foo.getBazList.stream().map(baz -> baz.getBar()))
}
Is there a clean way of doing that without having streams within streams?
I think that flatMap might be the solution but I can't figure out how to use it here.

There isn't. flatMap in case of Optional is to flatten a possible Optional<Optional<T>> to Optional<T>. So this is correct.
public List<Bar> get(Optional<Foo> foo) {
return foo.map(x -> x.getBazList()
.stream()
.map(Baz::getBar)
.collect(Collectors.toList()))
.orElse(Collections.emptyList());
}

A Java 9 approach would be the folloing:
public List<Bar> get(Optional<Foo> foo) {
return foo.map(Foo::getBazList)
.stream()
.flatMap(Collection::stream)
.map(Baz::getBar)
.collect(Collectors.toList());
}
That said, you should avoid using Optionals as parameters, see here.

Related

Java Streams; avoid finisher on Collectors.collectingAndThen

I've this code:
private Iterable<Practitioner> pickPractitioners(List<String> ids) {
return Optional.ofNullable(ids)
.map(List::stream)
.orElse(Stream.of())
.collect(
Collectors.collectingAndThen(
Collectors.toList(),
this.practitionerRepository::findAllById
)
);
}
Problem is that when ids is empty, this.practitionerRepository::findAllById is also executed.
I'd like to avoid this step if resulting collector is empty.
Any ideas?
In general to skip that part of the finisher you could pass a lambda instead of a method reference and check if the input is empty:
.collect(
Collectors.collectingAndThen(
Collectors.toList(),
r -> r.isEmpty() ? Collections.emptyList() : this.practitionerRepository.findAllById(r)
)
);
If your actual code is a simple as this example then you don't need to use streams or optional at all. Instead you could just check if the input of the method is null or empty in a ternary operator:
return ids == null || ids.isEmpty() ? Collections.emptyList() :
this.practitionerRepository.findAllById(ids);
Whilst the practical part of this question (how to avoid interrogating the repository with an empty list as an argument) is already addressed in other answers I want to point out that there's a cleaner way to build a pipeline in this method.
Firstly it's worthy to remind that the main purpose of Optional.ofNullable() is to create an Optional object that has to be returned from a method.
Attempts to use Optional.ofNullable() in order to utilize method-chaining or to avoid null-checks in the middle of the method according to Stuart Marks are considered to be anti-patterns.
Here is the quote from his talk at Devoxx:
"it's generally a bad idea to create an Optional for the specific
purpose of chaining methods from it to get a value."
A similar idea was expressed in his answer on stackoverflow.
What are the alternatives?
Since Java 9 Stream interface has its own method ofNullable().
Returns a sequential Stream containing a single element, if non-null,
otherwise returns an empty Stream.
Keeping all that in mind method pickPractitioners() could be rewritten like this:
private Function<List<String>, Iterable<Practitioner>> getPractitioners =
idList -> idList.isEmpty() ? Collections.emptyList() :
this.practitionerRepository.findAllById(idList);
private Iterable<Practitioner> pickPractitioners(List<String> ids) {
return Stream.ofNullable(ids)
.flatMap(List::stream)
.collect(Collectors.collectingAndThen(
Collectors.toList(),
getPractitioners
));
}
If you look at the signature of the Finisher. It is just a function, so you can just write it:
public static<T,A,R,RR> Collector<T,A,RR> collectingAndThen(Collector<T,A,R> downstream, Function<R,RR> finisher) {
static interface MyRepository extends JpaRepository<Part, Long> {
}
public static void main(String[] args) {
MyRepository myRepository = null;
List<Long> list = null;
Function<List<Long>, List<Part>> finisher = (ids) -> {
return ids.isEmpty() ? Collections.emptyList() : myRepository.findAllById(ids);
};
Optional.ofNullable(list)
.map(List::stream)
.orElse(Stream.of())
.collect(
Collectors.collectingAndThen(
Collectors.toList(),
finisher
)
);
}

Filtering min of Optional values

I want to get the minimum value of a function result of an object list.
But the return value of this function is optional.
So it would be OK if no fragment time is set so far and the return value should then be Optional.empty()
public Optional<Double> getFragmentTime(int fragment) {
...
}
private List<Entry> entries; // will be filled in the ctor.
public Optional<Double> getMinFragmentTime(int fragment) {
return entries.stream()
.map(e -> e.getFragmentTime(fragment))
.filter(Optional::isPresent)
.map(Optional::get)
.min(Double::compare);
}
Is this the correct way to archive it?
The two function calls .filter(Optional.isPresent) and .map(Optional.get) seems rather odd to me, and I think there must be a better solution for it.
You can use the advantage of flat-mapping with Optional::stream available since java-9:
return entries.stream() // Stream<Entry>
.map(e -> e.getFragmentTime(fragment)) // Stream<Optional<Double>>
.flatMap(Optional::stream) // Stream<Double>
.min(Double::compare); // Optional<Double>
Note that .min(Double.compare); is not correct usage, the parameter is in fact the lambda expression ((d1, d2) -> Double.compare(d1, d2) which shall be shortened as method reference Double::compare. Also using Comparator.comparingDouble(d -> d) is possible.
In case of java-8 you have to stick with .filter(Optional::isPresent).map(Optional::get).
First one should use the stream for the primitive type, as that has a nice support for min().
public OptionalDouble getFragmentTime(int fragment) {
...
}
public OptionalDouble getMinFragmentTime(int fragment) {
return entries.stream()
.flatMap(e -> e.getFragmentTime(fragment).stream())
.min();
}
An OptionalDouble may deliver a stream of 1 or 0 doubles.
A flatMap to DoubleStream, and then taking the min.
(Code not verified.)

Do I need a custom Spliterator to avoid extra .stream() call?

I have this code which works fine, but I find it ugly.
#EqualsAndHashCode
public abstract class Actions {
#Getter
private List<ActionsBloc> blocs;
public Actions mergeWith(#NotNull Actions other) {
this.blocs = Stream.of(this.blocs, other.blocs)
.flatMap(Collection::stream)
.collect(groupingBy(ActionsBloc::getClass, reducing(ActionsBloc::mergeWith)))
.values()
.stream()
.filter(Optional::isPresent)
.map(Optional::get)
.collect(toList());
return this;
}
}
ActionsBloc is a super type which contains a list of Action.
public interface ActionsBloc {
<T extends Action> List<T> actions();
default ActionsBloc mergeWith(ActionsBloc ab) {
this.actions().addAll(ab.actions());
return this;
}
}
What I want to do is merge blocs of Actions together based on the Class type. So I'm grouping by ActionsBloc::getClass and then merge by calling ActionsBloc::mergeWith.
What I find ugly is calling the values().stream() after the first stream was ended on collect.
Is there a way to operate only on one stream and get rid of values().stream(), or do I have to write a custom Spliterator? In other words have only one collect in my code.
You can work with a reducing identity to sort that out possibly. One way could be to update the implementation of mergeWith as :
default ActionsBloc mergeWith(ActionsBloc ab) {
this.actions().addAll(Optional.ofNullable(ab)
.map(ActionsBloc::actions)
.orElse(Collections.emptyList()));
return this;
}
and then modify the grouping and reduction to:
this.blocs = new ArrayList<>(Stream.of(this.blocs, other.blocs)
.flatMap(Collection::stream)
.collect(groupingBy(ActionsBloc::getClass, reducing(null, ActionsBloc::mergeWith)))
.values());
Edit: As Holger pointed out such use cases of using groupingBy and reducing further could be more appropriately implemented using toMap as :
this.blocs = new ArrayList<>(Stream.concat(this.blocs.stream(), other.blocs.stream())
.collect(Collectors.toMap(ActionsBloc::getClass, Function.identity(), ActionsBloc::mergeWith))
.values());

Enums Returning Arrays Stream

I have a requirement to validate a field against some predefined values (that can grow in future). So for this I have created a Enum and defined a method that returns the stream of the allowed values.
public enum EnumDemo {
VERSION("1.0.0","2.0.3");
private List<String> ver;
EnumDemo(String... ver) {
this.ver = Arrays.asList(ver);
}
public List<String> getVer() {
return ver;
}
public static Stream<EnumDemo> stream() {
return Arrays.stream(EnumDemo.values());
}
}
Now I need to validate a field against the values defined in this Enum.
I'm using:
Optional<EnumDemo> ab = EnumDemo.stream()
.map(l -> {l.getVer().stream()
.filter(c -> c.equals("2.0.3"))
.findFirst();})
.findFirst();
System.out.println(ab.get().getVer());
But it is giving me compilation error. Any help would be appreciated.
Edit:
Compilation Error:
The method map(Function<? super EnumDemo,? extends R>) in the type Stream<EnumDemo> is not applicable for the arguments ((<no type> l) -> {})
You should write it this way:
Optional<EnumDemo> ab = EnumDemo.stream().filter(l -> l.getVer().contains("2.0.3"))
.findFirst();
By the way, it wasn't working because you used {} for the lambda expression, so it was expecting a return statement in the {}. You could either remove the {} (along with the ;) or add in the return.
Anyway the original codes looked confusing, not sure if I guessed the intention correctly, but this implementation should be clearer.
Edit
Based on your comment, this is what you need:
EnumDemo.stream().flatMap(l -> l.getVer().stream())
.filter("2.0.3"::equals)
.findAny()
.ifPresent(System.out::println);
Update
Holger commented that there is a shorter and more meaningful way, with better performance:
if(EnumDemo.stream()
.anyMatch(l -> l.getVer().contains(userString))) {
System.out.println(userString);
}
To understand it, you have to think about lambdas. Lambdas represent interfaces but are specially treated by the JVM, so not every Lambda needs a class to represent. (Stateless lambdas can be just methods).
Now when looking at the map() method in the Stream interface:
<R> Stream<R> map(Function<? super T, ? extends R> mapper);
You see that it expects an implementation of the Function interface. You now have many different ways to provide that mapper. In this example lets map from Object to String:
1. Using an inline lambda:
.map(o -> o.toString())
2. Using a multiline lambda:
.map(o -> {
return o.toString();
})
3. Using method references:
.map(Object::toString)
4. Using an anonymous class:
.map(new Function<Object, String>(){
#Override
public String apply(Object o){
return o.toString();
}
})
Your current code uses the 2. approach. But without a return statement. This is even better seen when looking at the anonymous class at 4.. It seems natural, that when not using a return statement in a method that no value is returned.
And that's why you get the compilation error.
You just have to add the return statement:
.map(l -> {
return l.getVer().stream()
.filter(c -> c.equals("2.0.3"))
.findFirst();
});
Or remove the brackets {}:
.map(l -> l.getVer().stream()
.filter(c -> c.equals("2.0.3"))
.findFirst());
Or even use the approach provided by #Jai in his answer. Which works even better, than what you currently have.
You are using lambda expression and not returning any value so it is giving compilation error. It is better to use ifPresent()
String val="2.0.3";
EnumDemo.stream()
.flatMap(l -> l.getVer().stream())
.filter(c -> c.equals(val))
.findAny()
.ifPresent(x -> System.out.println(x));

How to convert lambda filters with dynamic values to method references

I have some Java code which filters a list based on some input. It currently uses a lambda, for example:
public List<ComplexObject> retrieveObjectsFilteredByTags(List<String> allowedTags) {
List<ComplexObject> complexObjects = retrieveAllComplexObjects();
return complexObjects
.stream()
.filter( compObject -> allowedTags.contains(compObject.getTag()))
.collect(Collectors.toList());
}
What I want to do is to move the filter logic to another method to make it re-usable and easily unit testable. So I wanted to use a method reference in place of the lambda passed to the filter method. Easy to do if the filter logic is fairly static (i.e. list of allowed tags is known at compile time) but I can't figure out how to do this with dynamic data in the filter.
What I wanted was some way to use a method reference and then pass the second dynamic param i.e.
public List<ComplexObject> retrieveObjectsFilteredByTags(List<String> allowedTags) {
List<ComplexObject> complexObjects = retrieveAllComplexObjects();
return complexObjects
.stream()
.filter(this::filterByAllowedTags, allowedTags)
.collect(Collectors.toList());
}
So is it possible to do what I want or am I possibly approaching this situation incorrectly?
I'd suggest passing in a Predicate as a parameter. That way the caller can filter based on any criteria it wants, including allowedTags or whatever:
public List<ComplexObject> retrieveObjectsFilteredBy(Predicate<ComplexObject> pred) {
List<ComplexObject> complexObjects = retrieveAllComplexObjects();
return complexObjects.stream()
.filter(pred)
.collect(Collectors.toList());
}
This would be called like so:
List<String> allowedTags = ... ;
List<ComplexObject> result =
retrieveObjectsFilteredBy(cobj -> allowedTags.contains(cobj.getTag()));
But you could go even further, depending on how much refactoring you're willing to do. Instead of "retrieve" returning a List, how about having it return a Stream? And instead of the retrieve-filter method returning a List, how about having it return a Stream too?
public Stream<ComplexObject> retrieveObjectsFilteredBy2(Predicate<ComplexObject> pred) {
Stream<ComplexObject> complexObjects = retrieveAllComplexObjects2();
return complexObjects.filter(pred);
}
And the calling side would look like this:
List<String> allowedTags = ... ;
List<ComplexObject> result =
retrieveObjectsFilteredBy2(cobj -> allowedTags.contains(cobj.getTag()))
.collect(toList());
Now if you look at it carefully, you can see that the retrieve-filter method isn't adding any value at all, so you might just as well inline it into the caller:
List<String> allowedTags = ... ;
List<ComplexObject> result =
retrieveAllComplexObjects2()
.filter(cobj -> allowedTags.contains(cobj.getTag()))
.collect(toList());
Of course, depending upon what the caller wants to do, it might not want to collect the results into a list; it might want to process the results with forEach(), or something else.
Now you can still factor out the filter into its own method, for testing/debugging, and you can use a method reference:
boolean cobjFilter(ComplexObject cobj) {
List<String> allowedTags = ... ;
return allowedTags.contains(cobj.getTag());
}
List<ComplexObject> result =
retrieveAllComplexObjects2()
.filter(this::cobjFilter)
.collect(toList());
If you don't want the filter to have the allowed tags built into it, you can change it from being a predicate into a higher-order function that returns a predicate instead:
Predicate<ComplexObject> cobjFilter(List<String> allowedTags) {
return cobj -> allowedTags.contains(cobj.getTag());
}
List<String> allowedTags = ... ;
List<ComplexObject> result =
retrieveAllComplexObjects2()
.filter(cobjFilter(allowedTags))
.collect(toList());
Which of these variations makes the most sense depends on what your application looks like and what kind of dynamicism you require in filtering.
How about the following? It extracts the predicate in a separate method to make it easily testable, and can be reused easily.
public Predicate<ComplexObject> tagAllowed(List<String> allowedTags) {
return (ComplexObject co) -> allowedTags.contains(co.getTag());
}
public List<ComplexObject> retrieveObjectsFilteredByTags(List<String> allowedTags) {
List<ComplexObject> complexObjects = retrieveAllComplexObjects();
return complexObjects
.stream()
.filter(tagAllowed(allowedTags))
.collect(Collectors.toList());
}
The problem with the method reference this::filterByAllowedTags is that it has the shape:
(ComplexObject, List<String>) -> boolean
But it's being passed into filter() which expects a lambda of the shape:
(ComplexObject) -> boolean
In other words, this::filterByAllowedTags can never be a Predicate, but it could be some alternate interface Predicate2. Then you'd also need an overload of filter which takes a Predicate2.
Eclipse Collections (formerly GS Collections) has the method select() which behaves just like filter(), and selectWith() which behaves like the overload I just described.
Using select():
public List<ComplexObject> retrieveObjectsFilteredByTags(List<String> allowedTags)
{
// retrieveAllComplexObjects returns a MutableList, possibly FastList
MutableList<ComplexObject> complexObjects = retrieveAllComplexObjects();
// select() returns MutableList here which extends List
return complexObjects.select(compObject -> allowedTags.contains(compObject.getTag()));
}
Using selectWith():
public List<ComplexObject> retrieveObjectsFilteredByTags(List<String> allowedTags)
{
// retrieveAllComplexObjects returns a MutableList, possibly FastList
MutableList<ComplexObject> complexObjects = retrieveAllComplexObjects();
// select() returns MutableList here which extends List
return complexObjects.selectWith(this::filterByAllowedTags, allowedTags);
}
private boolean filterByAllowedTags(ComplexObject complexObject, List<String> allowedTags)
{
return allowedTags.contains(complexObject.getTag());
}
Note: I am a committer for Eclipse Collections.

Categories