简体   繁体   中英

Java8 lambda approach

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

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()));
}

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));

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));

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;
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM