
Java 教程
- Java - 首頁
- Java - 概述
- Java - 歷史
- Java - 特性
- Java 與 C++
- JVM - Java 虛擬機器
- Java - JDK vs JRE vs JVM
- Java - Hello World 程式
- Java - 環境搭建
- Java - 基本語法
- Java - 變數型別
- Java - 資料型別
- Java - 型別轉換
- Java - Unicode 系統
- Java - 基本運算子
- Java - 註釋
- Java - 使用者輸入
- Java - 日期和時間
Java 控制語句
- Java - 迴圈控制
- Java - 決策制定
- Java - If-else
- Java - Switch
- Java - For 迴圈
- Java - For-Each 迴圈
- Java - While 迴圈
- Java - do-while 迴圈
- Java - Break
- Java - Continue
面向物件程式設計
- Java - OOPs 概念
- Java - 物件和類
- Java - 類屬性
- Java - 類方法
- Java - 方法
- Java - 變數作用域
- Java - 建構函式
- Java - 訪問修飾符
- Java - 繼承
- Java - 聚合
- Java - 多型
- Java - 重寫
- Java - 方法過載
- Java - 動態繫結
- Java - 靜態繫結
- Java - 例項初始化塊
- Java - 抽象
- Java - 封裝
- Java - 介面
- Java - 包
- Java - 內部類
- Java - 靜態類
- Java - 匿名類
- Java - 單例類
- Java - 包裝類
- Java - 列舉
- Java - 列舉建構函式
- Java - 列舉字串
Java 內建類
Java 檔案處理
Java 錯誤和異常
- Java - 異常
- Java - try-catch 塊
- Java - try-with-resources
- Java - 多重捕獲塊
- Java - 巢狀 try 塊
- Java - Finally 塊
- Java - throw 異常
- Java - 異常傳播
- Java - 內建異常
- Java - 自定義異常
Java 多執行緒
- Java - 多執行緒
- Java - 執行緒生命週期
- Java - 建立執行緒
- Java - 啟動執行緒
- Java - 執行緒合併
- Java - 執行緒命名
- Java - 執行緒排程器
- Java - 執行緒池
- Java - 主執行緒
- Java - 執行緒優先順序
- Java - 守護執行緒
- Java - 執行緒組
- Java - 關閉鉤子
Java 同步
Java 網路
- Java - 網路
- Java - 套接字程式設計
- Java - URL 處理
- Java - URL 類
- Java - URLConnection 類
- Java - HttpURLConnection 類
- Java - Socket 類
- Java - 泛型
Java 集合
Java 介面
Java 資料結構
Java 集合演算法
高階 Java
- Java - 命令列引數
- Java - Lambda 表示式
- Java - 傳送郵件
- Java - Applet 基礎
- Java - Javadoc 註釋
- Java - 自動裝箱和拆箱
- Java - 檔案不匹配方法
- Java - REPL (JShell)
- Java - 多版本 Jar 檔案
- Java - 私有介面方法
- Java - 內部類菱形運算子
- Java - 多解析度影像 API
- Java - 集合工廠方法
- Java - 模組系統
- Java - Nashorn JavaScript
- Java - Optional 類
- Java - 方法引用
- Java - 函式式介面
- Java - 預設方法
- Java - Base64 編碼解碼
- Java - Switch 表示式
- Java - Teeing 收集器
- Java - 微基準測試
- Java - 文字塊
- Java - 動態 CDS 歸檔
- Java - Z 垃圾收集器 (ZGC)
- Java - 空指標異常
- Java - 打包工具
- Java - 密封類
- Java - 記錄類
- Java - 隱藏類
- Java - 模式匹配
- Java - 緊湊數字格式化
- Java - 垃圾回收
- Java - JIT 編譯器
Java 雜項
- Java - 遞迴
- Java - 正則表示式
- Java - 序列化
- Java - 字串
- Java - Process API 改進
- Java - Stream API 改進
- Java - 增強的 @Deprecated 註解
- Java - CompletableFuture API 改進
- Java - 流
- Java - 日期時間 Api
- Java 8 - 新特性
- Java 9 - 新特性
- Java 10 - 新特性
- Java 11 - 新特性
- Java 12 - 新特性
- Java 13 - 新特性
- Java 14 - 新特性
- Java 15 - 新特性
- Java 16 - 新特性
Java API 和框架
Java 類參考
- Java - Scanner
- Java - 陣列
- Java - 字串
- Java - Date
- Java - ArrayList
- Java - Vector
- Java - Stack
- Java - PriorityQueue
- Java - LinkedList
- Java - ArrayDeque
- Java - HashMap
- Java - LinkedHashMap
- Java - WeakHashMap
- Java - EnumMap
- Java - TreeMap
- Java - IdentityHashMap
- Java - HashSet
- Java - EnumSet
- Java - LinkedHashSet
- Java - TreeSet
- Java - BitSet
- Java - Dictionary
- Java - Hashtable
- Java - Properties
- Java - Collection
- Java - Array
Java 有用資源
Java 9 - 新特性
JAVA 9(也稱為 jdk 1.9)是JAVA 程式語言開發的一個主要版本。其初始版本於 2017 年 9 月 21 日釋出。Java 9 版本的主要目標是:
使 JDK 和 Java 標準版平臺基於模組化,這意味著它可以縮減到小型計算裝置。
提高 JDK 和 Java 實現的整體安全性。
使 Java 程式碼庫和大型應用程式的構建過程和維護對於 JAVA SE 和 EE 平臺來說更容易。
為 Java 平臺設計和實現一個標準的模組系統,該系統可以輕鬆地應用於平臺和 JDK。
以下是 Java 9 支援的新特性列表
模組系統
模組系統旨在將 Java 程式碼中的模組化提升到一個新的水平。模組是程式碼和資料的自描述集合。模組可以包含包,以及特定於特定功能的配置。模組提供了對自身內容的更好的訪問控制。從 Java 9 開始,Java 庫被分成多個模組,可以使用以下命令檢視。
C:\Users\Mahesh>java --list-modules java.base@20.0.2 java.compiler@20.0.2 java.datatransfer@20.0.2 java.desktop@20.0.2 ... jdk.xml.dom@20.0.2 jdk.zipfs@20.0.2
示例 - 使用模組
以下程式碼片段定義了一個在應用程式根資料夾中的 module-info.java 檔案中宣告的模組。
module com.tutorialspoint.greetings { requires com.tutorialspoint.util; requires static com.tutorialspoint.logging; requires transitive com.tutorialspoint.base; exports com.tutorialspoint.greetings.HelloWorld; opens com.tutorialspoint.greetings.HelloWorld; }
在這裡,我們聲明瞭我們的模組依賴於三個模組,並匯出了一個供外部世界使用的公共類,並允許反射檢查特定類。預設情況下,模組的私有成員無法透過反射訪問。
REPL
REPL 代表 讀取-求值-列印-迴圈。Java 9 中引入了一個 REPL 引擎JShell,它是一個互動式控制檯,用於在控制檯中執行任意 Java 程式碼片段,無需儲存和編譯 Java 程式碼檔案。JShell 讀取輸入的每一行,對其求值,然後列印結果,然後再次準備接收下一組輸入。
示例 - 使用 JShell 作為 REPL
以下程式碼片段展示瞭如何在 JShell 中建立變數。分號是可選的。我們也可以在 JShell 中建立物件。如果變數未初始化,則會賦予預設值,如果是物件引用則為 null。建立變數後,就可以使用它,如最後一個語句所示,我們使用了字串變數來列印其值。
示例
在以下示例中,我們建立了變數,求值表示式,建立了日期物件。
jshell> int i = 10 i ==> 10 jshell> String name = "Mahesh"; name ==> "Mahesh" jshell> Date date = new Date() date ==> Fri Feb 02 14:52:49 IST 2024 jshell> String.format("%d pages read.", 10); $9 ==> "10 pages read." jshell> $9 $9 ==> "10 pages read." jshell> name name ==> "Mahesh"
改進的 JavaDocs
從 Java 9 開始,Java 現在支援 HTML5 輸出生成,並在生成的 API 文件中提供搜尋框。
示例
在這個例子中,我們正在建立一個相容 HTML5 的 javadoc。
考慮 C:/JAVA 資料夾中的以下程式碼。
Tester.java
/** * @author MahKumar * @version 0.1 */ public class Tester { /** * Default method to be run to print * <p>Hello world</p> * @param args command line arguments */ public static void main(String []args) { System.out.println("Hello World"); } }
執行 jdk 9 的 javadoc 工具,並使用 -html5 標誌生成新的文件型別。
C:\JAVA> javadoc -d C:/JAVA -html5 Tester.java Loading source file Tester.java... Constructing Javadoc information... Standard Doclet version 9.0.1 Building tree for all the packages and classes... Generating C:\JAVA\Tester.html... Generating C:\JAVA\package-frame.html... Generating C:\JAVA\package-summary.html... Generating C:\JAVA\package-tree.html... Generating C:\JAVA\constant-values.html... Building index for all the packages and classes... Generating C:\JAVA\overview-tree.html... Generating C:\JAVA\index-all.html... Generating C:\JAVA\deprecated-list.html... Building index for all classes... Generating C:\JAVA\allclasses-frame.html... Generating C:\JAVA\allclasses-frame.html... Generating C:\JAVA\allclasses-noframe.html... Generating C:\JAVA\allclasses-noframe.html... Generating C:\JAVA\index.html... Generating C:\JAVA\help-doc.html...
它將在 D:/test 目錄中建立更新的 Java 文件頁面,您將看到以下輸出。

