网易首页 > 网易号 > 正文 申请入驻

喜新厌旧,是我的本性。今天就宠mapstruct怎么了!

0
分享至

这些年写Java写多了,感觉Java是越来越丑。尤其是在玩了TypeScript之后,看到Java代码总有一股想吐的感觉。这种思想的转变,从侧面上证明了,我并不是一个专一的人。

因为我是一条狗。

喜新厌旧,是我的本性,即使我把自己表现的很纯洁。

按理说,牛x的人物并不需要关注语言层面这种较低级的问题。但是,无论是什么语言,各种属性拷贝,是在工程上绕不开的问题。比如折腾人的VOBODTODO等。

项目中的代码,有六成,是在做这些无用的转换和各种数据验证。这个比例是我瞎诌的,但也相差无几。

在Java中,有三种方式来处理这些属性拷贝:

  1. 直接编码,把代码硬怼上去

  2. 使用各种BeanUtils,通过反射完成赋值

  3. 使用类似MapStruct的工具,直接在编译期完成

其实嘛,哪一种都有利弊,有些东西虽然香,但实际用起来,还是要思量一下。个个打扮的花枝招展的,都是外在的皮囊。

本文主要介绍Mapstruct的使用,并从这香喷喷的工具中,闻一下其中变馊的味道。

1. 如何使用?

照例,需要在pom中加入依赖包,我们这里用的是1.4.1.Final版本。


org.mapstructgroupId>
mapstructartifactId>
${org.mapstruct.version}version>
dependency>

这还没完,还需要在pom中的build部分,增加一个插件。搞这么复杂,是因为它的原理和lombok是一样的,同样通过APT在编译器实现的。

这意味着,它的代码,在编译期就完成了。不需要反射,所以效率就和直接写get、set,是一样的。


org.apache.maven.pluginsgroupId>
maven-compiler-pluginartifactId>
3.8.1version>
1.8source>
1.8target>
org.mapstructgroupId>
mapstruct-processorartifactId>
${org.mapstruct.version}version>
path>
org.projectlombokgroupId>
lombokartifactId>
1.18.16version>
path>
org.projectlombokgroupId>
lombok-mapstruct-bindingartifactId>
0.2.0version>
path>
annotationProcessorPaths>
configuration>
plugin>

这时候,我们就可以使用它提供的注解,方便的进行属性拷贝了。

@Mapper(nullValueCheckStrategy = NullValueCheckStrategy.ALWAYS)
public interface Transform {
Transform T = Mappers.getMapper(Transform.class);
Member fromMemberEntity(MemberEntity entity);
MemberEntity fromMember(Member member);
}

上面是一段示例代码。Mapper注解,标志着这是一个类型转换工具(对象映射器),它提供了很多策略供我们选择。直接写接口文件,并不需要做一些额外的动作,mapstruct就知道你要干什么!

在传统的编程中,如果Member的属性非常的多,我们需要手工完成这个过程,代码会非常的多。

使用Mapperstruct之后,这部分重复的劳动,工具都替我们做了。

瞧瞧下面这张图!

上面的图表明了,代码在target下的generated-source目录下生成,这就是我们上面添加的插件的功劳;代码的内容,其实就是一些非空判断和get、set等。相同字段名相同类型的属性,将会无差别的拷贝过去。

如果你的bean属性非常的多,这个工具会让你的代码由几百行,变成几行!

2. 与其他方式比较

那mapstruct有什么优势么?为什么不直接使用BeanUtils?它们的效果一样的啊,而且后者各种类库都有提供。

主要原因,就是效率问题。

BeanUtils是通过反射实现的,效率肯定很低;而mapstuct是基于APT实现的,没有性能损耗。

BeanUtils的属性拷贝,在判断空值和不同类型的属性时,有很多障碍,会歇菜;而mapstruct有非常灵活的策略和转化方式,自定义性比较强(后面会谈到)。

3. 复杂场景

那下面我们就来看一个复杂的场景。

如果你的bean中,只有一些普通的属性,那么使用mapstruct,就是如丝般的顺滑。但总有一些异常情况,需要使用更高级的处理方式。

