Streams Java 8 - 重构流代码

时间:2018-02-01 15:23:08

标签: java-8 refactoring java-stream

我需要重构我的下面的流代码:

    List<Map<String, Integer>> list5 = new ArrayList<>();
    map3 = new HashMap<>();
    map3.put("foo", 1);
    map3.put("bar", 2);
    map3.put("zzz", 6);
    list5.add(map3);
    map3 = new HashMap<>();
    map3.put("foo", 3);
    map3.put("bar", 4);
    map3.put("zzz", null);
    list5.add(map3);

    //new list with processed maps
    List<Map<String, Integer>> list6 = list5.stream()
            .map(hashmap -> {
                Map<String, Integer> newMap = hashmap.entrySet().stream()
                        .collect(HashMap::new, (m, v) -> {
                            if (v.getKey().equals("bar")) {
                                m.put(v.getKey(), v.getValue() * 2);
                            } else {
                                m.put(v.getKey(), v.getValue());
                            }
                        }, HashMap::putAll);
                return newMap;
            })
            .collect(toList());
    System.out.println(list6);

我需要一种方法来仅从上面的流代码中提取/重构下面的逻辑,因为这篇文章只会在我拥有的其他地图列表中改变:

if (v.getKey().equals("bar")) {
    m.put(v.getKey(), v.getValue() * 2);
} else {
    m.put(v.getKey(), v.getValue());
}

使用IntelliJ,它会向main()本身添加一个双音素,这在这里是不期望的,并删除了代码。我需要一种方法来单独提取它,如下所示:

List<Map<String, Integer>> list6 = list5.stream()
            .map(hashmap -> {
                Map<String, Integer> newMap = hashmap.entrySet().stream()
                        .collect(HashMap::new, (m, v) -> {
                            biconsumerLogic1.accept(m, v);
                        }, HashMap::putAll);
                return newMap;
            })
            .collect(toList());

而biconsumerLogic1是一个独立的功能界面,如:

BiConsumer biconsumerLogic1() {
    accept(m, v) {
         //logic goes here...
    }
}

我如何实现这一目标?任何指针都表示赞赏。

谢谢..

4 个答案:

答案 0 :(得分:3)

看,问题在于使用流。你已经过度设计了,你不需要大部分。

查找

BiFunction<String, Integer, Integer> action = (k,v) -> v * 2;

newList.replaceAll(eachMap -> {
  Map<String, Integer> map = new HashMap<>(eachMap);
  map.computeIfPresent("bar", action);
  return map;
});

要替换动作,您需要执行以下操作:

list

现在,您可以将整个事物提取到一个单独的方法中,并接受action"bar"(可能还有{{1}}变量)作为参数,这里您有值替换器。

答案 1 :(得分:2)

我认为有更好的方法来做你实际做的事情。但严格回答如何提取和重构指定的代码,您可以这样做:

static <K, V> List<Map<K, V>> process(
        List<Map<K, V>> source,
        BiConsumer<? super Map<K, V>, ? super Map.Entry<K, V>> accumulator) {

    return source.stream()
        .map(m -> m.entrySet().stream()
            .collect(HashMap::new, accumulator, Map::putAll))
        .collect(Collectors.toList());
}

用法:

List<Map<String, Integer>> list6 = process(
    list5,
    (m, e) -> m.put(
        e.getKey(), 
        e.getKey().equals("bar") ? e.getValue() * 2 : e.getValue()));

答案 2 :(得分:2)

以下是我使用BiConsumers重构的版本:

Cars Inspected = 
VAR selectedMonth = MONTH(MAX('All Cars Inspected'[Workday]))
RETURN LOOKUPVALUE(Targets[Target],
           Targets[Location], "Texas",
           Targets[Description], "CarsInspected",
           Targets[sMonth], selectedMonth)

我可以利用更多控制并动态地将累加器注入psv main(...) { List<Map<String, Integer>> newList = processMapData(origList, accumulator()); System.out.println(newList); } private static List<Map<String, Integer>> processMapData(List<Map<String, Integer>> origList, BiConsumer<HashMap<String, Integer>, Map.Entry<String, Integer>> accumulator) { return origList.stream() .map(hashmap -> { Map<String, Integer> newMap = hashmap.entrySet().stream() .collect(HashMap::new, accumulator, HashMap::putAll); return newMap; }) .collect(toList()); } private static BiConsumer<HashMap<String, Integer>, Map.Entry<String, Integer>> accumulator() { return (m, v) -> { m.put(v.getKey(), v.getKey().equals("bar") ? v.getValue() * 2: v.getValue()); }; } 函数。 感谢@Federico提供的BiConsumer功能建议。

答案 3 :(得分:1)

怎么样:

list5.stream().forEach(map -> map.replaceAll((k,v) -> k.equals("bar") ? v * 2 : v));

这可以就地替换值。

如果您绝对需要地图:

list6 = list5.stream()
    .map(m -> m.entrySet().stream()
        .collect(toMap(Map.Entry::getKey, e -> e.getValue() * (e.getKey().equals("bar") ?  2 : 1))))
    .collect(toList());

如果您正在寻求重构,有两种选择:

选项1:

创建BiFunction,例如:

public static BiFunction<String, Integer, Integer> valueCalculator() {
    return (k,v) -> k.equals("bar") ? v * 2 : v;
}

并使用:

list5.stream().forEach(map -> map.replaceAll(valueCalculator()));

选项2:

创建方法:

public Integer valueCalculator(String key, Integer value) {
    return key.equals("bar") ? value * 2 : value;
}

要使用,请使用方法参考

list5.stream().forEach(map -> map.replaceAll(this::valueCalculator));

如果它是static方法:

list5.stream().forEach(map -> map.replaceAll(MyClass::valueCalculator));

我更喜欢选项2,因为它更容易理解,测试和调试。