Java8中方便又实用的Map函数总结

目录
  • 简介
  • computeIfAbsent函数
  • computeIfPresent函数
  • compute函数
  • merge函数
  • putIfAbsent函数
  • forEach函数
  • 总结

简介

java8之后,常用的Map接口中添加了一些非常实用的函数,可以大大简化一些特定场景的代码编写,提升代码可读性,一起来看看吧。

computeIfAbsent函数

比如,很多时候我们需要对数据进行分组,变成Map<Integer, List<?>>的形式,在java8之前,一般如下实现:

List<Payment> payments = getPayments();
Map<Integer, List<Payment>> paymentByTypeMap = new HashMap<>();
for(Payment payment : payments){
    if(!paymentByTypeMap.containsKey(payment.getPayTypeId())){
        paymentByTypeMap.put(payment.getPayTypeId(), new ArrayList<>());
    }
    paymentByTypeMap.get(payment.getPayTypeId())
            .add(payment);
}

可以发现仅仅做一个分组操作,代码却需要考虑得比较细致,在Map中无相应值时需要先塞一个空List进去。

但如果使用java8提供的computeIfAbsent方法,代码则会简化很多,如下:

List<Payment> payments = getPayments();
Map<Integer, List<Payment>> paymentByTypeMap = new HashMap<>();
for(Payment payment : payments){
    paymentByTypeMap.computeIfAbsent(payment.getPayTypeId(), k -> new ArrayList<>())
            .add(payment);
}

computeIfAbsent方法的逻辑是,如果map中没有(Absent)相应的key,则执行lambda表达式生成一个默认值并放入map中并返回,否则返回map中已有的值。

带默认值Map由于这种需要默认值的Map太常用了,我一般会封装一个工具类出来使用,如下:

public class DefaultHashMap<K, V> extends HashMap<K, V> {
    Function<K, V> function;

    public DefaultHashMap(Supplier<V> supplier) {
        this.function = k -> supplier.get();
    }

    @Override
    @SuppressWarnings("unchecked")
    public V get(Object key) {
        return super.computeIfAbsent((K) key, this.function);
    }
}

然后再这么使用,如下:

List<Payment> payments = getPayments();
Map<Integer, List<Payment>> paymentByTypeMap = new DefaultHashMap<>(ArrayList::new);
for(Payment payment : payments){
    paymentByTypeMap.get(payment.getPayTypeId())
            .add(payment);
}

呵呵,这玩得有点像python的defaultdict(list)

临时Cache有时,在一个for循环中,需要一个临时的Cache在循环中复用查询结果,也可以使用computeIfAbcent,如下:

List<Payment> payments = getPayments();
Map<Integer, PayType> payTypeCacheMap = new HashMap<>();
for(Payment payment : payments){
    PayType payType = payTypeCacheMap.computeIfAbsent(payment.getPayTypeId(),
            k -> payTypeMapper.queryByPayType(k));
    payment.setPayTypeName(payType.getPayTypeName());
}

因为payments中不同payment的pay_type_id极有可能相同,使用此方法可以避免大量重复查询,但如果不用computeIfAbcent函数,代码就有点繁琐晦涩了。

computeIfPresent函数

computeIfPresent函数与computeIfAbcent的逻辑是相反的,如果map中存在(Present)相应的key,则对其value执行lambda表达式生成一个新值并放入map中并返回,否则返回null。

这个函数一般用在两个集合做等值关联的时候,可少写一次判断逻辑,如下:

@Data
public static class OrderPayment {
    private Order order;
    private List<Payment> payments;

    public OrderPayment(Order order) {
        this.order = order;
        this.payments = new ArrayList<>();
    }

    public OrderPayment addPayment(Payment payment){
        this.payments.add(payment);
        return this;
    }
}
public static void getOrderWithPayment(){
    List<Order> orders = getOrders();
    Map<Long, OrderPayment> orderPaymentMap = new HashMap<>();
    for(Order order : orders){
        orderPaymentMap.put(order.getOrderId(), new OrderPayment(order));
    }
    List<Payment> payments = getPayments();
    //将payment关联到相关的order上
    for(Payment payment : payments){
        orderPaymentMap.computeIfPresent(payment.getOrderId(),
                (k, orderPayment) -> orderPayment.addPayment(payment));
    }
}