假设我想要由Unit转化为ProductUnitEntity,但其中有个字段measureType它们的类型不一样,我们就可以使用Mappings注解完成这个转化。

@Mappings({
@Mapping(source = "measureType.value", target = "measureType")
ProductUnitEntity fromUnit(Unit v);

编译后的代码如下所示。有了source和target,就可以实现比BeanUtils更加牛x的行为。你甚至可以通过dateFormat做一些日期转化之类的。

其实,上面的measureType是一个枚举类型。如何将普通的类型转化为枚举类型呢?我们只需要提供一个default方法就ok了。mapstruct会判断参数类型和返回值,所以说方法的名称可以是任何合法的值。

default Unit.MeasureType measureTypeIntegerToDomain(Integer value) {
for (Unit.MeasureType s : Unit.MeasureType.values()) {
if (s.getValue() == value) {
return s;

return null;

那mapstruct能实现List之间的转化么?也是可以的。下面两行代码,就能够自动的补充for循环,让你的代码更加简洁。

List fromSkuEntityList(List v);
List fromSkuList(List v);
End

那么问题来了。

既然这么好的东西,那为什么现在的很多项目,都不用mapstruct,甚至连BeanUtils都不用,直接手工在那里get、set呢?

一种原因是,这些工具会大幅减少代码量。mapstruct+hibernate-validate,一个管转化,另一个管验证,简直就是以代码行数论天下的公司的噩梦。绩效会降低的!

另一种原因就是,使用这些工具,并不利于项目的重构。假如你在DTO里把a字段改成了b字段,mapstruct都贴心的为你忽略了这些变化。你的项目代码并不会提示错误,风险将直接带到运行时。

而使用get、set的方式,除了代码量变的非常多以外,唯一的风险就是开发人员忘记了为某个新增的字段赋值。

在这种情况下,机器干的活,并不一定比人类可靠。所以使用mapstruct有一个大的前提:你的团队,能够通过约定,不给变量乱起名字,不乱重构。如此,才能发挥它的价值。

作者简介:小姐姐味道 (xjjdog),一个不允许程序员走弯路的公众号。聚焦基础架构和Linux。十年架构,日百亿流量,与你探讨高并发世界,给你不一样的味道。我的个人微信xjjdog0,欢迎添加好友,进一步交流。

特别声明:以上内容(如有图片或视频亦包括在内)为自媒体平台“网易号”用户上传并发布,本平台仅提供信息存储服务。

Notice: The content above (including the pictures and videos if any) is uploaded and posted by a user of NetEase Hao, which is a social media platform and only provides information storage services.

相关推荐
热点推荐
英剧天花板炸裂三季!9.0+神作封印悬疑天花板!!

英剧天花板炸裂三季!9.0+神作封印悬疑天花板!!

民智
2026-02-25 10:20:47
张冬云任四川省副省长,曾任南充市委书记

张冬云任四川省副省长,曾任南充市委书记

澎湃新闻
2026-02-25 16:48:29
疯涨?特朗普,大消息!

疯涨?特朗普,大消息!

魏家东
2026-02-25 08:16:35
中方投了弃权票

中方投了弃权票

第一财经资讯
2026-02-25 11:22:55
逛公园要先付69元拍照费?深圳一免费公园现收费“园中园”引质疑

逛公园要先付69元拍照费?深圳一免费公园现收费“园中园”引质疑

深圳晚报
2026-02-25 12:16:54
广州,有雷又有雨!连续一周

广州,有雷又有雨!连续一周

广州生活美食圈
2026-02-25 12:32:38
太离谱!陕西女子花250元在饭店订年夜饭,对方歇业初一把钱退了

太离谱!陕西女子花250元在饭店订年夜饭,对方歇业初一把钱退了

火山詩话
2026-02-25 14:16:59
克洛普出任皇马主帅的新要求:接受曼联为维尼修斯开出的报价?

克洛普出任皇马主帅的新要求:接受曼联为维尼修斯开出的报价?

夜白侃球
2026-02-25 22:38:06
黄子华再度封神,《夜王》炸裂!54岁的他依旧抗打!

黄子华再度封神,《夜王》炸裂!54岁的他依旧抗打!

乡野小珥
2026-02-25 20:00:48
李连杰晒影迷耗时100小时自制海报:谢谢这位有才的朋友;此前,该作者用成龙70部电影中的人物形象制作了海报,获大哥当面感谢

李连杰晒影迷耗时100小时自制海报:谢谢这位有才的朋友;此前,该作者用成龙70部电影中的人物形象制作了海报,获大哥当面感谢

极目新闻
2026-02-24 18:36:26
一场高速堵车,戳穿了3700万新能源车主“谎言”,差距一目了然

一场高速堵车,戳穿了3700万新能源车主“谎言”,差距一目了然

芭比衣橱
2026-02-24 09:41:49
苹果新品官宣:2月24日,正式开售

苹果新品官宣:2月24日,正式开售

科技堡垒
2026-02-24 15:01:58
73人死亡!美国、加拿大、英国、法国、俄罗斯,发布“安全警告”

73人死亡!美国、加拿大、英国、法国、俄罗斯,发布“安全警告”

每日经济新闻
2026-02-24 15:35:05
停摆近三十年,广州赛马运动再开闸

停摆近三十年,广州赛马运动再开闸

界面新闻
2026-02-25 13:09:09
重磅!3月1日起,CT检查这三项费用全面取消,全国统一执行!

重磅!3月1日起,CT检查这三项费用全面取消,全国统一执行!

悦心知足
2026-02-25 15:53:58
高速服务区如何盈利?多数人只上厕所或接热水,听保安怎么说?

高速服务区如何盈利?多数人只上厕所或接热水,听保安怎么说?

寄星夜幕星河
2026-02-17 20:39:30
耗资18亿!亚洲最大图书馆即将在武汉建成交付,成2026年最值得期待的中国建筑之一

耗资18亿!亚洲最大图书馆即将在武汉建成交付,成2026年最值得期待的中国建筑之一

越乔
2026-02-25 11:53:27
遭中方当头一棒后,不到24小时,高市喊话称愿与中国沟通对话

遭中方当头一棒后,不到24小时,高市喊话称愿与中国沟通对话

触摸史迹
2026-02-26 00:07:50
头号怨种出现了!仅仅晚5秒过出口,一浙C牌车缴纳1384.9元高速费

头号怨种出现了!仅仅晚5秒过出口,一浙C牌车缴纳1384.9元高速费

火山詩话
2026-02-25 10:53:39
大年初三失联的四川26岁男子已离世,被发现地方距家并不远

大年初三失联的四川26岁男子已离世,被发现地方距家并不远

大象新闻
2026-02-25 16:21:04
2026-02-26 01:43:00
小姐姐味道
小姐姐味道
十年架构,日百亿流量
329文章数 1203关注度
往期回顾 全部

科技要闻

“机器人只跳舞,没什么用”

头条要闻

女子爬山失联10天后遗体被找到 丈夫:她登顶神情恐惧

头条要闻

女子爬山失联10天后遗体被找到 丈夫:她登顶神情恐惧

体育要闻

勇士爆冷惜败鹈鹕 梅尔顿28分赛季新高

娱乐要闻

黄晓明新恋情!与小22岁美女同游新加坡

财经要闻

上海楼市放大招,地产预期别太大

汽车要闻

750km超长续航 2026款小鹏X9纯电版将于3月2日上市

态度原创

健康
艺术
旅游
手机
教育

转头就晕的耳石症,能开车上班吗?

艺术要闻

这些作品太美了,仙气飘飘,三位大咖不容错过!

旅游要闻

重庆酉阳樱花漫古城,吊脚飞檐藏春归,这才是中式浪漫天花板!

手机要闻

Nothing Phone(4a)手机粉色版外观公布,3月5日正式发布

教育要闻

弥勒市中医医院启动高考体检服务

无障碍浏览 进入关怀版