當前位置:
首頁 > 最新 > Kotlin和Java EE 系列之——如何讓 Kotlin 類對 Java EE 友好

Kotlin和Java EE 系列之——如何讓 Kotlin 類對 Java EE 友好

Kotlin 和 Java 都是 JVM 語言,所以它們之間相互轉換很容易,是這樣嗎?不完全是,讓 Kotlin 的類對 JEE 友好還需要一點工作。

Kotlin 的主要優勢之一就是能很好地集成 Java。事實上 Java 很容易轉換為 Kotlin,看起來用 Kotlin 寫 Java EE 應用似乎不需要動什麼腦筋。然而,兩者之間存在一些微妙的差別,使得轉換並不那麼順暢:

大多數框架要求非 final 的類,而 Kotlin 的類是 final 的。

注入會引入大量不必要的空檢查。

上述兩點以及強制的無參數構造函數會妨礙編寫函數式風格的代碼。

Java EE 和 Kotlin 並不是真正的朋友,除非你撮合它們。幸好所有這些問題都可以避免。

我們的轉換目標是一個簡單的 Java WAR,它可以通過 REST 介面從資料庫中存儲和檢索記錄。從 GitHub 拉取fables-kotlin倉庫開始吧。這個項目在 jee/java 目錄下。如果想運行它並進行測試,請查看 GitHub 上的說明。

讓 Kotlin 類對 Java EE 友好

Java EE 伺服器對類的構造方式非常挑剔。它們大多數必須是非 final,而且擁有一個無參數的構造函數,以及公有方法。無參數構造函數用於實例化,而另外兩個需求用於生成代理。代理會攔截對象的調用並豐富它們的附加功能。如果寫的是 Java 代碼,不需要考慮太多,但寫 Kotlin 代碼會有點不一樣。

在 Build 腳本中加入 Kotlin

在開始轉換之前,將 Kotlin 編譯器添加到 build 腳本中。也就是從這個:

改為這個:

我們必須註冊 Kotlin 編譯器插件,將其應用到模塊,並添加一些依賴項。Kotlin 標準庫並不是強制要求使用的,它雖然小型,卻提供了大量有用的功能。

簡單的開始:RestApplication 類

IntelliJ 內置支持將 Java 類轉換為 Kotlin。這很容易使用:你可以打開一個 Java 類然後按下 [CTRL]+[ALT]+[SHIFT]+K,或者拷貝一段 Java 文件中的代碼並在 Kotlin 文件中粘貼。兩種方式都會自動轉換代碼。下面把這個組合鍵稱為 [Kotlin]。

打開 RestApplication.java 類,按下 [Kotlin]。完成。

轉換後的代碼正常工作,但它仍然是 Java 風格的代碼,只是用了不同的語言。通過不可變的 Kotlin set 並把 getClasses 變成一個真正的函數來代替複雜的 Java HashSet 初始化過程 —— 這樣做:

轉換介面

按下 [Kotlin] 然後繼續。

轉換簡單的不可變類

按下 [Kotlin],IDEA 會幫你把類轉換成 Kotlin 代碼。很神奇,類的內容不見了。

休息一下,做點練習:

創建一個類型為 Person 且具有 person 屬性的 JavaBean。為其添加 getter, setter, equals, hasCode, 和 toString 方法,以及接收 person 的構造函數。現在統計一下你寫「person」的次數,不區分大小寫。

希望你對結果不要太震驚。擁有與這個 Java 類同樣功能的 Kotlin 類在代碼格式化良好的情況下只需要編寫 4 行代碼。

JPA 實體類

熱身過後,我們來嘗試更有趣的事情:JPA 實體類。這是很典型的,擁有很長的 setters 和 getters、巨大的equals, hashCode, 和toString的類。下面會用一個簡短的摘要來提醒你它有多臃腫。

這裡我們有第一個進行真正改進的機會。再使用一次 [Kotlin]。現在聲明它是一個數據類(data class)。將主構造函數聲明為私有的,放入所有欄位的聲明,刪除默認的東西並添加 override。刪除所有的方法(但要保留構造函數)。讓次構造函數調用主構造函數。來看看「瘦身」的效果:

