搶先一步
VMware 提供培訓和認證,以加速您的進展。
了解更多嗨,Spring 粉絲們! 歡迎收看另一集 Spring 小技巧! 在這一集中,我們將研究 Java 14 的新功能以及它們在建構基於 Spring Boot 的應用程式中的使用。
首先,我們需要使用最新且最棒的 Java 版本,Java 14,它尚未發布。 預計將在 2020 年初發布。 您可以在 Java.net 上下載搶先體驗版。 您也可以考慮使用 SDKManager (sdk
),它確實使安裝新的 JVM 版本變得非常容易。
請記住,每 6 個月都會有新的 Java 版本發布。 這些新版本可在生產環境中使用,但僅在一個版本與下一個版本之間的六個月內提供支援。 Java 專案偶爾也會發布長期支援 (LTS) 版本。 目前的長期支援版本是 Java 11。 Java 14 僅在 Java 15 發布之前才適合用於生產環境。 事實上,我們將研究許多預覽功能,有人可能會爭辯說這些功能根本不應該出現在生產環境中。 已經警告過你了!
如果您使用 SDKManager,您可以執行以下指令來安裝 Java 14。
sdk install java 14.ea.36-open
前往 Spring Initializr 並使用 Spring Boot 2.3 或更高版本產生一個新專案。 您還需要選擇 JDBC
和 PostgreSQL
。
舊版本的 Spring Boot 尚未支援 Java 14 執行時期。 當然,為了編輯這個 Java 版本,您需要將其匯入到您的 IDE 中。 不過,在您執行此操作之前,讓我們修改 pom.xml
以配置組建以支援 Java 14。 通常,當您前往 Spring Initializr 時,您還會指定一個 Java 版本。 Java 14 尚不支援,因此我們需要手動配置一些內容。
確保透過變更 java.version
屬性來指定 Java 版本。
<properties>
<java.version>14</java.version>
</properties>
這允許我們的組建使用 Java 14 以及該版本中的所有已發布功能,但要真正體驗 Java 14 的新穎性,我們需要啟用預覽功能 - 這些功能已發布,但預設情況下未啟動。
在 <plugins>...</plugins>
節中,新增以下外掛程式配置以啟用 Java 14 的預覽功能。
<plugin>
<artifactId>maven-compiler-plugin</artifactId>
<configuration>
<release>14</release>
<compilerArgs>
<arg>--enable-preview</arg>
</compilerArgs>
<forceJavacCompilerUse>true</forceJavacCompilerUse>
<parameters>true</parameters>
</configuration>
</plugin>
<plugin>
<artifactId>maven-surefire-plugin</artifactId>
<configuration>
<argLine>--enable-preview</argLine>
</configuration>
</plugin>
現在您已經準備好了! 讓我們來看一些 Java 程式碼。 Spring Initializr 非常好心地給了我們一個專案和一個骨架進入點類別。
package com.example.fourteen;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.context.event.ApplicationReadyEvent;
import org.springframework.context.event.EventListener;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.jdbc.core.PreparedStatementCreatorFactory;
import org.springframework.jdbc.core.RowMapper;
import org.springframework.jdbc.core.SqlParameter;
import org.springframework.jdbc.support.GeneratedKeyHolder;
import org.springframework.stereotype.Component;
import org.springframework.stereotype.Service;
import java.sql.Types;
import java.util.List;
@SpringBootApplication
public class FourteenApplication {
public static void main(String[] args) {
SpringApplication.run(FourteenApplication.class, args);
}
}
我們將建立一個簡單的 JDBC 支援服務,該服務使用 SQL 將其資料寫入資料庫。 我們需要一個對應到資料庫表格 people
中的資料的物件。
在這一點上,我通常會使用我的 IDE 的程式碼產生工具來費力地編寫 Javabean 物件,或者我會使用 Lombok 來註釋我的方式來建立一個編譯器合成的物件,該物件具有 getter、setter、toString
和 equals
的實作。 我甚至可能會勉強參考其他語言讓這種繁瑣的工作變得微不足道的能力。 Scala 支援case class。 Kotlin 支援data class。
而 Java 14 支援 _record_s。
record Person(Integer id, String name, int emotionalState) {
}
還不錯吧? 這個語法包含了很多內容! 它為我們提供了一個具有建構子和建構子參數、屬性、equals
和 toString
實作等的新物件。 我們可以像使用任何其他物件一樣實例化此物件的實例。 嘗試取消引用物件中的屬性,您會發現我們的建構子屬性已變為 id()
/id(int)
、name()
/name(String)
和 emotionalState()
/emotionalState(int)
。 對於這麼少的内容來說還不錯!
讓我們看一下 PeopleService
的實作。
PeopleService
使用 JdbcTemplate
快速將資料庫查詢的結果轉換為 Java 物件。 如果您曾經使用過 JdbcTemplate
(誰沒有用過?),這應該非常簡單明了。 我留下了一些未實作的部分,以便我們可以直接重新審視這些部分。
@Service
class PeopleService {
private final JdbcTemplate template;
//todo
private final String findByIdSql = null;
private final String insertSql = null;
private final RowMapper<Person> personRowMapper =
(rs, rowNum) -> new Person(rs.getInt("id"), rs.getString("name"), rs.getInt("emotional_state"));
PeopleService(JdbcTemplate template) {
this.template = template;
}
public Person create(String name, EmotionalState state) {
//todo
}
public Person findById(Integer id) {
return this.template.queryForObject(this.findByIdSql, new Object[]{id}, this.personRowMapper);
}
}
首先,我們要使用一些 SQL 查詢。 我一生都在竭盡全力避免在 Java 程式碼中鍵入 SQL 查詢。 天啊,如果人們知道他們可以雄辯地將 SQL 查詢表示為 Java Strings
,他們還會如此頻繁地使用 ORM 嗎? 對於任何稍微複雜的事情,我都會將我的 SQL 查詢提取到屬性檔案中,然後使用 Spring 的配置屬性機制載入這些檔案。
但是,我們可以在 Java 14 中做得更好! 多行字串終於來到了 Java! 現在它加入了 Python、Ruby、C++、C#、Rust、PHP、Kotlin、Scala、Groovy、Go、JavaScript、Clojure 以及其他十幾種語言的行列。 我很高興它終於來了!
將 sql
變數替換為以下宣告。
private final String findByIdSql =
"""
select * from PEOPLE
where ID = ?
""";
private final String insertSql =
"""
insert into PEOPLE(name, emotional_state)
values (?,?);
""";
太好了! 有一些方法可以用來修剪邊距等等。 您也可以在每行末尾使用反斜線跳脫序列 (\
) 來表示下一行應該從那裡開始,否則換行符會被逐字解釋。
讓我們看一下 create
方法。
將 Person
的 emotionalState
作為 int
儲存在資料庫中是一個實作細節。 我寧願不將其傳遞給使用者。 讓我們使用一個列舉來描述每個 Person
的情緒狀態。
enum EmotionalState {
SAD, HAPPY, NEUTRAL
}
這是一個開始,我想。 讓我們開始實作。 我們立刻就有機會使用 Java 14 中另一個漂亮的新功能:更智慧的 switch 運算式。 Switch 運算式讓我們可以從 switch case 的分支傳回一個值,然後將該值指派給一個變數。 語法幾乎與我們之前使用的相同,除了每個 case 都用箭頭 ->
而不是 :
與分支分開,並且不需要 break
語句。
在以下範例中,我們將 int
值指派給變數 index
,由於最近 Java 迭代中的另一個漂亮功能(使用 var
的自動型別推斷),我們不需要指定該變數的型別。
public Person create(String name, EmotionalState state) {
var index = switch (state) {
case SAD -> -1;
case HAPPY -> 1;
case NEUTRAL -> 0;
};
// todo
}
有了 index
,我們就可以建立執行針對資料庫的 SQL 語句所需的必要 PreparedStatement
。 我們可以執行該預備語句並傳入一個 KeyHolder
,它將用於收集從新插入的列傳回的產生的金鑰。
public Person create(String name, EmotionalState state) {
var index = switch (state) {
case SAD -> -1;
case HAPPY -> 1;
case NEUTRAL -> 0;
};
var declaredParameters = List.of(
new SqlParameter(Types.VARCHAR, "name"),
new SqlParameter(Types.INTEGER, "emotional_state"));
var pscf = new PreparedStatementCreatorFactory(this.insertSql, declaredParameters) {
{
setReturnGeneratedKeys(true);
setGeneratedKeysColumnNames("id");
}
};
var psc = pscf.newPreparedStatementCreator(List.of(name, index));
var kh = new GeneratedKeyHolder();
this.template.update(psc, kh);
// todo
}
唯一的麻煩是傳回的金鑰是一個 Number
,而不是 Integer
或 Double
或任何更具體的東西。 這讓我們有機會使用 Java 14 中另一個有趣的新功能,智慧型轉換。 智慧型轉換允許我們在 instanceof
測試中測試型別後避免冗餘轉換。 它更進一步,並為我們提供了一個變數名稱,我們可以藉此在測試範圍內引用自動轉換的變數。
public Person create(String name, EmotionalState state) {
var index = switch (state) {
case SAD -> -1;
case HAPPY -> 1;
case NEUTRAL -> 0;
};
var declaredParameters = List.of(
new SqlParameter(Types.VARCHAR, "name"),
new SqlParameter(Types.INTEGER, "emotional_state"));
var pscf = new PreparedStatementCreatorFactory(this.insertSql, declaredParameters) {
{
setReturnGeneratedKeys(true);
setGeneratedKeysColumnNames("id");
}
};
var psc = pscf.newPreparedStatementCreator(List.of(name, index));
var kh = new GeneratedKeyHolder();
this.template.update(psc, kh);
if (kh.getKey() instanceof Integer id) {
return findById(id);
}
throw new IllegalArgumentException("we couldn't create the " + Person.class.getName() + "!");
}
我們需要一個 int
才能將其傳遞給 findById(Integer)
,而此方法為我們完成了這項工作。 方便,對吧?
一切正常,所以讓我們使用一個簡單的 ApplicationListener<ApplicationReadyEvent
來執行程式碼
@Component
class Runner {
private final PeopleService peopleService;
Runner(PeopleService peopleService) {
this.peopleService = peopleService;
}
@EventListener(ApplicationReadyEvent.class)
public void exercise() throws Exception {
var elizabeth = this.peopleService.create("Elizabeth", EmotionalState.SAD);
System.out.println(elizabeth);
}
}
執行它,您會看到該物件已寫入資料庫,而且最棒的是,在列印結果 Person
物件時,您獲得了一個漂亮的新的 toString()
結果!
我們才剛剛開始探索 Java 14 中的所有新功能! 該語言中有很多新功能,我們已經開始在本影片中介紹這些功能,而且執行時期本身還有更多用於安全性和效能的功能。 我再也不能更衷心地建議您找到一種方法擺脫您的舊版 JDK(正在看著你,Java 8 使用者!),並移至最新的 JDK。