搜尋
首頁Javajava教程Java中萬惡的註解

Java中萬惡的註解

Feb 20, 2017 am 10:09 AM
java註解

本文由碼農網 – 孫騰浩原創翻譯,轉載請看清文末的轉載要求,歡迎參與我們的付費投稿計劃!

當Java 1.5引入註解,企業開發者對簡化EJB和其他企業產品開發抱持很大期望。可以看同一時期的一篇文章用EJB 3.0簡化企業Java開發。

然而從那時起,Java企業使用註解出現一些無法預料的後果和副作用,有些甚至到今天都沒有被注意到。幸運的是,並非所有的副作用都沒有被注意到,來看一些例子,在StackOverflow標題為“Why Java Annotations?”有很多有價值的評論,“Are Annotations Bad?”這篇文章有很棒的觀點,還有“Magics Is Evil”,“Annotations…Good, Bad or Worse?”。

Java中萬惡的註解

並非所有的註解都相同

儘管上面許多討論都包含有價值的觀點,但並不是所有註解都是相同的。

這裡有兩類註解,差別在於他們是否在運行期影響程式。首先,說一下無害的一類,它們並不會在運行期間對程式碼產生任何影響;另一種是有害的一類,它們會修改運行期行為。無害的註解包括@Deprecated, @Override, @SuppressWarnings, 等等。有害的註解包括@Entity, @Table, @PostConstruct, @ApplicationScoped,等等。

在無害的註解中存在一小部分註解,它們非常實用。有一些提供在編譯期間(靜態檢查)捕獲錯誤或提供安全保障。一些實用的註解包括:@Override, @NonNull/@Nullable 來自(Checker Framework), 等等。

為什麼有害的註解不好?

我們定義了一些有害的註解,為什麼要避免使用它們?

想像一個標準的Java Data類別擁有@PostConstruct方法。這個註解表示所標註的方法應該在物件創建好之後被呼叫。這個功能並不是由JVM處理,所以Date類別隱含取得未知的框架和容器,而自身語意並沒有做任何事。如果這些程式碼沒有運行在任何容器中,而只是運行在JVM中呢?這個註解大大降低了這個類別的重用性。另外對於任何使用Date的地方進行單元測試就變成了噩夢,因為你必須確保每次都正確綁定post-construction,要模擬一個相容的容器。這就有點可笑了,一個Date類別需要一個容器來運行,但這確實是有害的註解對類別、方法和參數的影響。

無可否認,業務邏輯往往複雜,需要更多依賴和關係,而不僅僅是一個簡單的Date類別。然而沒有理由在一個類別中明確或隱式地添加不必要的依賴或約束,有害的註解就是:依賴和約束。

企業陷阱

不幸的是有害的聲明在Java Enterprise 5大規模合法化。為了修正早期企業API的易用性問題,註解用來隱藏系統中冗餘的和難用的部分。新的JEE 5被稱讚為”輕量級”和”簡單”,表面上看起來是這樣。但是一個微小的,同時也是至關重要的誤用蔓延開來。

@Stateless
public class DocumentRepository {
   public Document getDocument(String title) {
      ...
   }
   ...
}


如果想要取得一個Stateless EJB,「只需要」在類別上宣告@Stateless註解。確實,編寫這個類別只需要只一點動作,但是請注意這個類別中有害的註解綁定了幾百頁的說明文檔,而且只能在百萬位元組的應用伺服器(Application Server)上運行。這又怎麼能稱的上是」輕量級」呢。所以,這個註解只是真正需要寫的Java程式碼的佔位符而已,程式碼仍需要以某種形式存在。現在只不過是隱藏在註解之下。

不幸的是,這種變通方案稱為一種模式,現在有害的註解廣泛分佈:JPA, CDI, Common Annotations, JAXB 等等。

有害的註解有時會出現在錯誤的地點

因為註解通常作為開發環境,有時有害的註解被當作單一職責原則(Single Responsibility Principle)或關注點分離(Separation of Concerns)的最佳實踐。

讓我們來考慮一下下面這個CDI範例:

@ApplicationScoped
public class DocumentFormatter {
   ...
}


上面的註解描述這個類別應該是一個CDI Bean,意味著它應該只能由CDI實例化,並確保每個應用程式中只有一個實例。

這些資訊並不屬於這個類別。這個服務在功能上(無論什麼方式)並不會對它在目前應用中的作用產生影響。這裡有兩個明顯的關注點。

一個JPA的簡單例子:

@Entity
@Table("PERSON")
public class Person {
   ...
}


问题在于这种类往往是”领域对象(domain objects)”,它们直接将领域模型持久化。更糟的是,数据传送对象(DTO)用来在对象之间传送数据,使得整个构造变得脆弱,因为对象间耦合过于紧密。不管怎样,这是一种错误的方式。

所有的这些附加的功能和(或)信息应该从这些类中分离出来,但是它们却悄悄混在一起,因为它们”只不过”是注解。

有害的注解有时蔓延

注解有时会传染其他对象。回顾上面那个CDI Bean。每个使用它的对象,每个依赖它的对象现在都拥有一个CDI注解,否则依赖关系树就不会构建成功。

@Entity注解也一样。因为对象之间的关系,其他对象也通过注解持久化,很快所有的持久化对象都会有这个注解。我们无法使用原生的第三方对象(除非序列化或包装它们),我们无法使用其他持久化机制(比如用NoSQL DB存放对象)。

这些注解使得这些对象无法复用。它们只能在一个严格的、受控制的、不透明的环境中使用,不能和任何东西整合。

有什么替代品?

是XML吗?当然不是,至少对于上面的例子来说不是。

