當前位置: 妍妍網 > 碼農

改造BeanUtils,優雅實作List數據拷貝

2024-04-29碼農

BeanUtils.copyProperties() ;確實為我們做了很多事情,雖然不能完美完成深拷貝,但是對於 po、vo、dto 的拷貝已經足夠用了。可還是有一些不夠完美的地方。

不足幾點如下:

. 不能拷貝 list,而拷貝 list 的情況又大量存在,因此會有許多重復程式碼。

for (S source : sources) {
T target = new T();
copyProperties(source, target);
list.add(target);
}

. 有一些簡單的查詢,僅僅需要轉換一下 vo 也需要 new Vo()。

public Vo findById(Integer id){
 Vo vo = new Vo();
 Po po = dao.findById(id);
 copyProperties(po, vo);
return vo;
}

. 這種拷貝方式是沒有返回值的,jdk8 支持 stream() 操作之後,支持不是很友好,不方便 lambda 運算式的使用,因此我們決定透過整合 BeanUtils 類,自己造一個方便用的輪子。

使用

我們將新建立一個輪子 BeanConvertUtils,使用如下,當我們要轉換 po、vo 時,只需要:

// 使用前
public Vo findById(Integer id){
 Vo vo = new Vo();
 Po po = dao.findById(id);
 copyProperties(po, vo);
return vo;
}
// 使用後
public Vo findById(Integer id){
return BeanConvertUtils.converTo(dao.findById(id), Vo::new);
}
// 使用後,透過lambda運算式特殊處理個別欄位
public Vo findById(Integer id){
return BeanConvertUtils.converTo(dao.findById(id), Vo::new
(s, t) -> t.setName(s.getName))
 );
}

當我們要拷貝 list 的時候也很簡單:

// 使用前
public List<Vo> findAll(){
 List<Vo> vos = new ArrayList();
 List<Po> pos = dao.findAll();
for (Po po : Pos) {
Vo vo = new Vo();
BeanUtis.copyProperties(po, vo);
vos.add(vo);
}
return vos;
}
// 使用後
public List<Vo> findAll(){
return BeanConvertUtils.converToList(dao.findAll(), Vo::new)
}
// 同樣支持自訂lambda
public List<Vo> findAll(){
return BeanConvertUtils.converToList(dao.findAll(), Vo::new,
(s, t) -> t.setName(s.getName))
 )
}

程式碼如下

/**
 * 轉換物件工具
 *
 * @author bugpool
 */

public classBeanConvertUtilsextendsBeanUtils{
publicstatic <S, T> convertTo(S source, Supplier<T> targetSupplier){
return convertTo(source, targetSupplier, null);
}
/**
* 轉換物件
*
@param source 源物件
@param targetSupplier 目標物件供應方
@param callBack 回呼方法
@param <S> 源物件型別
@param <T> 目標物件型別
@return 目標物件
*/

publicstatic <S, T> convertTo(S source, Supplier<T> targetSupplier, ConvertCallBack<S, T> callBack){
if (null == source || null == targetSupplier) {
returnnull;
}
T target = targetSupplier.get();
copyProperties(source, target);
if (callBack != null) {
callBack.callBack(source, target);
}
return target;
}
publicstatic <S, T> List<T> convertListTo(List<S> sources, Supplier<T> targetSupplier){
return convertListTo(sources, targetSupplier, null);
}
/**
* 轉換物件
*
@param sources 源物件list
@param targetSupplier 目標物件供應方
@param callBack 回呼方法
@param <S> 源物件型別
@param <T> 目標物件型別
@return 目標物件list
*/

publicstatic <S, T> List<T> convertListTo(List<S> sources, Supplier<T> targetSupplier, ConvertCallBack<S, T> callBack){
if (null == sources || null == targetSupplier) {
returnnull;
}
List<T> list = new ArrayList<>(sources.size());
for (S source : sources) {
T target = targetSupplier.get();
copyProperties(source, target);
if (callBack != null) {
callBack.callBack(source, target);
}
list.add(target);
}
return list;
}
/**
* 回呼介面
*
@param <S> 源物件型別
@param <T> 目標物件型別
*/

@FunctionalInterface
publicinterfaceConvertCallBack<ST{
voidcallBack(S t, T s);
}
}





效能

由於只是 BeanUtils 的一個封裝,跟原來的程式碼效能幾乎差不多,如果要說差一點也沒錯,畢竟多了一層函式堆疊的呼叫,但是基本可以忽略不計。主要的效能還是由 BeanUtils 決定。

提醒

不知道大家對這個 BeanConvertUtils 工具類感覺怎麽樣,自己在計畫中倒是大量使用,也很方便。

但是有兩點要提醒:

  • 此方法依舊不能解決深層次的深拷貝問題,詳細的可以 google 一下 BeanUtils 的深拷貝問題。

  • 如果 source 或者 targetSupplier 只要有一個為 null,本工具類不像 BeanUtils 一樣丟擲異常,而是返回 null,因為筆者認為呼叫方如果把 null 進行準換,那就是想轉換為 null,為不為空應該由呼叫方自己負責。

  • 來源:http://b.nxw.so/1661BT

    >>

    END

    精品資料,超贊福利,免費領

    微信掃碼/長按辨識 添加【技術交流群

    群內每天分享精品學習資料

    最近開發整理了一個用於速刷面試題的小程式;其中收錄了上千道常見面試題及答案(包含基礎並行JVMMySQLRedisSpringSpringMVCSpringBootSpringCloud訊息佇列等多個型別),歡迎您的使用。

    👇👇

    👇點選"閱讀原文",獲取更多資料(持續更新中