我知道如何“转换”一个简单的Java列表从Y -> Z,即:

List<String> x;
List<Integer> y = x.stream()
        .map(s -> Integer.parseInt(s))
        .collect(Collectors.toList());

现在我想对Map做基本相同的事情,即:

INPUT:
{
  "key1" -> "41",    // "41" and "42"
  "key2" -> "42"      // are Strings
}

OUTPUT:
{
  "key1" -> 41,      // 41 and 42
  "key2" -> 42       // are Integers
}

解决方案不应局限于String -> Integer。就像上面的List示例一样,我想调用任何方法(或构造函数)。


当前回答

另一种学习方法是通过collector .of()构建自定义收集器,不过这里的toMap() JDK收集器比较简洁(这里是+1)。

Map<String,Integer> newMap = givenMap.
                entrySet().
                stream().collect(Collector.of
               ( ()-> new HashMap<String,Integer>(),
                       (mutableMap,entryItem)-> mutableMap.put(entryItem.getKey(),Integer.parseInt(entryItem.getValue())),
                       (map1,map2)->{ map1.putAll(map2); return map1;}
               ));

其他回答

番石榴的功能图。transformValues是你要找的,它可以很好地与lambda表达式一起工作:

Maps.transformValues(originalMap, val -> ...)
Map<String, String> x;
Map<String, Integer> y =
    x.entrySet().stream()
        .collect(Collectors.toMap(
            e -> e.getKey(),
            e -> Integer.parseInt(e.getValue())
        ));

它不像列表代码那么好。你不能构造新的地图。映射到map()调用中,因此工作被混合到collect()调用中。

另一种学习方法是通过collector .of()构建自定义收集器,不过这里的toMap() JDK收集器比较简洁(这里是+1)。

Map<String,Integer> newMap = givenMap.
                entrySet().
                stream().collect(Collector.of
               ( ()-> new HashMap<String,Integer>(),
                       (mutableMap,entryItem)-> mutableMap.put(entryItem.getKey(),Integer.parseInt(entryItem.getValue())),
                       (map1,map2)->{ map1.putAll(map2); return map1;}
               ));

尽管可以在流的collect部分重新映射键或/和值,如其他答案所示,但我认为它应该属于map部分,因为该函数被设计用于转换流中的数据。其次,它应该易于重复,而不会引入额外的复杂性。可以使用SimpleEntry对象,该对象自Java 6以来已经可用。

使用java8

import java.util.AbstractMap.SimpleEntry;
import java.util.Map;
import java.util.Map.Entry;
import java.util.stream.Collectors;

public class App {

    public static void main(String[] args) {
        Map<String, String> x;
        Map<String, Integer> y = x.entrySet().stream()
                .map(entry -> new SimpleEntry<>(entry.getKey(), Integer.parseInt(entry.getValue())))
                .collect(Collectors.toMap(Entry::getKey, Entry::getValue));
    }

}

使用Java 9+

随着Java 9的发布,Map接口内引入了一个静态方法,以便更容易地创建一个条目,而不需要实例化一个新的SimpleEntry,如前面的示例所示。

import java.util.Map;
import java.util.Map.Entry;
import java.util.stream.Collectors;

public class App {

    public static void main(String[] args) {
        Map<String, String> x;
        Map<String, Integer> y = x.entrySet().stream()
                .map(entry -> Map.entry((entry.getKey(), Integer.parseInt(entry.getValue())))
                .collect(Collectors.toMap(Entry::getKey, Entry::getValue));
    }

}

像这样的一般解

public static <X, Y, Z> Map<X, Z> transform(Map<X, Y> input,
        Function<Y, Z> function) {
    return input
            .entrySet()
            .stream()
            .collect(
                    Collectors.toMap((entry) -> entry.getKey(),
                            (entry) -> function.apply(entry.getValue())));
}

例子

Map<String, String> input = new HashMap<String, String>();
input.put("string1", "42");
input.put("string2", "41");
Map<String, Integer> output = transform(input,
            (val) -> Integer.parseInt(val));