欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

Java8中方便又實用的Map函數(shù)總結(jié)

 更新時間:2022年11月14日 10:50:43   作者:扣釘日記  
java8之后,常用的Map接口中添加了一些非常實用的函數(shù),可以大大簡化一些特定場景的代碼編寫,提升代碼可讀性,快跟隨小編一起來看看吧

簡介

java8之后,常用的Map接口中添加了一些非常實用的函數(shù),可以大大簡化一些特定場景的代碼編寫,提升代碼可讀性,一起來看看吧。

computeIfAbsent函數(shù)

比如,很多時候我們需要對數(shù)據(jù)進行分組,變成Map<Integer, List<?>>的形式,在java8之前,一般如下實現(xiàn):

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);
}

可以發(fā)現(xiàn)僅僅做一個分組操作,代碼卻需要考慮得比較細致,在Map中無相應(yīng)值時需要先塞一個空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)相應(yīng)的key,則執(zhí)行l(wèi)ambda表達式生成一個默認值并放入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循環(huán)中,需要一個臨時的Cache在循環(huán)中復(fù)用查詢結(jié)果,也可以使用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極有可能相同,使用此方法可以避免大量重復(fù)查詢,但如果不用computeIfAbcent函數(shù),代碼就有點繁瑣晦澀了。

computeIfPresent函數(shù)

computeIfPresent函數(shù)與computeIfAbcent的邏輯是相反的,如果map中存在(Present)相應(yīng)的key,則對其value執(zhí)行l(wèi)ambda表達式生成一個新值并放入map中并返回,否則返回null。

這個函數(shù)一般用在兩個集合做等值關(guān)聯(lián)的時候,可少寫一次判斷邏輯,如下:

@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關(guān)聯(lián)到相關(guān)的order上
    for(Payment payment : payments){
        orderPaymentMap.computeIfPresent(payment.getOrderId(),
                (k, orderPayment) -> orderPayment.addPayment(payment));
    }
}

compute函數(shù)

compute函數(shù),其實和computeIfPresent、computeIfAbcent函數(shù)是類似的,不過它不關(guān)心map中到底有沒有值,都執(zhí)行l(wèi)ambda表達式計算新值并放入map中并返回。

這個函數(shù)適合做分組迭代計算,像分組匯總金額的情況,就適合使用compute函數(shù),如下:

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())
    );
}

當(dāng)oldValue是null,表示map中第一次計算相應(yīng)key的值,直接給amount就好,而后面再次累積計算時,直接通過add函數(shù)匯總就好。

merge函數(shù)

可以發(fā)現(xiàn),上面在使用compute匯總金額時,lambda表達式中需要判斷是否是第一次計算key值,稍微麻煩了點,而使用merge函數(shù)的話,可以進一步簡化代碼,如下:

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

這個函數(shù)太簡潔了,merge的第一個參數(shù)是key,第二個參數(shù)是value,第三個參數(shù)是值合并函數(shù)。

當(dāng)是第一次計算相應(yīng)key的值時,直接放入value到map中,后面再次計算時,使用值合并函數(shù)BigDecimal::add計算出新的匯總值,并放入map中即可。

putIfAbsent函數(shù)

putIfAbsent從命名上也能知道作用了,當(dāng)map中沒有相應(yīng)key時才put值到map中,主要用于如下場景:
如將list轉(zhuǎn)換為map時,若list中有重復(fù)值時,put與putIfAbsent的區(qū)別如下:

  • put保留最晚插入的數(shù)據(jù)。
  • putIfAbsent保留最早插入的數(shù)據(jù)。

forEach函數(shù)

說實話,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))

可以發(fā)現(xiàn),在python中的map遍歷寫法要少寫好幾行代碼呢,不過,雖然java在語法層面上并未支持這種寫法,但使用map的forEach函數(shù),也可以簡化出類似的效果來,如下:

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

總結(jié)

一直以來,java因代碼編寫太繁瑣而被開發(fā)者們所廣泛詬病,但從java8開始,從Map、Stream、var、multiline-string再到record,java在代碼編寫層面做了大量的簡化,java似乎開竅了