多版本 JAR
Java 9 中的多版本 JAR 功能增強了 JAR 格式,以便多個特定於 Java 版本的類檔案可以共存於單個歸檔檔案中。
在多版本 Jar 格式中,一個 jar 檔案可以包含不同版本的 Java 類或資源,可以根據平臺進行維護和使用。在 JAR 中,檔案 MANIFEST.MF 檔案在其主部分中有一個條目 Multi-Release: true。META-INF 目錄還包含一個 versions 子目錄,其子目錄(從 Java 9 開始以 9 開頭)儲存特定於版本的類和資原始檔。
使用 MANIFEST.MF,我們可以指定 Java 9 或更高版本特定類的單獨位置,如下所示:
Java 多版本 Jar 檔案目錄結構示例
jar root - Calculator.class - Util.class - Math.class - Service.class META-INF - versions - 9 - Util.class - Math.class - 10 - Util.class - Math.class
現在,如果 JRE 不支援多版本 jar,則它將選擇根級別的類來載入和執行,否則,將載入特定於版本的類。例如,如果上述 jar 用於 Java 8,則將使用根級別的 Util.class。如果相同的 jar 由 Java 9 執行,則將選擇 Java 9 版本的特定類,依此類推。這樣,第三方庫/框架可以在不更改其針對較低版本編寫的原始碼的情況下支援新功能。
集合工廠方法改進
在 Java 9 中,為 List、Set 和 Map 介面添加了新的靜態工廠方法,以建立這些集合的不變例項。這些工廠方法主要是為了以更簡潔的方式建立集合的便利工廠方法。
Java 9 之前 List 介面工廠方法的示例
在這裡,我們正在建立 Java 9 之前不可修改的列表。
package com.tutorialspoint; import java.util.ArrayList; import java.util.Collections; import java.util.List; public class Tester { public static void main(String[] args) { List<String> list = new ArrayList<>(); list.add("Java"); list.add("HTML 5"); list.add("C"); list = Collections.unmodifiableList(list); System.out.println(list); } }
讓我們編譯並執行上述程式,這將產生以下結果:
[Java, HTML 5, C]
Java 9 中 List 介面工廠方法的示例
在這裡,我們正在建立 Java 9 中不可修改的列表。
package com.tutorialspoint; import java.util.List; public class Tester { public static void main(String[] args){ List<String> list = List.of("Java","HTML 5","C"); System.out.println(list); } }
讓我們編譯並執行上述程式,這將產生以下結果:
[Java, HTML 5, C]
私有介面方法
Java 9 引入了私有和靜態私有介面方法。作為私有方法,此類方法無法透過實現類或子介面訪問。引入這些方法是為了允許封裝,其中某些方法的實現將僅保留在介面中。這有助於減少重複性,提高可維護性和編寫整潔的程式碼。
示例 - Java 9 中介面中的私有方法
package com.tutorialspoint; interface util { public default int operate(int a, int b) { return sum(a, b); } private int sum(int a, int b) { return a + b; } } public class Tester implements util { public static void main(String[] args) { Tester tester = new Tester(); System.out.println(tester.operate(2, 3)); } }
輸出
讓我們編譯並執行上述程式,這將產生以下結果:
5
類似地,我們可以擁有私有靜態方法,該方法可以從靜態和非靜態方法中呼叫。
程序 API 改進
在 Java 9 中,負責控制和管理作業系統程序的 Process API 已經得到了相當大的改進。ProcessHandle 類現在提供了程序的原生程序 ID、啟動時間、累積 CPU 時間、引數、命令、使用者、父程序和子程序。ProcessHandle 類還提供方法來檢查程序的活動狀態並銷燬程序。它具有 onExit 方法,CompletableFuture 類可以在程序退出時非同步執行操作。
生成新程序示例
在此示例中,我們為記事本建立了一個新程序,並使用 ProcessBuilder 啟動它。使用 ProcessHandle.Info 介面,我們獲取新生成的程序的程序資訊。
package com.tutorialspoint; import java.time.ZoneId; import java.util.stream.Stream; import java.util.stream.Collectors; import java.io.IOException; public class Tester { public static void main(String[] args) throws IOException { ProcessBuilder pb = new ProcessBuilder("notepad.exe"); String np = "Not Present"; Process p = pb.start(); ProcessHandle.Info info = p.info(); System.out.printf("Process ID : %s%n", p.pid()); System.out.printf("Command name : %s%n", info.command().orElse(np)); System.out.printf("Command line : %s%n", info.commandLine().orElse(np)); System.out.printf("Start time: %s%n", info.startInstant().map(i -> i.atZone(ZoneId.systemDefault()) .toLocalDateTime().toString()).orElse(np)); System.out.printf("Arguments : %s%n", info.arguments().map(a -> Stream.of(a).collect( Collectors.joining(" "))).orElse(np)); System.out.printf("User : %s%n", info.user().orElse(np)); } }
輸出
您將看到類似的輸出。
Process ID : 5580 Command name : C:\Program Files\WindowsApps\Microsoft.WindowsNotepad_11.2401.26.0_x64__8wekyb3d8bbwe\Notepad\Notepad.exe Command line : Not Present Start time: 2024-04-02T17:07:14.305 Arguments : Not Present User : DESKTOP\Tutorialspoint
Stream API 改進
Stream 在 Java 8 中引入,以幫助開發人員從物件序列執行聚合操作。在 Java 9 中,添加了一些方法來改進 Stream。
takeWhile(Predicate 介面) 方法
語法
default Stream<T> takeWhile(Predicate<? super T> predicate)
takeWhile 方法獲取所有值,直到謂詞返回 false。在有序流的情況下,它返回一個流,該流包含從該流中獲取的與給定謂詞匹配的最長字首元素。
dropWhile(Predicate 介面)
語法
default Stream<T> dropWhile(Predicate<? super T> predicate)
dropWhile 方法丟棄開頭所有值,直到謂詞返回 true。在有序流的情況下,它返回一個流,該流包含在丟棄與給定謂詞匹配的最長字首元素後該流的剩餘元素。
iterate 方法
語法
static <T> Stream<T> iterate(T seed, Predicate<? super T> hasNext, UnaryOperator<T> next)
iterate 方法現在具有 hasNext 謂詞作為引數,一旦 hasNext 謂詞返回 false,迴圈就會停止。
ofNullable
語法
static <T> Stream<T> ofNullable(T t)
引入 ofNullable 方法是為了防止 NullPointerExceptions 並避免 Stream 的空檢查。此方法返回一個包含單個元素的順序 Stream(如果非空),否則返回一個空 Stream。
帶資源的 try 改進
在 Java 9 之前,資源需要在 try 之前或 try 語句內宣告,如下面的示例所示。在此示例中,我們將使用 BufferedReader 作為資源來讀取字串,然後關閉 BufferedReader。
Java 9 及更高版本
import java.io.BufferedReader; import java.io.IOException; import java.io.Reader; import java.io.StringReader; public class Tester { public static void main(String[] args) throws IOException { System.out.println(readData("test")); } static String readData(String message) throws IOException { Reader inputString = new StringReader(message); BufferedReader br = new BufferedReader(inputString); try (br) { return br.readLine(); } } }
輸出
讓我們編譯並執行上述程式,這將產生以下結果:
test
增強的 @Deprecated 註解
@Deprecated 註解是在 Java 5 版本中引入的。使用 @Deprecated 註解的程式元素意味著出於以下任何原因都不應使用它:
- 其使用可能會導致錯誤。
- 它可能在未來版本中不相容。
- 它可能在未來版本中被刪除。
- 更好的、更高效的替代方案已取代它。
每當使用已棄用的元素時,編譯器都會生成警告。在 Java 9 中,對 @Deprecated 註解進行了兩項新的增強。
forRemoval - 指示被註解的元素是否將在未來版本中被移除。預設值為 false。
since - 返回被註解的元素何時被棄用的版本。預設值為空字串。
使用 since 棄用
以下 Java 9 上 Boolean 類的 javadoc 示例說明了在 @Deprecated 註解上使用 since 屬性。