不過我們仍然停留在無參數構造函數的階段。來看看強制的 name 屬性。該值將通過公共構造函數或 JPA 提供。然而,JPA 會先構造對象,然後再設置值,這意味著我們必須為構造提供一些默認值。空字元串是個簡單但成本小的方案。

業務服務

KittenBusinessService.java 是一個簡單的服務,它能插入和讀取數據。在將其轉換為 Kotlin 之後,我們必須使用一點技巧來讓它發揮作用。

首先,entityManager 的聲明完全錯了:

作為在類構造之後注入的值,它必須聲明為可空,並使用 null 作為初始值,所有調用都需要進行空值檢查。幸好 Kotlin 有辦法在變數第一次使用之前設置為非空值:lateinit (延遲初始化)。也就是說現在沒有值,但晚一點會有,這正是注入所做的事情。這允許我們將其聲明為非空的(non-nullable),並拋出所有空值檢查(null-checks):

類和所有非私有方法必須聲明為 open —— 否則就無法創建代理。我們還要對返回的 id 類型做一個小小的修復,因為實體在被持久化之後,id 不再是 null。!! 意味著「值不能是 null;如果是,則拋出異常」。find 方法只是個函數,所以我們按這種方式聲明它。

這個方法的返回值由編譯器推導。不過,我更願意聲明它。如果你弄錯了,返回了一個錯誤的類型, 聲明將會捕獲到這一點,你也將得到一個編譯錯誤,而不是一些奇怪的運行時行為。

REST 服務

再次從自動轉換開始。為類和所有非私有成員聲明 open。現在嘗試使用服務,不會成功:

記住每個類屬性會自動創建 getter 和 setter,而且 Kotlin 中所有東西都是 final 的。受保護(protected)的變數 kittenBusinessService 創建了一個 final 的受保護的 setter,我們並不喜歡這樣,因為它不能被代理。這裡我們可以將其聲明為 open 或 private,兩種方式都可以。因為它是私下裡使用的,我們聲明它為 private,同時聲明它為 lateinit 來處理空值檢查:

小結

Kotlin 最酷的地方在於它與 Java 能很好的互動。我們可以一個個的去轉換類,期間不會出現問題。

Kotlin 和 Java 在默認情況下有兩點差異;Kotlin 的類和方法是 final 的,但 Java 的是 open 的;Kotlin 的成員是公共的,而 Java 的是受保護的。在寫獨立程序的時這並沒有太大的差別,因為編譯器會對所有問題發出警告,但是在 Java EE 框架中這會產生問題。在應用程序部署和使用之前你不會收到任何對問題的警告。通過謹慎的編碼可以避免問題,但小心的對待每個類的時候難免出錯。只要忘了一個 open 就會造成應用程序出錯。

在下一部分中,我會告訴你如何利用 Kotlin 編輯器插件來處理 Kotlin 的細節,讓你的 Java EE 應用更健壯。這些插件也會讓代碼更清晰,更有效,最終比對應的 Java 代碼更好。

喜歡這篇文章嗎?立刻分享出去讓更多人知道吧!

本站內容充實豐富,博大精深,小編精選每日熱門資訊,隨時更新,點擊「搶先收到最新資訊」瀏覽吧!


請您繼續閱讀更多來自 開源中國 的精彩文章:

TAG:開源中國 |

您可能感興趣

Gradle Kotlin DSL的accessors 生成問題
Spring Boot與Kotlin 使用MongoDB資料庫
Spring Boot與Kotlin使用Spring-data-jpa簡化數據訪問層
Kotlin Android 環境搭建
開發 iOS 應用,Kotlin Native 是否夠格?
Google發布Android KTX預覽版,它能為Kotlin開發者做些什麼?
Kotlin打造Android路由框架
Canonical宣布Kotlin編程語言Snap包格式上線
Kotlin和Swift語言在Redmonk榜上排名大幅提升
Kotlin 繼承
Kotlin 類和對象
Kotlin語言Web庫又添一虎將:Kweb
Android開發者是時候轉向Kotlin了
Kotlin項目下的Retrofit2網路請求框架
Kotlin 泛型
Kotlin 介面
谷歌發布 Android KTX 預覽版:提供相應 API 層,讓Kotlin開發更簡潔
Kotlin 擴展
Kotlin 編程
從源碼角度分析 Kotlin by lazy 的實現