最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

Java使用record關(guān)鍵詞統(tǒng)計(jì)余額的示例代碼

 更新時(shí)間:2026年04月23日 08:43:30   作者:碼農(nóng)阿豪@新空間  
很多?Java?程序員在日常開發(fā)中都會(huì)遇到類似需求,那就是統(tǒng)計(jì)一批用戶當(dāng)前可用余額,本文解析了一段Java余額統(tǒng)計(jì)代碼的設(shè)計(jì)思想,感興趣的小伙伴可以了解下

Java record 關(guān)鍵詞+ Map 匯總統(tǒng)計(jì)實(shí)戰(zhàn):一段余額統(tǒng)計(jì)代碼背后的設(shè)計(jì)思想

很多 Java 程序員在日常開發(fā)中都會(huì)遇到類似需求:

統(tǒng)計(jì)一批用戶當(dāng)前可用余額

但當(dāng)代碼寫出來后,往往會(huì)變成一坨:

  • if/else 到處都是
  • BigDecimal 累加混亂
  • Map 使用不規(guī)范
  • DTO 寫一堆模板代碼

最近在項(xiàng)目中看到一段非常典型的實(shí)現(xiàn)代碼,涉及:

  • Java record
  • Map.getOrDefault
  • 批次余額統(tǒng)計(jì)
  • BigDecimal 累加
  • MyBatis LambdaQueryWrapper

雖然代碼不長(zhǎng),但里面隱藏著很多 值得學(xué)習(xí)的設(shè)計(jì)思想。

本文就帶大家 逐行拆解這段代碼,并分析背后的實(shí)現(xiàn)邏輯。

一、完整代碼

先看完整方法:

public Map<Long, BatchBalanceSummary> summarizeAvailableBalances(List<Long> userIds) {
    if (userIds == null || userIds.isEmpty()) {
        return Map.of();
    }

    List<Long> distinctUserIds = userIds.stream()
        .filter(java.util.Objects::nonNull)
        .distinct()
        .toList();

    if (distinctUserIds.isEmpty()) {
        return Map.of();
    }

    for (Long userId : distinctUserIds) {
        ensureUserBatchWallet(userId);
        expireIfNeeded(userId);
    }

    Map<Long, BatchBalanceSummary> result = new LinkedHashMap<>();

    for (Long userId : distinctUserIds) {
        result.put(userId, new BatchBalanceSummary(BigDecimal.ZERO, BigDecimal.ZERO));
    }

    List<AccountBatchEntity> batches = accountBatchMapper.selectList(
        new LambdaQueryWrapper<AccountBatchEntity>()
            .in(AccountBatchEntity::getUserId, distinctUserIds)
            .eq(AccountBatchEntity::getStatus, STATUS_ACTIVE)
            .gt(AccountBatchEntity::getRemainingAmount, BigDecimal.ZERO)
    );

    for (AccountBatchEntity batch : batches) {

        BatchBalanceSummary current =
            result.getOrDefault(batch.getUserId(),
                new BatchBalanceSummary(BigDecimal.ZERO, BigDecimal.ZERO));

        if (ACCOUNT_TYPE_PROMO.equalsIgnoreCase(batch.getAccountType())) {

            result.put(batch.getUserId(),
                new BatchBalanceSummary(
                    current.cashBalance(),
                    current.promoBalance()
                        .add(normalize(batch.getRemainingAmount()))
                ));

        } else {

            result.put(batch.getUserId(),
                new BatchBalanceSummary(
                    current.cashBalance()
                        .add(normalize(batch.getRemainingAmount())),
                    current.promoBalance()
                ));
        }
    }

    return result;
}

這段代碼的核心作用其實(shí)就是:

統(tǒng)計(jì)一批用戶當(dāng)前可用余額(現(xiàn)金 + 贈(zèng)送金)

返回結(jié)構(gòu):

userId -> 余額匯總

二、余額匯總對(duì)象:Java record

代碼中使用了 record 定義余額對(duì)象:

public record BatchBalanceSummary(
        BigDecimal cashBalance,
        BigDecimal promoBalance) {
}

record 是 Java 16 引入的 數(shù)據(jù)類語法糖

它會(huì)自動(dòng)生成:

  • 構(gòu)造函數(shù)
  • getter
  • equals
  • hashCode
  • toString

傳統(tǒng)寫法:

public class BatchBalanceSummary {

    private BigDecimal cashBalance;
    private BigDecimal promoBalance;

}

至少要寫幾十行代碼。

而 record:1 行搞定

record 編譯后結(jié)構(gòu)

BatchBalanceSummary

├── cashBalance
├── promoBalance
├── equals()
├── hashCode()
└── toString()

三、整體執(zhí)行流程

這段代碼整體流程如下:

可以看到整個(gè)過程非常清晰:

  • 輸入用戶列表
  • 數(shù)據(jù)清洗
  • 賬戶狀態(tài)校驗(yàn)
  • 查詢批次余額
  • 匯總統(tǒng)計(jì)

四、第一步:參數(shù)防御

if (userIds == null || userIds.isEmpty()) {
    return Map.of();
}

