Java對象字段拷貝最佳實踐分享
前言
一開始在線表和歷史表都是一張表,只不過字段設置不一樣,顯示不一樣
但后續(xù)數(shù)據(jù)越來越多,為了不影響在線表,數(shù)據(jù)最終得落入歷史表,不影響在線表的CRUD
以下章節(jié)圍繞如何克隆在線表的數(shù)據(jù)
對象字段拷貝 的需求,比如從數(shù)據(jù)庫查詢出的對象需要轉換成 DTO,或者在審核流程中更新一張表的同時寫入歷史表等
如果手動 set 字段,代碼會變得繁瑣,難以維護
1. 傳統(tǒng)set(不推薦)
最簡單的方法是 手動賦值,但是當字段較多時,代碼冗長且容易遺漏。
示例代碼:
CheckBoxDetailDO checkBoxDetailDO = new CheckBoxDetailDO(); checkBoxDetailDO.setCheckStatus(1L); checkBoxDetailDO.setCntr(checkBox.getCntr()); checkBoxDetailDO.setImgCntrF(checkBox.getImgCntrF()); checkBoxDetailDO.setCreateTime(checkBox.getCreateTime());
缺點:
- 代碼冗長:如果 CheckBoxDO有幾十個字段,手寫 set 非常麻煩
- 易出錯:如果 CheckBoxDO結構變化,必須手動修改所有 set 邏輯,維護成本高
適用場景:
字段較少(少于 3 個字段)
除了set,還有一種跟他很像,我也放在這個章節(jié)
Lombok 的 @Builder,可以使用 builder() 方法來 鏈式賦值,提高可讀性(但我感覺沒啥差異)
CheckBoxDetailDO checkBoxDetailDO = CheckBoxDetailDO.builder() .checkStatus(1L) .cntr(checkBox.getCntr()) .imgCntrF(checkBox.getImgCntrF()) .createTime(checkBox.getCreateTime()) .build();
2. copyProperties(有局限)
CheckBoxDetailDO checkBoxDetailDO = new CheckBoxDetailDO(); BeanUtils.copyProperties(checkBox, checkBoxDetailDO); checkBoxDetailDO.setCheckStatus(1L); // 額外賦值
優(yōu)點:
- 代碼簡潔,自動拷貝 相同字段,避免手動 set
- 無需額外依賴,Spring 內(nèi)置
缺點:
- 性能一般,使用了 反射,比手動 set 慢
- 字段名必須完全匹配,如果 CheckBoxDetailDO 和 CheckBoxDO字段名不一樣,無法拷貝
- 不支持復雜轉換,比如 數(shù)據(jù)類型不同(int vs String)、默認值設置 等
適用場景:
- 字段名和類型完全匹配的簡單拷貝
- 項目已經(jīng)使用 Spring,避免額外依賴
3. MapStruct(推薦)
如果 CheckBoxDO和 CheckBoxDetailDO 結構類似,并且字段較多,推薦使用 MapStruct 進行自動對象映射
MapStruct 在編譯期生成代碼,相比 BeanUtils 性能更優(yōu),并且支持字段轉換
1、定義轉換接口
創(chuàng)建一個 Mapper 接口,并用 @Mapper 注解標識。
import org.mapstruct.Mapper; import org.mapstruct.Mapping; import org.mapstruct.factory.Mappers; @Mapper(componentModel = "spring") public interface CheckBoxConverter { CheckBoxConverter INSTANCE = Mappers.getMapper(CheckBoxConverter.class); @Mapping(target = "checkStatus", constant = "1L") // 強制設定 checkStatus 為 1 CheckBoxDetailDO toDetailDO(CheckBoxDO checkBox); }
2、調用轉換
@Resource private ChekBoxDetailMapper chekBoxDetailMapper; CheckBoxDetailDO checkBoxDetailDO = CheckBoxConverter.INSTANCE.toDetailDO(checkBox); chekBoxDetailMapper.insert(checkBoxDetailDO);
優(yōu)點:
- 高性能,編譯期生成代碼,沒有反射開銷
- 自動映射字段,省去 set 代碼
- 支持類型轉換,例如 String -> Long、Date -> LocalDateTime 等
- 字段名不同也能映射,可以用 @Mapping(source = “oldField”, target = “newField”) 自定義映射關系
缺點:
需要引入 MapStruct 依賴,但一次配置,終身受益
適用場景:
- 字段較多且映射規(guī)則較復雜
- 項目對性能要求較高(比 BeanUtils 更快)
但是會有bug:
后續(xù)發(fā)現(xiàn)id自增字段也被復刻了!
采取忽略的方式:
@Mapper public interface CheckBoxConverter { CheckBoxConverter INSTANCE = Mappers.getMapper(CheckBoxConverter.class); @Mapping(target = "id", ignore = true) // 忽略 id 字段 @Mapping(target = "checkStatus", constant = "1L") // 強制設定 checkStatus 為 1 CheckBoxDetailDO toDetailDO(CheckBoxDO checkBox); }
截圖如下:
這里拓展下這種方式其他的知識點:
使用 @BeanMapping(ignoreByDefault = true)(僅拷貝指定字段)
類似如下代碼:
@Mapper(componentModel = "spring") public interface CheckBoxConverter { CheckBoxConverter INSTANCE = Mappers.getMapper(CheckBoxConverter.class); @BeanMapping(ignoreByDefault = true) @Mapping(target = "cntr", source = "cntr") @Mapping(target = "imgCntrF", source = "imgCntrF") @Mapping(target = "createTime", source = "createTime") @Mapping(target = "checkStatus", constant = "1L") CheckBoxDetailDO toDetailDO(CheckBox checkBox); }
如果不想修改代碼:
CheckBoxDetailDO checkBoxDetailDO = CheckBoxConverter.INSTANCE.toDetailDO(checkBox); checkBoxDetailDO.setId(null); // 手動清除 id
最后,不要忘記insert,否則它只是一個對象,沒有存儲
CheckBoxDetailDO checkBoxDetailDO = CheckBoxConverter.INSTANCE.toDetailDO(checkBox); checkBoxDetailMapper.insert(checkBoxDetailDO); // 插入數(shù)據(jù)庫
4. 總結
方案 | 代碼簡潔度 | 性能 | 適用場景 |
---|---|---|---|
手動 set | ? 差 | ? | 快 |
BeanUtils.copyProperties | ? 好 | ?一般 | 字段完全匹配,簡單拷貝 |
Lombok @Builder | ? 好 | ? 快 | 代碼可讀性強,構建新對象 |
MapStruct | ? 最優(yōu) | ? 最優(yōu) | 復雜對象映射,性能高 |
以上就是Java對象字段拷貝最佳實踐分享的詳細內(nèi)容,更多關于Java對象字段拷貝的資料請關注腳本之家其它相關文章!
相關文章
spring的applicationContext.xml文件與NamespaceHandler解析
這篇文章主要介紹了spring的applicationContext.xml文件與NamespaceHandler解析,Spring容器啟動,在創(chuàng)建BeanFactory時,需要加載和解析當前ApplicationContext對應的配置文件applicationContext.xml,從而獲取bean相關的配置信息,需要的朋友可以參考下2023-12-12SpringBoot日志框架之Log4j2快速入門與參數(shù)詳解
本文介紹了SpringBoot日志框架log4j2的基本使用和配置方法,包括將日志輸出到控制臺、文件、Elasticsearch和Kafka,多個輸出目的地的配置,異步日志記錄器的使用以及l(fā)og4j2.xml配置文件的詳細語法和參數(shù)含義,需要的朋友可以參考下2023-05-05springboot?aop里的@Pointcut()的配置方式
這篇文章主要介紹了springboot?aop里的@Pointcut()的配置方式,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教2021-11-11解決MultipartFile.transferTo(dest) 報FileNotFoundExcep的問題
這篇文章主要介紹了解決MultipartFile.transferTo(dest) 報FileNotFoundExcep的問題,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教2021-07-07