上一篇:3600万中国人在抖音“上清华”

作者:明明如月学长

blog.csdn.net/w605283073/article/details/107371462

1 背景

之前在专栏中讲过“不推荐使用属性拷贝工具”,推荐直接定义转换类和方法使用 IDEA 插件自动填充 get / set 函数。

不推荐的主要理由是:

有些属性拷贝工具性能有点差 有些属性拷贝工具有“BUG” 使用属性拷贝工具容易存在一些隐患(后面例子会讲到)

2 示例

首先公司内部就遇到过 commons 包的 BeanUtils 进行属性拷贝性能较差的真实案例,然后该同事换成了 Spring 的 BeanUtils 性能好了很多,感兴趣大家可以使用性能测试框架或者基准测试框架去对比,这里就不对比了。

接下来我们看 Spring 的 BeanUtils 的属性拷贝会存在啥问题:

import lombok.Data;
import java.util.List;@Data
public class A {private String name;private List<Integer> ids;
}
@Data
public class B {private String name;private List<String> ids;
}
import org.springframework.beans.BeanUtils;import java.util.Arrays;public class BeanUtilDemo {public static void main(String[] args) {A first = new A();first.setName("demo");first.setIds(Arrays.asList(1, 2, 3));B second = new B();BeanUtils.copyProperties(first, second);for (String each : second.getIds()) {// 类型转换异常System.out.println(each);}}
}

大家运行上述示例时,会发生类型转换异常。

打断点可以看到,属性拷贝之后 B 类型的 second 对象中 ids 仍然为 Integer 类型:

如果不转换为字符串,直接进行打印,并不会报错。

使用CGlib 在不定义Converter 的情况下也会遇到类似问题:

import org.easymock.cglib.beans.BeanCopier;import java.util.Arrays;public class BeanUtilDemo {public static void main(String[] args) {A first = new A();first.setName("demo");first.setIds(Arrays.asList(1, 2, 3));B second = new B();final BeanCopier beanCopier = BeanCopier.create(A.class, B.class, false);beanCopier.copy(first,second,null);for (String each : second.getIds()) {// 类型转换异常System.out.println(each);}}
}

同样,问题在运行时才暴露出来。

接下来我们看下 mapstruct:

import org.mapstruct.Mapper;
import org.mapstruct.factory.Mappers;@Mapper
public interface Converter {Converter INSTANCE = Mappers.getMapper(Converter.class);B aToB(A car);
}
import java.util.Arrays;public class BeanUtilDemo {public static void main(String[] args) {A first = new A();first.setName("demo");first.setIds(Arrays.asList(1, 2, 3));B second = Converter.INSTANCE.aToB(first);for (String each : second.getIds()) {// 正常System.out.println(each);}}
}

可以成功的将 A 中 List<Integer> 转为 B 中的 List<String> 类型。(搜索公众号互联网架构师,回复“2T”,送你一份Java面试题宝典)

我们看下编译生成的 Converter 实现类:

import java.util.ArrayList;
import java.util.List;
import javax.annotation.Generated;
import org.springframework.stereotype.Component;@Generated(value = "org.mapstruct.ap.MappingProcessor",comments = "version: 1.3.1.Final, compiler: javac, environment: Java 1.8.0_202 (Oracle Corporation)"
)
@Component
public class ConverterImpl implements Converter {@Overridepublic B aToB(A car) {if ( car == null ) {return null;}B b = new B();b.setName( car.getName() );b.setIds( integerListToStringList( car.getIds() ) );return b;}protected List<String> integerListToStringList(List<Integer> list) {if ( list == null ) {return null;}List<String> list1 = new ArrayList<String>( list.size() );for ( Integer integer : list ) {list1.add( String.valueOf( integer ) );}return list1;}
}

自动帮我们进行了转换,我们可能没有意识到类型并不一致。

如果我们在 A 类中添加一个 String number 属性,在 B 类中添加一个 Long number 属性,使用 mapstruect 当 number 设置为非数字类型时就会报 .NumberFormatException

@Override
public B aToB(A car) {if ( car == null ) {return null;}B b = new B();b.setName( car.getName() );if ( car.getNumber() != null ) { // 问题出在这里b.setNumber( Long.parseLong( car.getNumber() ) );}b.setIds( integerListToStringList( car.getIds() ) );return b;
}

使用 cglib 默认则不会映射 number 属性,B 中的 number 为 null。

如果手动定义转换器,使用 IDEA 插件(如 generateO2O)自动转换:

public final class A2BConverter {public static B from(A first) {B b = new B();b.setName(first.getName());b.setIds(first.getIds());return b;}
}

在编码阶段就可以非常明确地发现这个问题:

3 结论

由于 Java 的泛型其实是编译期检查,编译后泛型擦除,导致运行时 List<Integer> 和 List<String> 都是 List 类型,可以正常赋值。这就导致在使用很多属性映射工具时,编译时不容易明显的错误。

mapstruct 自定义了注解处理器,在编译阶段可以读取映射双方的泛型类型,进而进行映射。但是这种映射也很可怕,有时候我们由于粗心等原因定义错了类型,自动帮助我们进行了转换,会带了很多副作用。

之前对各种属性映射工具的性能进行了简单的对比,结果如下:

因此慎用属性转换工具,如果可能建议自定义转换类,使用IDEA插件自动填充,效率也挺高, A 或 B 中任何属性类型不匹配,甚至删除一个属性,编译阶段即可报错,而且直接调用 get set 的效率也是非常高的。

看完这篇文章,你有什么收获?欢迎在留言区与10w+Java开发者一起讨论~

关注微信公众号:互联网架构师,在后台回复:2T,可以获取我整理的教程,都是干货。

猜你喜欢

1、GitHub 标星 3.2w!史上最全技术人员面试手册!FackBoo发起和总结

2、如何才能成为优秀的架构师?

3、从零开始搭建创业公司后台技术栈

4、程序员一般可以从什么平台接私活?

5、37岁程序员被裁,120天没找到工作,无奈去小公司,结果懵了...

6、滴滴业务中台构建实践,首次曝光

7、不认命,从10年流水线工人,到谷歌上班的程序媛,一位湖南妹子的励志故事

8、15张图看懂瞎忙和高效的区别

9、2T架构师学习资料干货分享

为什么不推荐使用BeanUtils属性转换工具,老程序员都不使用!相关推荐

  1. 工作10以上老程序员都去哪了?作为新时代的程序员我们该何去何从

    在纽约,PyGotham每年召开之际,都会有超过600名程序员聚集在一起讨论工作. 为了让会议更加多元化,组织者尽量邀请一些女性程序员以及各种肤色的程序员. 那么,老程序员都去哪了?他们去了大学教书, ...

  2. 老程序员都去哪儿了?

    摆在老程序员们面前有三条路,一是转行,二是继续钻研成为技术大牛,三是转型为管理人员. 我最近采访了十五位30岁以上的老程序员们,在此我想发表下我的观点. 网络上总有这类观点-- 「如果所有的技术都想着 ...

  3. 老程序员都去哪儿了?国内的大龄程序员都去哪了

    摆在老程序员们面前有三条路,一是转行,二是继续钻研成为技术大牛,三是转型为管理人员. 我最近采访了十五位30岁以上的老程序员们,在此我想发表下我的观点. 网络上总有这类观点-- 「如果所有的技术都想着 ...

  4. 为什么不推荐使用BeanUtils属性转换工具

    点击关注公众号,Java干货及时送达  作者:明明如月学长 blog.csdn.net/w605283073/article/details/107371462 1 背景 之前在专栏中讲过" ...

  5. Java技术:为什么不推荐使用BeanUtils属性转换工具

    1 背景 之前在专栏中讲过"不推荐使用属性拷贝工具",推荐直接定义转换类和方法使用 IDEA 插件自动填充 get / set 函数. 不推荐的主要理由是: 有些属性拷贝工具性能有 ...

  6. 【ssd】M.2的SATA,PCI-x2(Socket 2 ),PCI-x4(Socket 3)了解一下,老程序员都快被新硬件搞蒙圈了

    3块金手指的是走SATA通道的, 2块金手指的是走PCIE通道的 SATA3.0接口理论传输速率 6 Gbps (750 MB/s) ,实际传输速率 600 MB/s 左右. M.2.2接口有两种类型 ...

  7. 码龄超过20年,依然对生活和编程充满激情,这是三位70后“老”程序员的故事

    大数据文摘出品 作者:周素云.张秋玥 加班996,生病ICU. 这是一句最近搅乱了很多程序员平静生活,也让所有的"社畜"认真反思人生的话题.但是,让程序员们真正感到焦虑的其实并不只 ...

  8. 为什么老程序员的效率如此高?编程速度快,Bug数量又少

    大神程序员出发之后径直穿过了田地,十分果断.他只用了十分钟就到了另一边. "你是怎么做到的?"另外两个人问道,"那些地雷怎么没有伤到你?" "很简单, ...

  9. 为什么老程序员的效率如此高?编程速度快,Bug数量又少?

    为什么老程序员编程速度快,Bug数量少? 之前看到一位程序员讲到:2个月前公司有一个35+的老程序员入职,和项目主管一个年纪,但是还是干技术,基本没话,就是干自己的.公司暂时还没有让他挑大梁,观察了他 ...

  10. python视频课程推荐-听说程序员都在用,5款Python开发工具推荐

    很多Python学习者想必都会有如下感悟:最开始学习Python的时候,因为没有去探索好用的工具,吃了很多苦头.后来工作中深刻体会到,合理使用开发的工具的便利和高效.今天,我就把Python程序员使用 ...

最新文章

  1. 笔记一:python安装和执行
  2. 镇海区工业机器人与自动化设备_镇海区开展首期“工业机器人操作实训班”蓄力智能制造产业发展...
  3. 11.10 chkconfig:管理开机服务
  4. WTM系列视频教程:View和Taghelper
  5. PHP十六个魔术方法
  6. 数据结构基础入门知识
  7. 谷粒商城高级篇爬坑笔记--错误异常信息乱码问题
  8. MySQL数据库基本操作1
  9. [SheRO]用D3D绘制2D图像
  10. 第四篇、Tomcat 集群
  11. 为cfree5 配置舒心的编译环境
  12. 免费网络视频监控软件cmsclient
  13. 智能制造学习纪录片和书籍
  14. 第四篇:ROS常用命令行指令【重点】
  15. 单利 java_JAVA中的单利
  16. [USACO12MAR]花盆Flowerpot
  17. 双十一一大波建站优惠来袭,这不薅点来建站?
  18. Sanic部署(1)
  19. indesign选中不了图片删除_有办法了!批量删除多个Word页眉页脚
  20. IO基础 File String

热门文章

  1. 在FL Studio中如何混音你的鼓组采样与旋律采样
  2. spring-tool-suite(STS) 创建 spring boot项目
  3. C#获取实体类属性名和值 | 遍历类对象
  4. 渠道效果五步优化,让采购的流量物超所值
  5. jquery伪分页控件
  6. 设计模式之(Facade)外观模式
  7. 未知账户(S-1-5-21)无法删除的问题
  8. 因为项目的原因,要学习J2EE了
  9. codeforce 460B Little Dima and Equation
  10. pd17虚拟机启动器生成方法