Reputation: 107
I have this piece of code that filters from a list of objects based on a set of String identifiers passed in and returns a map of string-id and objects. Something similar to follows:
class Foo {
String id;
String getId() {return id};
};
// Get map of id --> Foo objects whose string are in fooStr
Map<String,Foo> filterMethod (Set<String> fooStr) {
List<Foo> fDefs; // list of Foo objects
Map<String,Foo> fObjMap = new HashMap<String, Foo>(); // map of String to Foo objects
for (Foo f : fDefs) {
if (fooStr.contains(f.getId()))
fObjMap.put(f.getId(),f);
}
return (fObjMap);
}
Is there a better Java8 way of doing this using filter or map? I could not figure it out and tried searching on stackoverflow but could not find any hints, so am posting as a question.
Any help is much appreciated. ~Ash
Upvotes: 1
Views: 151
Reputation: 21124
Just use the filter
operator with the same predicate as above and then the toMap
collector to build the map. Also notice that your iterative solution precludes any possibility of key conflict, hence, I have omitted that, too.
Map<String, Foo> idToFooMap = fDefs.stream()
.filter(f -> fooStr.contains(f.getId()))
.collect(Collectors.toMap(Foo::getId, f -> f));
Upvotes: 2
Reputation: 7828
Though ggreiner has already provided a working solution, when there are duplicates you'd better handle it including a mergeFunction
.
Directly using Collectors.toMap(keyMapper, valueMapper), one or another day you will encounter this following issue.
If the mapped keys contains duplicates (according to Object.equals(Object)), an IllegalStateException is thrown when the collection operation is performed. If the mapped keys may have duplicates, use toMap(Function, Function, BinaryOperator) instead.
Based on the OP's solution, I think it would be better using
import static java.util.stream.Collectors.*; // save some typing and make it cleaner;
fDefs.stream()
.filter(foo -> fooStr.contains(foo.getId()))
.collect(toMap(Foo::getId, foo -> foo, (oldFoo, newFoo) -> newFoo));
Upvotes: 2
Reputation: 11779
When including items conditionally in the final output use filter
and when going from stream to a map use Collectors.toMap
. Here's what you end up with:
Map<String,Foo> filterMethod (final Set<String> fooStr) {
List<Foo> fDefs; // list of Foo objects
return fDefs.stream()
.filter(foo -> fooStr.contains(foo.getId()))
.collect(Collectors.toMap(Foo::getId, Function.identity()));
}
Upvotes: 2
Reputation: 989
Maybe something like this?
Map<String,Foo> filterMethod (Set<String> fooStr) {
List<Foo> fDefs; // get this list from somewhere
Map<String, Foo> fObjMap = new HashMap<> ();
fDefs.stream()
.filter(foo -> fooStr.contains(foo.getId()))
.forEach(foo -> fObjMap.put(foo.getId(), foo))
return fObjMap;
}
Upvotes: 0