一、介紹
Java,作為一款非常熱門的編程語(yǔ)言,盡管它有著非常豐富的語(yǔ)言特性,完全面向?qū)ο缶幊蹋幊谈叨纫?guī)范化,但是也有一個(gè)最受大家詬病的一個(gè)缺點(diǎn):?jiǎn)拢绕涫钱?dāng)你開發(fā)了很多年之后,你會(huì)明顯的感受到,相比動(dòng)態(tài)語(yǔ)言,java 定義變量之前,要先創(chuàng)建類,然后定義變量類型,每個(gè)類要寫很多的get/set/toString/hashCode/equals等等方法。
尤其是當(dāng)一個(gè)實(shí)體類,高達(dá)幾十個(gè)變量時(shí),寫完get、set方法之后,一個(gè)實(shí)體類的長(zhǎng)度快接近一千行。
為了避免寫這些“羅嗦”的方法,很多程序員一直在尋覓著找一個(gè)能夠使他們擺脫這種重復(fù)勞動(dòng)工作的工具,例如:idea、eclipse 開發(fā)工具的快捷生成get、set方法的工具,還有我們今天要談?wù)摰倪@個(gè)Lombok工具。
二、Lombok
Lombok 是一款非常流行的代碼簡(jiǎn)潔工具,利用它的注解特性,直接就可以幫我們省去高大幾百行的get、set方法,操作非常方便。
如果是idea開發(fā)工具,可以直接在preferences -> plugins里面搜索lombok,然后點(diǎn)擊安裝即可!
接著,在項(xiàng)目工程中導(dǎo)入lombok依賴包!
-
-
org.projectlombok -
lombok -
1.18.12 -
provided
最后,只需要在對(duì)應(yīng)的實(shí)體類上加上@Data注解,即可完成類屬性get/set的注入。
- importlombok.Data;
- @Data
- publicclassUser{
- privateStringid;
- privateStringage;
- privateStringname;
- //可以不用顯式寫get、set方法
- }
使用@Data注解在類上,這個(gè)實(shí)體類中的屬性就不需要顯式寫get、set方法了。
對(duì)這個(gè)類進(jìn)行編譯之后,我們打開User.class文件,看看編譯后的文件內(nèi)容長(zhǎng)啥樣?
- publicclassUser{
- privateStringid;
- privateStringage;
- privateStringname;
- publicUser(){
- }
- publicStringgetId(){
- returnthis.id;
- }
- publicStringgetAge(){
- returnthis.age;
- }
- publicStringgetName(){
- returnthis.name;
- }
- publicvoidsetId(Stringid){
- this.id=id;
- }
- publicvoidsetAge(Stringage){
- this.age=age;
- }
- publicvoidsetName(Stringname){
- this.name=name;
- }
- publicbooleanequals(Objecto){
- if(o==this){
- returntrue;
- }elseif(!(oinstanceofUser)){
- returnfalse;
- }else{
- Userother=(User)o;
- if(!other.canEqual(this)){
- returnfalse;
- }else{
- label47:{
- Objectthis$id=this.getId();
- Objectother$id=other.getId();
- if(this$id==null){
- if(other$id==null){
- breaklabel47;
- }
- }elseif(this$id.equals(other$id)){
- breaklabel47;
- }
- returnfalse;
- }
- Objectthis$age=this.getAge();
- Objectother$age=other.getAge();
- if(this$age==null){
- if(other$age!=null){
- returnfalse;
- }
- }elseif(!this$age.equals(other$age)){
- returnfalse;
- }
- Objectthis$name=this.getName();
- Objectother$name=other.getName();
- if(this$name==null){
- if(other$name!=null){
- returnfalse;
- }
- }elseif(!this$name.equals(other$name)){
- returnfalse;
- }
- returntrue;
- }
- }
- }
- protectedbooleancanEqual(Objectother){
- returnotherinstanceofUser;
- }
- publicinthashCode(){
- intPRIME=true;
- intresult=1;
- Object$id=this.getId();
- intresult=result*59+($id==null?43:$id.hashCode());
- Object$age=this.getAge();
- result=result*59+($age==null?43:$age.hashCode());
- Object$name=this.getName();
- result=result*59+($name==null?43:$name.hashCode());
- returnresult;
- }
- publicStringtoString(){
- return"User(id="+this.getId()+",age="+this.getAge()+",name="+this.getName()+")";
- }
- }
很清晰的看到,使用@Data注解之后,User類新增了get、set、hashCode、equals和toString方法。
通過上面的例子,大家可以發(fā)現(xiàn),使用@Data注解可以大大減少了代碼量,使代碼非常簡(jiǎn)潔,這也是很多開發(fā)者熱衷于使用Lombok的主要原因。
Lombok的工作原理是怎么實(shí)現(xiàn)的呢?
由于Java的官方版本沒有提供這種快速生成方法的注解工具,類似Lombok這樣的工具,其實(shí)都是使用了從Java 6和JSR 269的Annotation Processing技術(shù)中實(shí)現(xiàn)方法的注入。
簡(jiǎn)單的說(shuō),就是使用了 Java 非公開的 API,在 javac 編譯代碼時(shí),通過強(qiáng)類型轉(zhuǎn)換獲取JavacAnnotationProcessor對(duì)象,再?gòu)腏avacAnnotationProcessor的方法里面拿到抽象語(yǔ)法樹(AST)做強(qiáng)制修改,注入get、set等方法。
使用Lombok這種方案,有個(gè)最大的好處,就是可以節(jié)省大量的重復(fù)代碼,讓代碼更佳簡(jiǎn)潔!但是也有很多弊端!
三、有哪些壞處呢?
3.1、強(qiáng)迫隊(duì)友也安裝 Lombok
當(dāng)你在使用Lombok工具插件來(lái)快速開發(fā)項(xiàng)目的時(shí)候,如果別的同事也要和你一起協(xié)作開發(fā)項(xiàng)目,那么他不得不也要安裝Lombok插件,不然項(xiàng)目編譯會(huì)報(bào)錯(cuò)。
3.2、代碼可調(diào)試性降低
代碼可調(diào)試性會(huì)降低,為什么會(huì)這么說(shuō)呢?
Lombok雖然給我們節(jié)省了get和set方法的編程,但是如果我想知道類的某個(gè)屬性被哪些方法操作給set了,如果用原生的方法,可以很好的知道調(diào)用方。但是如果使用Lombok插件來(lái)生成,這個(gè)時(shí)候你根本無(wú)從得知。甚至沒辦法調(diào)試!
3.3、不懂 Lombok 注解,會(huì)踩坑
我們知道,使用@Data會(huì)重寫hashCode()和equals()方法,如果是單個(gè)實(shí)體類,沒有繼承的話,你使用@Data不會(huì)產(chǎn)生問題。
但是如果這個(gè)實(shí)體類又繼承了父類,@Data只會(huì)重寫子類的hashCode()和equals()方法,不會(huì)把父類的屬性加進(jìn)去,這樣就會(huì)導(dǎo)致,例如當(dāng)你在使用HashMap的時(shí)候,用當(dāng)前這個(gè)實(shí)體類作為key,可能會(huì)得到意想不到的結(jié)果。
遇到這種情況,你可以在類上加上這個(gè)注解@EqualsAndHashCode(callSuper=true),子類的hashCode()和equals()方法會(huì)加入父類的屬性。
3.4、破壞封裝性
封裝是 java 面向?qū)ο缶幊讨蟹浅V匾囊粋€(gè)特性。
例如,針對(duì)User實(shí)體類,我新加一個(gè)tag屬性,我只想暴露它的get方法,不想暴露set方法給外部,沒有用@Data注解的時(shí)候,我可以很靈活的進(jìn)行編程,但是使用@Data注解之后,屬性tag被完全暴露在外界了。
- publicclassUser{
- privateStringid;
- privateStringage;
- privateStringname;
- privateStringtag="學(xué)生";
- publicStringgetTag(){
- returntag;
- }
- }
3.5、影響 jdk 升級(jí)
其實(shí)以上的坑點(diǎn),都不算什么很大的坑點(diǎn),在我看來(lái),最大的坑點(diǎn)其實(shí)就是Lombok的工作原理,使用了非官方支持的 API 接口,通過程序強(qiáng)制植入方式來(lái)修改類,實(shí)現(xiàn)get、set等方法的注入。
按照如今 JDK 的升級(jí)頻率,每半年都會(huì)推出一個(gè)新的版本,但是Lombok作為一個(gè)第三方工具,并且是由開源團(tuán)隊(duì)維護(hù)的,那么他的迭代速度是無(wú)法保證的。
假如某天JDK把這種后門堵住了,那Lombok基本上就不能用了,到時(shí)候又是個(gè)麻煩事情。
四、總結(jié)
Lombok 作為一款非常流行的工具插件,肯定有它自身的優(yōu)勢(shì)所在,到底建不建議在日常開發(fā)中使用,我個(gè)人其實(shí)是一個(gè)中立的態(tài)度,如果你們團(tuán)隊(duì)的人都喜歡它,那推薦你使用,在使用之前,最好培訓(xùn)一下,有哪些坑點(diǎn),避免踩坑。
如果多數(shù)人不太喜歡用它,那就不推薦你使用,很多公司禁止你使用它的原因,其實(shí)這種插件有點(diǎn)類似那種流氓插件,工作原理不是官方所認(rèn)可的方式來(lái)實(shí)現(xiàn),假如某天新版本的 jdk 突然把這個(gè)漏洞給堵住了,那么項(xiàng)目想要升級(jí) jdk,就比較困難。
因此大家在評(píng)估要不要在代碼中引入Lombok的時(shí)候,在想它的優(yōu)點(diǎn)同時(shí),能夠考慮到它會(huì)帶來(lái)的哪些問題,以便更好的做決定!
五、參考
https://projectlombok.org/
https://time.geekbang.org/column/article/164907
http://blog.itpub.net/69908877/viewspace-2676272/
原文鏈接:https://mp.weixin.qq.com/s/5EE0Vf8A2-8fnMQGfw0U-w