前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >JAVA知识回顾之Java8 Merge

JAVA知识回顾之Java8 Merge

作者头像
Jetpropelledsnake21
发布2022-09-29 11:16:57
3110
发布2022-09-29 11:16:57
举报
文章被收录于专栏:JetpropelledSnake

0x00 概述

本文主要讲述Java8 Map的merger操作。

0x01 用例和代码

代码语言:javascript
复制
//计算唯一的单词出现次数
var map = new HashMap<String, Integer>();
words.forEach(word -> {
    var prev = map.get(word);
    if (prev == null) {
        map.put(word, 1);
    } else {
        map.put(word, prev + 1);
    }
});
代码语言:javascript
复制
//给定输入 对应的输出结果
var words = List.of("Foo", "Bar", "Foo", "Buzz", "Foo", "Buzz", "Fizz", "Fizz");
//...
{Bar=1, Fizz=2, Foo=3, Buzz=2}
代码语言:javascript
复制
//进行重构以避免条件逻辑
words.forEach(word -> {
    map.putIfAbsent(word, 0);
    map.put(word, map.get(word) + 1);
});

putIfAbsent()是必要的,否则代码会在第一次出现未知的单词时中断,另外map.get(word) 里面map.put() 有点尴尬。

代码语言:javascript
复制
words.forEach(word -> {
    map.putIfAbsent(word, 0);
    map.computeIfPresent(word, (w, prev) -> prev + 1);
});

仅当question(word)中的键存在时才调用给定的转换。否则它什么都不做。

代码语言:javascript
复制
words.forEach(word ->
        map.compute(word, (w, prev) -> prev != null ? prev + 1 : 1)
);

compute()就像是computeIfPresent(),无论给定key是否存在都会调用它。如果键的值不存在,则prev参数为null。

实现一个简单的merge:

代码语言:javascript
复制
default V merge(K key, V value, BiFunction<V, V, V> remappingFunction) {
    V oldValue = get(key);
    V newValue = (oldValue == null) ? value :
               remappingFunction.apply(oldValue, value);
    if (newValue == null) {
        remove(key);
    } else {
        put(key, newValue);
    }
    return newValue;
}

merge() 适用于两种情况。如果给定的Key值不存在,它就变成了put(key, value)。但如果所述Key已经存值,remappingFunction可以操作合并:

  • 只需返回新值覆盖旧值: (old, new) -> new
  • 只需返回旧值保留旧值: (old, new) -> old
  • 以某种方式合并两者,例如: (old, new) -> old + new
  • 甚至删除旧值: (old, new) -> null
代码语言:javascript
复制
//1 的下word ,如果没有key就将1添加到现有值。
words.forEach(word ->
        map.merge(word, 1, (prev, one) -> prev + one)
);

使用merge()模拟一个帐户操作:

代码语言:javascript
复制
//vo
class Operation {
    private final String accNo;
    private final BigDecimal amount;
}
//针对不同账户的操作

var operations = List.of(
    new Operation("123", new BigDecimal("10")),
    new Operation("456", new BigDecimal("1200")),
    new Operation("123", new BigDecimal("-4")),
    new Operation("123", new BigDecimal("8")),
    new Operation("456", new BigDecimal("800")),
    new Operation("456", new BigDecimal("-1500")),
    new Operation("123", new BigDecimal("2")),
    new Operation("123", new BigDecimal("-6.5")),
    new Operation("456", new BigDecimal("-600"))
);

如果想要为每个账户计算余额,不使用merge:

代码语言:javascript
复制
var balances = new HashMap<String, BigDecimal>();
operations.forEach(op -> {
    var key = op.getAccNo();
    balances.putIfAbsent(key, BigDecimal.ZERO);
    balances.computeIfPresent(key, (accNo, prev) -> prev.add(op.getAmount()));
});

使用merge():

代码语言:javascript
复制
operations.forEach(op ->
        balances.merge(op.getAccNo(), op.getAmount(), 
                (soFar, amount) -> soFar.add(amount))
);

operations.forEach(op ->
        balances.merge(op.getAccNo(), op.getAmount(), BigDecimal::add)
);

//{123=9.5, 456=-100}

完整代码:

代码语言:javascript
复制
package other;

import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import lombok.Data;
import org.junit.Test;

