简体   繁体   中英

Map key value to an object in Java 8 stream

Let's say I have this code:

Map<String, String> map;
// later on
map.entrySet().stream().map(MyObject::new).collect(Collectors.toList());

And I have a MyObject Constructor which takes two arguments of type String . I want to be able to do this but I cannot. I know I can do e -> new MyObject(e.getKey(), e.getValue()) but prefer MyObject::new .

Similar code works for Set<String> and List<String> with one argument constructor of MyObject class.

use a lambda:

map.entrySet()
   .stream()
   .map(e -> new MyObject(e.getKey(), e.getValue()))
   .collect(Collectors.toList());

otherwise the only way to use a method reference is by creating a function as such:

private static MyObject apply(Map.Entry<String, String> e) {
      return new MyObject(e.getKey(), e.getValue());
}

then do something like:

map.entrySet()
   .stream()
   .map(Main::apply)
   .collect(Collectors.toList());

Where Main is the class containing the apply method.

 map.entrySet().stream().map(MyObject::new).collect(Collectors.toList())); 

And I have a MyObject Constructor which takes two arguments of type String . I want to be able to do this but I cannot.

In map.entrySet().stream().map(...) , Java is expecting a Function , mapping one value to another value. One value. From the stream, the function receives a value of type Map.Entry<String, String> , but your constructor takes two String arguments. Java doesn't automagically expand a Map.Entry<String, String> to a pair of String s to pass to your constructor. You have to do that unwrapping manually.

Add a Map.Entry constructor

class MyObject {
        private final String k;
        private final String v;

        MyObject(String s1, String s2) {
            k = s1;
            v = s2;
        }

        MyObject(Map.Entry<String, String> e) {
            this(e.getKey(), e.getValue());
        }

        public String toString() {
            return "key: " + k + ' ' + "value: " + v;
        }
    }

You will be able to call

List<MyObject> myObjectList = map.entrySet().stream().map(MyObject::new).collect(Collectors.toList());

The problem with the constructor is that it defines two parameters, while Function#apply demanded by Stream#map accepts only one.

You could write a static factory method for MyObject

class MyObject {
    public static MyObject of(Map.Entry<String, String> e) {
        return new MyObject(e.getKey(), e.getValue());
    }
}

and refer to it like

map(MyObject::of)

Before you do so, ask yourself if one pretty-looking line in a plain processing chain somewhere is worthy of a new constructor or utility method.

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