compute函数

compute函数,其实和computeIfPresent、computeIfAbcent函数是类似的,不过它不关心map中到底有没有值,都执行lambda表达式计算新值并放入map中并返回。

这个函数适合做分组迭代计算,像分组汇总金额的情况,就适合使用compute函数,如下:

List<Payment> payments = getPayments();
Map<Integer, BigDecimal> amountByTypeMap = new HashMap<>();
for(Payment payment : payments){
    amountByTypeMap.compute(payment.getPayTypeId(),
            (key, oldVal) -> oldVal == null ? payment.getAmount() : oldVal.add(payment.getAmount())
    );
}

当oldValue是null,表示map中第一次计算相应key的值,直接给amount就好,而后面再次累积计算时,直接通过add函数汇总就好。

merge函数

可以发现,上面在使用compute汇总金额时,lambda表达式中需要判断是否是第一次计算key值,稍微麻烦了点,而使用merge函数的话,可以进一步简化代码,如下:

List<Payment> payments = getPayments();
Map<Integer, BigDecimal> amountByTypeMap = new HashMap<>();
for(Payment payment : payments){
    amountByTypeMap.merge(payment.getPayTypeId(), payment.getAmount(), BigDecimal::add);
}

这个函数太简洁了,merge的第一个参数是key,第二个参数是value,第三个参数是值合并函数。

当是第一次计算相应key的值时,直接放入value到map中,后面再次计算时,使用值合并函数BigDecimal::add计算出新的汇总值,并放入map中即可。

putIfAbsent函数

putIfAbsent从命名上也能知道作用了,当map中没有相应key时才put值到map中,主要用于如下场景:
如将list转换为map时,若list中有重复值时,put与putIfAbsent的区别如下:

  • put保留最晚插入的数据。
  • putIfAbsent保留最早插入的数据。

forEach函数

说实话,java中要遍历map,写法上是比较啰嗦的,不管是entrySet方式还是keySet方式,如下:

for(Map.Entry<String, BigDecimal> entry: amountByTypeMap.entrySet()){
    Integer payTypeId = entry.getKey();
    BigDecimal amount = entry.getValue();
    System.out.printf("payTypeId: %s, amount: %s \n", payTypeId, amount);
}

再看看在python或go中的写法,如下:

for payTypeId, amount in amountByTypeMap.items():
    print("payTypeId: %s, amount: %s \n" % (payTypeId, amount))

可以发现,在python中的map遍历写法要少写好几行代码呢,不过,虽然java在语法层面上并未支持这种写法,但使用map的forEach函数,也可以简化出类似的效果来,如下:

amountByTypeMap.forEach((payTypeId, amount) -> {
    System.out.printf("payTypeId: %s, amount: %s \n", payTypeId, amount);
});

总结

一直以来,java因代码编写太繁琐而被开发者们所广泛诟病,但从java8开始,从Map、Stream、var、multiline-string再到record,java在代码编写层面做了大量的简化,java似乎开窍了

到此这篇关于Java8中方便又实用的Map函数总结的文章就介绍到这了,更多相关Java8 Map函数内容请搜索我们以前的文章或继续浏览下面的相关文章希望大家以后多多支持我们!

(0)