Spring框架使用配置来管理对象,因此可以用XML当做配置文件。然而,是否某个依赖需要在运行期改变,而不通过重新编译?如果不需要,那么很难说配置应该用另一门语言来表示,尤其重构困难、测试困难、管理需要特殊工具。

真正的替代品当然是好的Java代码,正确封装并解耦的。是的,用代码来管理对象,尽管有时被当做样板(boilerplate),但并不算糟糕。它带来一些好处,比如让代码可读、可调试、可重构。只有那些长片的、复杂的、冗余的样板是糟糕的,比如“关于EJB 2.0”。但是解决方案并不是摆脱所有的样板或用另一种语言隐藏样板,而是简单干净的架构,直接而不多余的信息,简单并合适的方式来面向对象。

这也适用于JPA、Spring和其他东西。误用注解来表示功能会发生Stcakoverflow上这个问题“Arguments Against Annotations”,为什么不用已有的工具呢:比如Java语言本身和编译器,来解决这类问题,面向对象和软件最佳实践。

总结

如果注解在代码运行期加上了额外功能和约束,那它是有害的。这很糟糕,因为它隐藏了类或方法的切面,使之难懂、难复用、难重构、难测试。

不幸的是Java Enterprise不理睬Java开发者社区中发对注解的声音。所以企业级Java和其他”官方”框架更不可能重视这类问题。

至少我们可以持续关注有害的注解,如果可能尽量避免使用,编写新的框架和软件替换掉注解,不会出现有害注解所带来的问题。

 以上就是Java中万恶的注解 的内容,更多相关内容请关注PHP中文网(www.php.cn)!

陳述
本文內容由網友自願投稿,版權歸原作者所有。本站不承擔相應的法律責任。如發現涉嫌抄襲或侵權的內容,請聯絡admin@php.cn
如何將Maven或Gradle用於高級Java項目管理,構建自動化和依賴性解決方案?如何將Maven或Gradle用於高級Java項目管理,構建自動化和依賴性解決方案?Mar 17, 2025 pm 05:46 PM

本文討論了使用Maven和Gradle進行Java項目管理,構建自動化和依賴性解決方案,以比較其方法和優化策略。

如何使用適當的版本控制和依賴項管理創建和使用自定義Java庫(JAR文件)?如何使用適當的版本控制和依賴項管理創建和使用自定義Java庫(JAR文件)?Mar 17, 2025 pm 05:45 PM

本文使用Maven和Gradle之類的工具討論了具有適當的版本控制和依賴關係管理的自定義Java庫(JAR文件)的創建和使用。

如何使用咖啡因或Guava Cache等庫在Java應用程序中實現多層緩存?如何使用咖啡因或Guava Cache等庫在Java應用程序中實現多層緩存?Mar 17, 2025 pm 05:44 PM

本文討論了使用咖啡因和Guava緩存在Java中實施多層緩存以提高應用程序性能。它涵蓋設置,集成和績效優勢,以及配置和驅逐政策管理最佳PRA

如何將JPA(Java持久性API)用於具有高級功能(例如緩存和懶惰加載)的對象相關映射?如何將JPA(Java持久性API)用於具有高級功能(例如緩存和懶惰加載)的對象相關映射?Mar 17, 2025 pm 05:43 PM

本文討論了使用JPA進行對象相關映射,並具有高級功能,例如緩存和懶惰加載。它涵蓋了設置,實體映射和優化性能的最佳實踐,同時突出潛在的陷阱。[159個字符]

Java的類負載機制如何起作用,包括不同的類載荷及其委託模型?Java的類負載機制如何起作用,包括不同的類載荷及其委託模型?Mar 17, 2025 pm 05:35 PM

Java的類上載涉及使用帶有引導,擴展程序和應用程序類負載器的分層系統加載,鏈接和初始化類。父代授權模型確保首先加載核心類別,從而影響自定義類LOA

See all articles

熱AI工具

Undresser.AI Undress

Undresser.AI Undress

人工智慧驅動的應用程序,用於創建逼真的裸體照片

AI Clothes Remover

AI Clothes Remover

用於從照片中去除衣服的線上人工智慧工具。

Undress AI Tool

Undress AI Tool

免費脫衣圖片

Clothoff.io

Clothoff.io

AI脫衣器

AI Hentai Generator

AI Hentai Generator

免費產生 AI 無盡。

熱門文章

R.E.P.O.能量晶體解釋及其做什麼(黃色晶體)
4 週前By尊渡假赌尊渡假赌尊渡假赌
R.E.P.O.最佳圖形設置
4 週前By尊渡假赌尊渡假赌尊渡假赌
R.E.P.O.如果您聽不到任何人,如何修復音頻
4 週前By尊渡假赌尊渡假赌尊渡假赌
R.E.P.O.聊天命令以及如何使用它們
4 週前By尊渡假赌尊渡假赌尊渡假赌

熱工具

mPDF

mPDF

mPDF是一個PHP庫,可以從UTF-8編碼的HTML產生PDF檔案。原作者Ian Back編寫mPDF以從他的網站上「即時」輸出PDF文件,並處理不同的語言。與原始腳本如HTML2FPDF相比,它的速度較慢,並且在使用Unicode字體時產生的檔案較大,但支援CSS樣式等,並進行了大量增強。支援幾乎所有語言,包括RTL(阿拉伯語和希伯來語)和CJK(中日韓)。支援嵌套的區塊級元素(如P、DIV),

Atom編輯器mac版下載

Atom編輯器mac版下載

最受歡迎的的開源編輯器

EditPlus 中文破解版

EditPlus 中文破解版

體積小,語法高亮,不支援程式碼提示功能

PhpStorm Mac 版本

PhpStorm Mac 版本

最新(2018.2.1 )專業的PHP整合開發工具

WebStorm Mac版

WebStorm Mac版

好用的JavaScript開發工具