import java.util.*;

/**
 * @author liuqian
 * @date 2019/10/7 19:11.
 */
public class MapMethodsTest {

    @Test
    public void mapMergeTest() throws JsonProcessingException {
        ObjectMapper objectMapper = new ObjectMapper();
        List<StudentScore> studentScoreList = buildATestList();
        // 按照学生分组,求得每个学生的总分
        // 常规做法
        Map<String, Integer> studentScoreMap = new HashMap<>();
        studentScoreList.forEach(studentScore -> {
            if (studentScoreMap.containsKey(studentScore.getStuName())) {
                studentScoreMap.put(studentScore.getStuName(), studentScoreMap.get(studentScore.getStuName()) + studentScore.getScore());
            } else {
                studentScoreMap.put(studentScore.getStuName(), studentScore.getScore());
            }
        });
        // {"李四":228,"张三":215,"王五":235}
        System.out.println(objectMapper.writeValueAsString(studentScoreMap));

        // merge() 方法
        Map<String, Integer> studentScoreMap2 = new HashMap<>();
        studentScoreList.forEach(studentScore -> studentScoreMap2.merge(
                studentScore.getStuName(),
                studentScore.getScore(),
                Integer::sum));
        // {"李四":228,"张三":215,"王五":235}
        System.out.println(objectMapper.writeValueAsString(studentScoreMap2));
    }

    @Test
    public void mapComputeTest() {
        String k = "key";
        Map<String, Integer> map = new HashMap<String, Integer>() {{
            put(k, 1);
        }};
        // 2
        System.out.println(map.compute(k, (key, oldVal) -> oldVal + 1));
    }

    @Test
    public void mapCountComputeTest() {
        List<String> words = new ArrayList<String>() {{
            add("A");
            add("B");
            add("C");
            add("A");
            add("C");
            add("E");
            add("E");
            add("E");
            add("E");
            add("A");
            add("E");
        }};
        // the word appear times
        Map<String, Integer> wordCountMap = new HashMap<>();
        words.forEach(word -> wordCountMap.compute(word, (key, oldCount) -> {
            if (Objects.isNull(oldCount)) {
                return 1;
            }
            return oldCount + 1;
        }));
        System.out.println(wordCountMap);
    }

    private List<StudentScore> buildATestList() {
        List<StudentScore> studentScoreList = new ArrayList<>();
        StudentScore studentScore1 = new StudentScore() {{
            setStuName("张三");
            setSubject("语文");
            setScore(70);
        }};
        StudentScore studentScore2 = new StudentScore() {{
            setStuName("张三");
            setSubject("数学");
            setScore(80);
        }};
        StudentScore studentScore3 = new StudentScore() {{
            setStuName("张三");
            setSubject("英语");
            setScore(65);
        }};
        StudentScore studentScore4 = new StudentScore() {{
            setStuName("李四");
            setSubject("语文");
            setScore(68);
        }};
        StudentScore studentScore5 = new StudentScore() {{
            setStuName("李四");
            setSubject("数学");
            setScore(70);
        }};
        StudentScore studentScore6 = new StudentScore() {{
            setStuName("李四");
            setSubject("英语");
            setScore(90);
        }};
        StudentScore studentScore7 = new StudentScore() {{
            setStuName("王五");
            setSubject("语文");
            setScore(80);
        }};
        StudentScore studentScore8 = new StudentScore() {{
            setStuName("王五");
            setSubject("数学");
            setScore(85);
        }};
        StudentScore studentScore9 = new StudentScore() {{
            setStuName("王五");
            setSubject("英语");
            setScore(70);
        }};

        studentScoreList.add(studentScore1);
        studentScoreList.add(studentScore2);
        studentScoreList.add(studentScore3);
        studentScoreList.add(studentScore4);
        studentScoreList.add(studentScore5);
        studentScoreList.add(studentScore6);
        studentScoreList.add(studentScore7);
        studentScoreList.add(studentScore8);
        studentScoreList.add(studentScore9);

        return studentScoreList;
    }

    @Data
    private class StudentScore {
        private String stuName;
        private String subject;
        private Integer score;
    }
}
本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
原始发表:2022-09-17,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 0x00 概述
  • 0x01 用例和代码
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档