使用 forRemoval 棄用
以下 Java 9 上 System 類的 javadoc 示例說明了在 @Deprecated 註解上使用 forRemoval 屬性。

內部類菱形運算子
在 Java 9 中,菱形運算子也可以與匿名類一起使用,以簡化程式碼並提高可讀性。
示例
在下面的示例中,我們為抽象類 Handler 建立了匿名類,該類接受泛型引數,但在建立匿名類時沒有物件型別,因為我們不需要傳遞型別引數。編譯器本身會推斷型別。
public class Tester { public static void main(String[] args) { // create an Anonymous class to handle 1 // Here we do not need to pass Type arguments in diamond operator // as Java 9 compiler can infer the type automatically Handler<Integer> intHandler = new Handler<>(1) { @Override public void handle() { System.out.println(content); } }; intHandler.handle(); Handler<? extends Number> intHandler1 = new Handler<>(2) { @Override public void handle() { System.out.println(content); } }; intHandler1.handle(); Handler<?> handler = new Handler<>("test") { @Override public void handle() { System.out.println(content); } }; handler.handle(); } } abstract class Handler<T> { public T content; public Handler(T content) { this.content = content; } abstract void handle(); }
輸出
讓我們編譯並執行上述程式,這將產生以下結果:
1 2 Test
多解析度影像 API
多解析度影像 API 是在 Java 9 中引入的。此 API 支援具有不同解析度變體的多個影像。此 API 允許將一組具有不同解析度的影像用作單個多解析度影像。
考慮以下影像。



這些是三個不同尺寸的徽標影像。
現在,為了使用這三個影像,從 Java 9 開始,可以使用多解析度影像 API 作為單個 API 來獲取所有變體或要顯示的特定變體。
// read all images into one multiresolution image MultiResolutionImage multiResolutionImage = new BaseMultiResolutionImage(images.toArray(new Image[0]));
這裡 MultiResolutionImage 和 BaseMultiResolutionImage 類是 java.awt.image 包的一部分。
以下是多解析度影像的主要操作。
Image getResolutionVariant(double destImageWidth, double destImageHeight) - 獲取最適合在指定尺寸下表示此邏輯影像的特定影像。
List<Image> getResolutionVariants() - 獲取所有解析度變體的可讀列表。
示例 - 獲取所有變體
在此示例中,我們載入了三個影像並將它們儲存在 MultiResolutionImage 中。然後使用 getResolutionVariants() 方法,我們檢查此多解析度影像中所有可用的影像變體並列印它。
package com.tutorialspoint; import java.awt.Image; import java.awt.image.BaseMultiResolutionImage; import java.awt.image.MultiResolutionImage; import java.io.IOException; import java.net.MalformedURLException; import java.net.URL; import java.util.ArrayList; import java.util.List; import javax.imageio.ImageIO; public class Tester { public static void main(String[] args) throws IOException, MalformedURLException { // prepare a list of urls of all images List<String> imgUrls = List.of("https://tutorialspoint.tw/java9/images/logo.png", "https://tutorialspoint.tw/java9/images/mini_logo.png", "https://tutorialspoint.tw/java9/images/large_logo.png"); // create a list of Image object List<Image> images = new ArrayList<Image>(); // Create image objects using image urls for (String url : imgUrls) { images.add(ImageIO.read(new URL(url))); } // read all images into one multiresolution image MultiResolutionImage multiResolutionImage = new BaseMultiResolutionImage(images.toArray(new Image[0])); // get all variants of images List<Image> variants = multiResolutionImage.getResolutionVariants(); System.out.println("Total number of images: " + variants.size()); // print all the images for (Image img : variants) { System.out.println(img); } } }
輸出
讓我們編譯並執行上述程式,這將產生以下結果:
Total number of images: 3 BufferedImage@7ce6a65d: type = 6 ColorModel: #pixelBits = 32 numComponents = 4 color space =java.awt.color.ICC_ColorSpace@548ad73b transparency = 3 has alpha = true isAlphaPre = false ByteInterleavedRaster: width =311 height = 89 #numDataElements 4 dataOff[0] = 3 BufferedImage@4c762604: type = 6 ColorModel: #pixelBits = 32 numComponents = 4 color space =java.awt.color.ICC_ColorSpace@548ad73b transparency = 3 has alpha = true isAlphaPre = false ByteInterleavedRaster: width =156 height = 45 #numDataElements 4 dataOff[0] = 3 BufferedImage@2641e737: type = 6 ColorModel: #pixelBits = 32 numComponents = 4 color space =java.awt.color.ICC_ColorSpace@548ad73b transparency = 3 has alpha = true isAlphaPre = false ByteInterleavedRaster: width =622 height = 178 #numDataElements 4 dataOff[0] = 3
CompletableFuture API 增強
CompletableFuture 類是在 Java 8 中引入的,用於表示 Future,可以透過顯式設定其值和狀態來完成它。它可以用作 java.util.concurrent.CompletionStage。它支援依賴函式和操作,這些函式和操作會在 Future 完成時觸發。在 Java 9 中,CompletableFuture API 得到了進一步增強。以下是對 API 進行的相關更改。
- 支援延遲和超時。
- 改進對子類的支援。
- 添加了新的工廠方法。
支援延遲和超時
public CompletableFuture<T> completeOnTimeout(T value, long timeout, TimeUnit unit)
如果在給定超時之前未完成,則此方法使用給定值完成此 CompletableFuture。
public CompletableFuture<T> orTimeout(long timeout, TimeUnit unit)
如果在給定超時之前未完成,則此方法使用 TimeoutException 異常完成此 CompletableFuture。
改進對子類的支援
public Executor defaultExecutor()
它返回用於未指定 Executor 的非同步方法的預設 Executor。可以在子類中重寫此方法以返回 Executor,以提供至少一個獨立執行緒。
public <U> CompletableFuture<U> newIncompleteFuture()
返回 CompletionStage 方法要返回的型別的新的不完整 CompletableFuture。CompletableFuture 類的子類應重寫此方法以返回與該 CompletableFuture 相同類的例項。預設實現返回 CompletableFuture 類的例項。
新的工廠方法
public static <U> CompletableFuture<U> completedFuture(U value)
此工廠方法返回一個新的 CompletableFuture,它已使用給定值完成。
public static <U> CompletionStage<U> completedStage(U value)
此工廠方法返回一個新的 CompletionStage,它已使用給定值完成,並且僅支援介面 CompletionStage 中存在的方法。
public static <U> CompletionStage<U> failedStage(Throwable ex)
此工廠方法返回一個新的 CompletionStage,它已使用給定異常異常完成,並且僅支援介面 CompletionStage 中存在的方法。
其他功能
除了提到的功能外,Java 9 還對 JDK 平臺進行了大量增強。其中一些列在下面。
- GC(垃圾收集器)改進
- 堆疊遍歷 API
- 過濾傳入的序列化資料
- 棄用 Applet API
- 最佳化字串連線
- 增強的 Method Handles
- Java 平臺日誌記錄 API 和服務
- 緊湊字串
- Nashorn 的解析器 API