相关推荐

  • Java8如何基于flatMap处理异常函数

    Java8的flatMap函数,作用是:如果有值,为其执行mapping函数返回Optional类型返回值,否则返回空Optional. 见到的映射函数往往都只有一句话,连大括号都不需要加的,如下: String personValue = Optional.ofNullable(map.get("person")) .flatMap(value -> Optional.of(value.toString().trim())) .orElse(""); 可是如

  • Java 8 中 Map 骚操作之 merge() 的使用方法

    Java 8 最大的特性无异于更多地面向函数,比如引入了lambda等,可以更好地进行函数式编程.前段时间无意间发现了map.merge()方法,感觉还是很好用的,此文简单做一些相关介绍.首先我们先看一个例子. merge()怎么用? 假设我们有这么一段业务逻辑,我有一个学生成绩对象的列表,对象包含学生姓名.科目.科目分数三个属性,要求求得每个学生的总成绩.加入列表如下: private List<StudentScore> buildATestList() { List<Student

  • Java8中方便又实用的Map函数总结

    目录 简介 computeIfAbsent函数 computeIfPresent函数 compute函数 merge函数 putIfAbsent函数 forEach函数 总结 简介 java8之后,常用的Map接口中添加了一些非常实用的函数,可以大大简化一些特定场景的代码编写,提升代码可读性,一起来看看吧. computeIfAbsent函数 比如,很多时候我们需要对数据进行分组,变成Map<Integer, List<?>>的形式,在java8之前,一般如下实现: List<

  • 浅析Java8 中 Map 接口的新方法

    我们提一个需求:给定一个 List<String> ,统计每个元素出现的所有位置. 比如,给定 list: ["a", "b", "b", "c", "c", "c", "d", "d", "d", "f", "f", "g"] ,那么应该返回: a : [

  • 关于Java8中map()和flatMap()的一些事

    两个方法的背景 这两个方法看起来做着同样的事情,但实际上又有些不一样.看源码部分是这样的 package java.util.stream; map()方法 /** * @param <R> The element type of the new stream * @param mapper a <a href="package-summary.html#NonInterference" rel="external nofollow" rel=&q

  • java8中Map的一些骚操作总结

    一 前言 本篇内容是关于 map 新特性的一些方法使用上的介绍,如果有不足之处欢迎补充!! 二 map新特性 关于以下函数式编程的函数的计算知识追寻者都使用 简单字符串代替了,参数无非就是Key,value: 2.1 forEach forEach迭代,相当于for循环 public static void main(String[] args) { HashMap<String, Object> hashMap = new HashMap<>(); hashMap.put(&qu

  • Java8中List转Map(Collectors.toMap) 的技巧分享

    前言 在实际项目中我们经常会用到 List 转 Map 操作,在过去我们可能使用的是 for 循环遍历的方式.举个例子: 先定义类: // 简单对象 @Accessors(chain = true) // 链式方法 @lombok.Data class User { private String id; private String name; } 然后有这样一个 List: List<User> userList = Lists.newArrayList( new User().setId(

  • python中map()函数的使用方法示例

    前言 在python里有一个函数map(),它有点高大上的感觉.本文将详细给大家介绍python中map()函数使用的相关内容,分享出来供大家参考学习,下面话不多说了,来一起看看详细的介绍: 或许你已经看过GOOGLE最挣钱的论文: "MapReduce: Simplified Data Processing on Large Clusters" Google的那篇MapReduce论文里说:Our abstraction is inspired by the map and redu

  • Jquery中map函数的用法

    很久没用map()这个函数了,由于最近看一篇react的文章,其中有谈到map()这个函数,于是就重新查了一些资料,发现map()函数可以用在不同的地方,下面小编总结具有内容分享给大家,也方便今后查找. 其实,本人一直很少用map()这个函数,因为最近看一篇React的文章,其实有谈及map()函数,于是自己也重新查了一些资料,发现map()函数也可以用在不同的地方: map()函数把每个元素通过函数传递到当前匹配集合中,生成包含返回值的新的Jquery对象 语法:.map(callback(i

  • jquery中map函数遍历数组用法实例

    本文实例讲述了jquery中map函数遍历数组用法.分享给大家供大家参考.具体如下: <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> <html xmlns="http://www.w3.org/1999/xhtml"> <

  • jquery中map函数与each函数的区别实例介绍

    ​jquery中的each函数和map函数的用法看起来差不多,但其实还是有一点区别的. ​其中一个重要的区别是,each返回的是原来的数组,并不会新创建一个数组.而map方法会返回一个新的数组.如果在没有必要的情况下使用map,则有可能造成内存浪费. ​例如: var items = [1,2,3,4]; $.each(items, function() { alert('this is ' + this); }); var newItems = $.map(items, function(i)

  • jQuery中map函数的两种方式

    两种方式: 1.直接jQuery.map //将原数组中每个元素加 4 转换为一个新数组. $.map( [0,1,2], function(n){ return n + 4; }); //结果: [4, 5, 6] //原数组中每个元素扩展为一个包含其本身和其值加 1 的数组,并转换为一个新数组 $.map( [0,1,2], function(n){ return [ n, n + 1 ]; }); //结果: [0, 1, 1, 2, 2, 3] 2.遍历对象.map 例子: <form

随机推荐