這是典型的 防御式編程

如果用戶列表為空:

直接返回:

{}

避免后面邏輯執(zhí)行。

Map.of() 是 Java 9 新特性:

返回 不可變 Map。

五、第二步:數(shù)據(jù)清洗

List<Long> distinctUserIds = userIds.stream()
        .filter(Objects::nonNull)
        .distinct()
        .toList();

作用:

  • 去掉 null
  • 去重

例如:

輸入:

[1001,1002,null,1001]

輸出:

[1001,1002]

這樣可以避免:

  • 重復(fù)查詢數(shù)據(jù)庫(kù)
  • 重復(fù)統(tǒng)計(jì)余額

六、第三步:確保錢包存在

ensureUserBatchWallet(userId);

這一步通常是:

初始化用戶錢包

如果用戶第一次使用余額系統(tǒng):

就創(chuàng)建錢包記錄。

例如:

user_wallet

表中插入一條數(shù)據(jù)。

七、第四步:處理余額過期

expireIfNeeded(userId);

余額系統(tǒng)通常都有:

  • 贈(zèng)送金
  • 優(yōu)惠金
  • 過期時(shí)間

所以需要在統(tǒng)計(jì)前:

把過期余額標(biāo)記為失效

否則會(huì)統(tǒng)計(jì)到錯(cuò)誤金額。

八、第五步:初始化結(jié)果 Map

Map<Long, BatchBalanceSummary> result = new LinkedHashMap<>();

為什么用 LinkedHashMap?

因?yàn)椋嚎梢员3植迦腠樞?/p>

初始化結(jié)果:

1001 -> (0,0)
1002 -> (0,0)

代碼:

result.put(userId,
    new BatchBalanceSummary(BigDecimal.ZERO, BigDecimal.ZERO));

九、第六步:查詢數(shù)據(jù)庫(kù)批次

List<AccountBatchEntity> batches =
    accountBatchMapper.selectList(...)

SQL 等價(jià):

SELECT *
FROM account_batch
WHERE user_id IN (...)
AND status = ACTIVE
AND remaining_amount > 0

查詢條件:

條件含義
user_id指定用戶
status批次有效
remaining_amount > 0還有余額

十、第七步:余額累加

核心代碼:

BatchBalanceSummary current =
    result.getOrDefault(...)

作用:

獲取當(dāng)前用戶已經(jīng)累計(jì)的余額。

如果不存在:

返回默認(rèn):

(0,0)

判斷余額類型

ACCOUNT_TYPE_PROMO

如果是:

贈(zèng)送余額

就加到:

promoBalance

否則:

cashBalance

現(xiàn)金余額累加

current.cashBalance().add(amount)

贈(zèng)送余額累加

current.promoBalance().add(amount)

十一、余額統(tǒng)計(jì)示例

假設(shè)數(shù)據(jù)庫(kù)數(shù)據(jù):

userIdtypeamount
1001cash100
1001promo20
1001cash30
1002promo50

統(tǒng)計(jì)過程:

1001 -> (0,0)

+100 cash
1001 -> (100,0)

+20 promo
1001 -> (100,20)

+30 cash
1001 -> (130,20)

最終:

1001 -> (130,20)
1002 -> (0,50)

十二、余額統(tǒng)計(jì)架構(gòu)圖

整個(gè)余額系統(tǒng)一般是這樣設(shè)計(jì):

十三、record 的優(yōu)勢(shì)

使用 record 后代碼變得非常干凈:

BatchBalanceSummary

只負(fù)責(zé):

數(shù)據(jù)承載

優(yōu)點(diǎn):

  • 不可變對(duì)象
  • 線程安全
  • 減少模板代碼
  • 更清晰的領(lǐng)域模型

十四、幾個(gè)可以優(yōu)化的地方

1 使用 computeIfAbsent

可以替換:

getOrDefault

寫法更優(yōu)雅:

result.computeIfAbsent(
    userId,
    k -> new BatchBalanceSummary(BigDecimal.ZERO, BigDecimal.ZERO)
);

2 SQL 聚合優(yōu)化

如果數(shù)據(jù)量很大:

可以用 SQL 聚合:

SELECT user_id,
       account_type,
       SUM(remaining_amount)
FROM account_batch
GROUP BY user_id,account_type

減少 Java 層循環(huán)。

3 批量過期處理

目前代碼:

expireIfNeeded(userId)

如果用戶很多:

可能產(chǎn)生大量 SQL。

可以改成:

批量過期處理

十五、總結(jié)

這段代碼雖然只有幾十行,但實(shí)際上包含了很多優(yōu)秀的設(shè)計(jì)思想:

  • record 數(shù)據(jù)對(duì)象
  • Map 匯總統(tǒng)計(jì)
  • 防御式編程
  • BigDecimal 安全計(jì)算
  • 批次余額設(shè)計(jì)

一句話總結(jié):

通過批次賬戶模型,實(shí)現(xiàn)用戶余額的安全、可擴(kuò)展統(tǒng)計(jì)。

