首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >Streams Java 8-重构流代码

Streams Java 8-重构流代码
EN

Stack Overflow用户
提问于 2018-02-01 15:23:07
回答 3查看 864关注 0票数 1

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

代码语言:javascript
复制
    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);

我需要一种仅从上面的流代码中提取/重构以下逻辑的方法,因为这部分将只更改我所拥有的其他映射列表:

代码语言:javascript
复制
if (v.getKey().equals("bar")) {
    m.put(v.getKey(), v.getValue() * 2);
} else {
    m.put(v.getKey(), v.getValue());
}

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

代码语言:javascript
复制
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是一个独立的功能接口,如下所示:

代码语言:javascript
复制
BiConsumer biconsumerLogic1() {
    accept(m, v) {
         //logic goes here...
    }
}

我怎样才能做到这一点?任何指点都会受到赞赏。

谢谢..

EN

回答 3

Stack Overflow用户

回答已采纳

发布于 2018-02-01 20:33:22

下面是我使用BiConsumers进行重构的版本:

代码语言:javascript
复制
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());
    };
}

我可以利用更多的控制,并将累加器动态注入到processMapData函数中。感谢@Federico的BiConsumer函数建议。

票数 2
EN

Stack Overflow用户

发布于 2018-02-01 15:41:31

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

看:

代码语言:javascript
复制
List<Map<String, Integer>> newList = new ArrayList<>(list);

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

要替换这个动作,你需要做这样的事情:

代码语言:javascript
复制
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;
});

现在,您可以将整个过程提取到一个单独的方法中,并接受listaction (也可能是"bar"变量)作为参数,这里有您的值替换器。

票数 3
EN

Stack Overflow用户

发布于 2018-02-01 15:27:34

不如:

代码语言:javascript
复制
list5.stream().forEach(map -> map.replaceAll((k,v) -> k.equals("bar") ? v * 2 : v));

这将对值进行就地替换。

如果你绝对需要一张新地图:

代码语言:javascript
复制
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,如:

代码语言:javascript
复制
public static BiFunction<String, Integer, Integer> valueCalculator() {
    return (k,v) -> k.equals("bar") ? v * 2 : v;
}

并使用:

代码语言:javascript
复制
list5.stream().forEach(map -> map.replaceAll(valueCalculator()));

备选案文2:

创建一个方法:

代码语言:javascript
复制
public Integer valueCalculator(String key, Integer value) {
    return key.equals("bar") ? value * 2 : value;
}

使用方法引用

代码语言:javascript
复制
list5.stream().forEach(map -> map.replaceAll(this::valueCalculator));

如果它是static方法,则为:

代码语言:javascript
复制
list5.stream().forEach(map -> map.replaceAll(MyClass::valueCalculator));

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

票数 1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/48566208

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档