到此這篇關(guān)于Java8中方便又實用的Map函數(shù)總結(jié)的文章就介紹到這了,更多相關(guān)Java8 Map函數(shù)內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • Java發(fā)起http請求的完整步驟記錄

    Java發(fā)起http請求的完整步驟記錄

    這篇文章主要給大家介紹了關(guān)于Java發(fā)起http請求的相關(guān)資料,文中通過示例代碼介紹的非常詳細,對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2021-02-02
  • Java實現(xiàn)房屋出租系統(tǒng)詳解

    Java實現(xiàn)房屋出租系統(tǒng)詳解

    這篇文章主要介紹了實現(xiàn)Java房屋出租系統(tǒng)的實現(xiàn)過程,文章條理清晰,在實現(xiàn)過程中加深了對相關(guān)概念的理解,具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2021-10-10
  • 詳解springboot設(shè)置cors跨域請求的兩種方式

    詳解springboot設(shè)置cors跨域請求的兩種方式

    這篇文章主要介紹了詳解springboot設(shè)置cors跨域請求的兩種方式,小編覺得挺不錯的,現(xiàn)在分享給大家,也給大家做個參考。一起跟隨小編過來看看吧
    2018-11-11
  • IntelliJ?IDEA快速查詢maven依賴關(guān)系圖文教程

    IntelliJ?IDEA快速查詢maven依賴關(guān)系圖文教程

    Maven提供了來查看依賴關(guān)系,而IDE往往提供了更加便利的方式,比如Eclipse或者IDEA都有類似的功能,下面這篇文章主要給大家介紹了關(guān)于IntelliJ?IDEA快速查詢maven依賴關(guān)系的相關(guān)資料,需要的朋友可以參考下
    2023-11-11
  • java實現(xiàn)本地緩存的示例代碼

    java實現(xiàn)本地緩存的示例代碼

    在高性能服務(wù)架構(gòu)設(shè)計中,緩存是不可或缺的環(huán)節(jié),因此這篇文章主要為大家詳細介紹了java中如何實現(xiàn)本地緩存,感興趣的小伙伴可以了解一下
    2024-01-01
  • java實現(xiàn)上傳文件到服務(wù)器和客戶端

    java實現(xiàn)上傳文件到服務(wù)器和客戶端

    這篇文章主要為大家詳細介紹了java實現(xiàn)上傳文件到服務(wù)器和客戶端,具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2018-01-01
  • Tomcat和Spring中的事件機制深入講解

    Tomcat和Spring中的事件機制深入講解

    這篇文章主要給大家介紹了關(guān)于Tomcat和Spring中事件機制的相關(guān)資料,文中通過示例代碼介紹的非常詳細,對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面來一起看看吧
    2018-12-12
  • Spring的自動裝配常用注解詳解

    Spring的自動裝配常用注解詳解

    這篇文章主要介紹了Spring的自動裝配常用注解詳解,自動裝配就是指 Spring 容器在不使用 <constructor-arg> 和<property> 標簽的情況下,可以自動裝配相互協(xié)作的 Bean 之間的關(guān)聯(lián)關(guān)系,將一個 Bean 注入其他 Bean 的 Property 中,需要的朋友可以參考下
    2023-08-08
  • 詳解Java類加載器與雙親委派機制

    詳解Java類加載器與雙親委派機制

    這篇文章主要為大家介紹一下Java中的類加載器與雙親委派機制,文中通過示例為大家進行了詳細的介紹,對我們學(xué)習(xí)Java有一定幫助,需要的可以參考一下
    2022-08-08
  • springboot2.0整合logback日志的詳細代碼

    springboot2.0整合logback日志的詳細代碼

    這篇文章主要介紹了springboot2.0整合logback日志的應(yīng)用場景分析,本文通過實例代碼給大家介紹的非常詳細,對大家的學(xué)習(xí)或工作具有一定的參考借鑒價值,需要的朋友可以參考下
    2022-02-02

最新評論