這種設(shè)計(jì)在很多系統(tǒng)中都會(huì)出現(xiàn):

  • 錢包系統(tǒng)
  • 積分系統(tǒng)
  • 余額系統(tǒng)
  • 賬戶系統(tǒng)

如果你在做 支付 / 錢包 / 優(yōu)惠金系統(tǒng),這種設(shè)計(jì)模式基本是必備技能。

到此這篇關(guān)于Java使用record關(guān)鍵詞統(tǒng)計(jì)余額的示例代碼的文章就介紹到這了,更多相關(guān)Java統(tǒng)計(jì)余額內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • SpringBoot使用外置的Servlet容器的方法步驟

    SpringBoot使用外置的Servlet容器的方法步驟

    SpringBoot 是一個(gè)非常流行的 Java 開發(fā)框架,它提供了一個(gè)簡(jiǎn)單而強(qiáng)大的方式來創(chuàng)建基于 Servlet 容器的 Web 應(yīng)用程序,本文將介紹 SpringBoot 中如何使用 Servlet 容器,需要的朋友可以參考下
    2024-12-12
  • 詳解spring mvc(注解)上傳文件的簡(jiǎn)單例子

    詳解spring mvc(注解)上傳文件的簡(jiǎn)單例子

    本篇文章主要介紹了spring mvc(注解)上傳文件的簡(jiǎn)單例子,具有一定的參考價(jià)值,有興趣的可以了解一下。
    2017-01-01
  • 使用@TransactionalEventListener監(jiān)聽事務(wù)教程

    使用@TransactionalEventListener監(jiān)聽事務(wù)教程

    這篇文章主要介紹了使用@TransactionalEventListener監(jiān)聽事務(wù)教程,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2021-09-09
  • Spring?Validation參數(shù)效驗(yàn)的各種使用姿勢(shì)總結(jié)

    Spring?Validation參數(shù)效驗(yàn)的各種使用姿勢(shì)總結(jié)

    在實(shí)際項(xiàng)目中經(jīng)常需要對(duì)前段傳來的數(shù)據(jù)進(jìn)行校驗(yàn),下面這篇文章主要給大家介紹了關(guān)于Spring?Validation參數(shù)效驗(yàn)的各種使用姿勢(shì),文中通過實(shí)例代碼介紹的非常詳細(xì),需要的朋友可以參考下
    2022-04-04
  • java中XML的使用全過程

    java中XML的使用全過程

    這篇文章主要介紹了java中XML的使用全過程,具有很好的參考價(jià)值,希望對(duì)大家有所幫助,如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2025-05-05
  • 詳解java如何集成swagger組件

    詳解java如何集成swagger組件

    今天給大家?guī)淼氖顷P(guān)于Java的相關(guān)知識(shí),文章圍繞著java如何集成swagger組件展開,文中有非常詳細(xì)的介紹及代碼示例,需要的朋友可以參考下
    2021-06-06
  • Java中Switch用法代碼示例

    Java中Switch用法代碼示例

    這篇文章主要介紹了Java中Switch用法代碼示例,向大家分享了兩段代碼,具有一定參考價(jià)值,需要的朋友可以了解下。
    2017-11-11
  • 關(guān)于SpringBoot整合Canal數(shù)據(jù)同步的問題

    關(guān)于SpringBoot整合Canal數(shù)據(jù)同步的問題

    大家都知道canal是阿里巴巴旗下的一款開源工具,純java開發(fā),支持mysql數(shù)據(jù)庫(kù),本文給大家介紹SpringBoot整合Canal數(shù)據(jù)同步的問題,需要的朋友可以參考下
    2022-03-03
  • Java實(shí)現(xiàn)HTML轉(zhuǎn)PDF及合并PDF文件詳細(xì)教程

    Java實(shí)現(xiàn)HTML轉(zhuǎn)PDF及合并PDF文件詳細(xì)教程

    之前在工作中遇到過一個(gè)需求,是將用戶填寫的申報(bào),由固定模板的來生成pdf,后來想到先把內(nèi)容生成html,然后再把html格式的內(nèi)容轉(zhuǎn)換成pdf,這篇文章主要介紹了Java實(shí)現(xiàn)HTML轉(zhuǎn)PDF及合并PDF文件的相關(guān)資料,需要的朋友可以參考下
    2025-07-07
  • 微服務(wù)框架FEIGN使用常見問題分析

    微服務(wù)框架FEIGN使用常見問題分析

    這篇文章主要為大家介紹了微服務(wù)框架FEIGN常見問題分析,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪
    2022-08-08

最新評(píng)論

常熟市| 石城县| 青冈县| 茂名市| 十堰市| 班戈县| 南充市| 临朐县| 灵石县| 贞丰县| 翁源县| 昭觉县| 三明市| 保德县| 祥云县| 葵青区| 潞城市| 宣恩县| 安康市| 新邵县| 襄樊市| 莱阳市| 汽车| 鄂尔多斯市| 蒙山县| 尼玛县| 博野县| 理塘县| 正定县| 白银市| 剑阁县| 湟源县| 分宜县| 个旧市| 曲麻莱县| 三亚市| 西贡区| 东乡族自治县| 广宗县| 峨眉山市| 泗水县|