一直以來,Java 常常是企業級應用開發的首選語言之一。然而,在眾多新舊語言的包圍下,Java 對初學者的學習曲線顯得相當陡峭。為了解決這些問題,減少 Java 新手的學習難度,近幾年來的 Java 新功能有許多都環繞著如何降低語言與語法複雜度。
Java 23 中的預覽功能 JEP 477 隱式宣告類別和實例主方法就是在簡化 Java 入門程式的編寫過程,特別是針對初學者和小型程式的開發。本文亦將深入探討它的核心概念和功能,分析其如何改變初學者 Java 程式的編寫方式,以及這些變更對軟體工程師和開發人員的影響。
目錄
前言
每當面對新的程式語言時,第一個範例程式的複雜度高低常常會影響到新手是否願意持續投注心力學習。學習過 Java 的朋友們應該都很熟悉,如果你想要說聲 Hello, World! 的話,所需要輸入的字元數量和所需要理解的基礎知識硬是比其他語言多上一大堆:
// HelloWorld.java
public class HelloWorld {
public static void main(String[] args) {
System.out.println("Hello, World!");
}
}
我們只是想說聲「安安你好」但卻開不了口,因為身為一位 Java 初學者,你要先做的事是:
- 檔案名稱必須要和類別名稱相同。在這裡你要了解檔案和類別之間的對應,但其實「說哈囉」不需要用到類別
- 需要學習
public
關鍵字,隨之而來的是protected
、private
和預設修飾子,對繼承與套件存取的差異 - 需要學習
static
關鍵字,隨之而來的是靜態成員和實例成員之間的差異。這時候又會提到類別的概念 - 需要學習
class {}
關鍵字和架構,又是跟類別有關,但在這邊其實用不到類別 - 需要學習
String[]
,但在主方法中其實根本沒有用到這個參數,另外要學習陣列和終端機命令列的觀念 - 說到這邊已經沒有力氣解釋什麼是
System.out.println
了……
Java 新手的學習困境
- 複雜的程式結構:即使是最簡單的 “Hello World” 程式,也需要新手了解類別、靜態方法和
main
方法的概念。因為要一開始要學習的東西太多,這些複雜性讓他們感到困惑和沮喪,拖慢了學習進程 - 冗長的樣板程式碼:Java 要求明確宣告類別和方法,導致了大量的樣板程式碼。對於初學者來說,額外的程式碼會分散他們對核心邏輯的注意力,使得學習過程變得更加困難
- 陡峭的學習曲線:由於嚴格語法和物件導向的特性,新手需要同時學習許多概念才能編寫有意義的程式。陡峭的學習曲線會打擊初學者的信心,甚至導致他們放棄學習
這些問題突顯了簡化 Java 初始學習體驗的必要性,而這正是 JEP 477 所要解決的問題。
JEP 477 概觀
本功能讓初學者輕鬆地撰寫第一個 Java 程式,而無需理解那些更強大、更複雜的程式語法和功能。簡單的小程式可以用精簡的宣告方式撰寫,無需嚴格的語法結構。在需要時,我們能夠無縫且順暢地從小型程式遷移到大型程式以使用更高級的功能。經驗豐富的開發人員也可以享受簡潔編寫小型程式的樂趣。
優點
- 對於初學者來說,可以不需要一開始就接觸到類別、靜態、陣列等概念,因此可降低學習門檻,適合教學。
- 對於簡單的程式,可以省略類別和靜態
main
方法的宣告,使程式碼更簡潔。 - 當程式變得更複雜時,開發者可以隨時轉換為顯式類別,並添加更多的結構和功能。
- 自動匯入常用 API,減少了樣板程式碼。
缺點
- 對於大型專案,顯式宣告類別和使用適當的套件結構仍然是更好的做法,因為它們提供了更好的結構,並且更易於維護。
- 對於不熟悉此功能的開發人員來說,隱式類別和實例
main
方法可能會導致困惑。 - 需要理解隱式類別的限制,它們不能被其他類別引用或繼承,也不能有顯式建構式。
- 可能導致開發者忽視重要的 Java 概念,如類別、套件和模組。
介紹
靈活的啟動協定:實例 main
方法
JEP 477 加強了 Java 程式的啟動規範,允許宣告更靈活的 main
方法,可以是實例方法,也不一定要有 String[]
參數。這大大簡化了最基本的 Hello World 程式:
// HelloWorld.java
public class HelloWorld {
void main() { // 原本是 public static void main(String[] args)
System.out.println("Hello, World!");
}
}
- 主方法不需要
public
,只要不是private
就行了 - 主方法不需要
static
,一般的實例方法也可以 - 不需要
String[]
傳入值,除非你真的需要從命令列中動態輸入傳值進程式中
隱式宣告的類別
如果一個 Java 原始碼檔案中沒有明確地宣告類別(或是有欄位和方位並沒有被 class {}
結構包圍),編譯器會自動為該檔案建立繼承自 Object
的 final
隱式類別:
// HelloWorld.java <- final class HelloWorld extends Object {}
void main() {
System.out.println("Hello, World!");
}
- 不需要
class {}
結構 - 自動建立隱式類別
HelloWorld
簡化控制台互動
引入了新的 java.io.IO
類別,提供了簡單的方法來進行控制台輸入輸出:
// HelloWorld.java
// import static java.io.IO.*; // 預設靜態匯入
void main() {
println("Hello, World!");
}
新的輸入輸出方法有下列三個:
void println(Object obj)
void print(Object obj)
String readln(String prompt)
使用方法與限制
檔案中所有未被 class {}
包覆的欄位和方法都會歸在同一個隱式類別之中,外部類別無法呼叫其建構式與靜態成員。另外隱式類別只有預設無參數建構式,不允許其他帶參數的建構式,也不能實作介面。
String hello() { return "Hello, "; }
String world = "World!";
void main() {
println(this.hello() + this.world);
}
自動匯入 java.base
模組
隱式類別會自動匯入 java.base
模組中所有公共頂層類別和介面,使得常用的 API 可以直接使用而無需額外的 import
語句。可以參考本站文章以獲得更多模組匯入的細節。
// import module java.base; // 預設模組匯入
void main() {
var authors = List.of("James", "Bill", "Guy", "Alex", "Dan", "Gavin");
for (var name : authors) {
println(name + ": " + name.length());
}
}
程式進入點順序
啟動器會依照下列的順序尋找主方法:
- 非
private
的static void main(String[] a)
- 非
private
的static void main()
- 非
private
的void main(String[] a)
- 非
private
的void main()
更複雜的例子
String hello() {
return "Hello, ";
}
void main() {
println(this.hello() + Test.get());
}
class Test { // 內部類別
static String get() {
String name = readln("Your name: "); // 從輸入讀值
return "" != name ? name : "World!";
}
}
總結
JEP 477 代表了 Java 語言設計者在簡化與保持語言完整性之間尋求平衡的努力。通過引入隱式宣告類別和實例 main
方法,Java 正在向更加友好和靈活的程式設計模式邁進。這不僅有利於初學者快速上手,也為經驗豐富的開發者提供了編寫小型程式和原型的便利工具。
不過,我們需要謹慎地評估這些新功能在實際專案中的應用。雖然它帶來了新的可能性,但我們仍然需要注意程式碼的可維護性、可讀性和可擴展性。在享受簡化語法帶來的便利的同時,我們也要確保不忽視那些使 Java 成為強大的企業級程式語言的核心概念和最佳實踐。
本篇文章的內容為老喬原創、二創或翻譯而來。雖已善盡校對、順稿與查核義務,但人非聖賢,多少仍會有疏漏之處難以避免。如果大家有任何問題、建議或指教,都歡迎在底下留言與老喬討論!