一、前言
Java Shell (JShell),自 Java 9 開始引入,是一個互動式的 Java REPL (Read-Eval-Print Loop) 工具。它允許開發者即時執行 Java 程式碼片段,無需完整的類別宣告或編譯步驟。對於學習 Java 語法、快速測試程式碼邏輯、實驗 API 或進行程式碼除錯都非常方便。雖然 JShell 主要在 Java 9 中推出,但 Java 7 和 8 並沒有這個功能。直到 Java 9 後,JShell 不斷地演進,新增了許多實用特性。本文將整理 Java 9 至 Java 17 之間 JShell 的重要新特性,並分析其應用場景。
二、JShell 的基本架構與運作原理
JShell 的核心概念是建立一個互動式的程式碼執行環境。它的架構可以簡單分為以下幾個部分:
- 輸入解析器 (Input Parser): 負責接收使用者輸入的 Java 程式碼片段。
- 程式碼編譯器 (Code Compiler): 將輸入的程式碼片段動態編譯為 bytecode。
- 執行引擎 (Execution Engine): 負責執行已編譯的 bytecode。
- 輸出處理器 (Output Processor): 顯示執行結果或錯誤訊息。
- 狀態維護器 (State Manager): 管理 JShell 的執行狀態,例如變數、方法、類別等。
JShell 的運作流程大致如下:
- 使用者輸入 Java 程式碼片段(例如,變數宣告、運算式、方法呼叫)。
- 輸入解析器分析程式碼片段。
- 程式碼編譯器將程式碼片段動態編譯成 bytecode。
- 執行引擎執行編譯後的 bytecode。
- 輸出處理器將執行結果顯示給使用者。
- 狀態維護器記錄程式碼片段的執行狀態。
示意圖:
三、Java 9 JShell 的引入與基本功能
Java 9 是 JShell 的誕生版本,其主要特色與功能包括:
-
互動式程式碼執行: 可以直接輸入 Java 程式碼片段並即時執行,例如宣告變數、執行運算式、定義方法等。
xxxxxxxxxx
1jshell> int x = 10;
2x ==> 10
3
4jshell> x * 2
5$2 ==> 20
6
7jshell> System.out.println("Hello, JShell!");
8Hello, JShell!
9
-
支援 import 語法: 可以引入 Java 類別或 package。
xxxxxxxxxx
1jshell> import java.util.List;
2jshell> List<String> myList = List.of("a", "b", "c");
3myList ==> [a, b, c]
4
-
歷史紀錄: 可以使用方向鍵瀏覽和重新執行之前輸入的程式碼。
-
內建命令: 提供許多內建命令來管理 JShell 環境,例如
/list
(列出輸入過的程式碼片段),/vars
(列出變數) ,/methods
(列出方法),/exit
(退出 JShell) 等 [1] 。 -
支援類別與介面: 可以定義類別和介面,並在 JShell 中使用它們。
xxxxxxxxxx
1jshell> class MyClass { int value = 5; public int getValue(){ return value;} }
2| 已建立類別 MyClass
3
4jshell> MyClass mc = new MyClass();
5mc ==> MyClass
6
7jshell> mc.getValue();
8$7 ==> 5
9
-
開啟執行 JShell 互動介面
使用
jshell
指令進入互動介面。xxxxxxxxxx
1$ jshell
2| Welcome to JShell -- Version 17.0.13
3| For an introduction type: /help intro
4
5jshell> /help
6| Type a Java language expression, statement, or declaration.
7| Or type one of the following commands:
8| /list [<name or id>|-all|-start]
9| list the source you have typed
10| /edit <name or id>
11| edit a source entry
12| /drop <name or id>
13| delete a source entry
14| /save [-all|-history|-start] <file>
15| Save snippet source to a file
16| /open <file>
17| open a file as source input
18| /vars [<name or id>|-all|-start]
19| list the declared variables and their values
20| /methods [<name or id>|-all|-start]
21| list the declared methods and their signatures
22| /types [<name or id>|-all|-start]
23| list the type declarations
24| /imports
25| list the imported items
26| /exit [<integer-expression-snippet>]
27| exit the jshell tool
28| /env [-class-path <path>] [-module-path <path>] [-add-modules <modules>] ...
29| view or change the evaluation context
30| /reset [-class-path <path>] [-module-path <path>] [-add-modules <modules>]...
31| reset the jshell tool
32| /reload [-restore] [-quiet] [-class-path <path>] [-module-path <path>]...
33| reset and replay relevant history -- current or previous (-restore)
34| /history [-all]
35| history of what you have typed
36| /help [<command>|<subject>]
37| get information about using the jshell tool
38| /set editor|start|feedback|mode|prompt|truncation|format ...
39| set configuration information
40| /? [<command>|<subject>]
41| get information about using the jshell tool
42| /!
43| rerun last snippet -- see /help rerun
44| /<id>
45| rerun snippets by ID or ID range -- see /help rerun
46| /-<n>
47| rerun n-th previous snippet -- see /help rerun
48|
49| For more information type '/help' followed by the name of a
50| command or a subject.
51| For example '/help /list' or '/help intro'.
52|
53| Subjects:
54|
55| intro
56| an introduction to the jshell tool
57| keys
58| a description of readline-like input editing
59| id
60| a description of snippet IDs and how use them
61| shortcuts
62| a description of keystrokes for snippet and command completion,
63| information access, and automatic code generation
64| context
65| a description of the evaluation context options for /env /reload and /reset
66| rerun
67| a description of ways to re-evaluate previously entered snippets
68
69jshell>
70
建議使用的退出方式:
- 首選 /exit 命令: 這是最乾淨和推薦的退出方式,可以確保 JShell 正常終止,並釋放資源。
- Ctrl + D 作為快捷鍵: 如果你希望快速退出,可以使用 Ctrl + D。
xxxxxxxxxx
1$ jshell
2| Welcome to JShell -- Version 17.0.13
3| For an introduction type: /help intro
4
5jshell> /exit
6| Goodbye
7
-
JShell 自動補全功能
自動補全功能是一個非常實用的特性。按下 Tab 鍵可以進行以下自動補全:
- 關鍵字和指令: 例如 int, class, import, /list, /vars 等等。
- 變數名稱: 如果你宣告了變數,按下 Tab 鍵可以補全該變數的名稱。
- 方法名稱: 如果你呼叫方法或存取物件的成員,按下 Tab 鍵可以補全方法名稱或成員名稱。
- 類別和套件名稱: 如果你使用 import 語法,按下 Tab 鍵可以補全類別名稱或套件名稱。
自動補全的使用方法:
- 輸入部分程式碼: 在 JShell 提示符號後輸入你想要補全的程式碼片段。
- 按下 Tab 鍵: 按下 Tab 鍵。
- 如果有多個選項: 如果有多個可能的選項,JShell 會顯示一個清單,你可以繼續輸入或者使用方向鍵選擇。 選擇補全選項: JShell 會將補全選項填入,然後你就可以繼續編輯或執行。
範例:
- 輸入 Sys 然後按下 Tab 鍵: JShell 會補全為 System,因為這是 Java 標準函式庫中最符合的類別。
- 輸入 System.o 然後按下 Tab 鍵: JShell 會顯示以 o 開頭的 System 類別的成員,例如 out。
- 輸入 System.out.p 然後按下 Tab 鍵: JShell 會顯示以 p 開頭的 System.out 物件的方法,例如 print, println, printf。
- 輸入 List 然後按下 Tab 鍵: 如果已經 import java.util.*, JShell 會顯示可能的 List 介面補全。
xxxxxxxxxx
1jshell> List
2List ListIterator ListResourceBundle
3
4Signatures:
5java.util.List<E>
6
7<press tab again to see documentation>
8jshell> List
9java.util.List<E>
10An ordered collection (also known as a sequence ).The user of this interface has
11precise control over where in the list each element is inserted. The user can
12access elements by their integer index (position in the list), and search for
13elements in the list.
14Unlike sets, lists typically allow duplicate elements. More formally, lists
15typically allow pairs of elements e1 and e2 such that e1.equals(e2) , and they
16typically allow multiple null elements if they allow null elements at all. It is
17not inconceivable that someone might wish to implement a list that prohibits
18duplicates, by throwing runtime exceptions when the user attempts to insert
19them, but we expect this usage to be rare.
20The List interface places additional stipulations, beyond those specified in the
21Collection interface, on the contracts of the iterator , add , remove , equals ,
22and hashCode methods. Declarations for other inherited methods are also included
23here for convenience.
24The List interface provides four methods for positional (indexed) access to list
25elements. Lists (like Java arrays) are zero based. Note that these operations
26may execute in time proportional to the index value for some implementations
27(the LinkedList class, for example). Thus, iterating over the elements in a list
28is typically preferable to indexing through it if the caller does not know the
29
30<press tab again to see next page>
31jshell> List
32
四、Java 10 至 17 JShell 的新特性與改進
自 Java 9 之後,JShell 並沒有重大改版,主要是針對穩定性、效能和一些便利性做了改進。以下列出 Java 10 至 Java 17 間 JShell 的一些新特性與改進:
-
效能優化: 各版本針對 JShell 的執行速度和資源消耗進行了優化,讓 JShell 執行起來更快速、更穩定。
-
Bug 修復: 各版本針對 JShell 發現的錯誤進行修復,提升了 JShell 的可靠性。
-
更友善的錯誤訊息: JShell 的錯誤訊息更加清晰,更容易讓開發者理解錯誤的原因。
-
更方便的操作: JShell 可能在特定版本中優化了指令或操作方式,使其使用更加方便,但這些屬於小型的優化,並沒有革命性的改動。
-
與新 Java 特性的整合: JShell 會跟隨新 Java 版本同步更新,確保能正常執行新版本 Java 語法和特性,例如:
-
Java 10 的 var 關鍵字:
xxxxxxxxxx
1jshell> var str = "Hello";
2str ==> "Hello"
3
-
Java 14 的 Record 類型:
xxxxxxxxxx
1jshell> record Point(int x, int y) {}
2| 已建立記錄 Point
3
4jshell> Point p = new Point(1, 2);
5p ==> Point[x=1, y=2
6
五、JShell 的應用場景與範例
JShell 的應用場景非常廣泛,以下列舉一些常見例子:
-
學習 Java 語法:
JShell 是一個學習 Java 語法的絕佳工具,可以即時驗證程式碼片段,加速學習過程。例如:
xxxxxxxxxx
1jshell> String message = "Hello";
2message ==> "Hello"
3
4jshell> message.toUpperCase()
5$2 ==> "HELLO"
6
-
API 探索:
可以快速探索 Java 標準函式庫或第三方函式庫,例如嘗試不同 API 的使用方法。
xxxxxxxxxx
1jshell> import java.time.LocalDateTime;
2jshell> import java.time.format.DateTimeFormatter;
3jshell> LocalDateTime now = LocalDateTime.now();
4now ==> 2024-01-02T16:30:45.123
5jshell> now.format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss"))
6$4 ==> "2024-01-02 16:30:45"
7
-
快速程式碼測試:
在開發過程中,可以使用 JShell 快速測試程式碼片段,例如驗證演算法邏輯或運算式結果。
xxxxxxxxxx
1jshell> int a = 5;
2jshell> int b = 10;
3jshell> a > b ? "a is bigger" : "b is bigger";
4$8 ==> "b is bigger"
5
-
除錯輔助:
JShell 可以當作簡單的除錯工具,快速驗證變數的值或程式碼邏輯。
xxxxxxxxxx
1jshell> int value = 10;
2jshell> value = value + 5;
3value ==> 15
4
六、總結
JShell 自 Java 9 引入以來,提供了一個方便的互動式 Java 開發環境。雖然 Java 10 至 17 的版本更新主要集中在效能提升、bug 修復和與新語法的整合,沒有革命性的功能新增,但是 JShell 仍然是 Java 開發者學習、測試、除錯的有效工具。透過 JShell,開發者可以更快速地迭代程式碼,提升開發效率。無論你是 Java 初學者,還是資深的 Java 開發者,JShell 都是一個值得學習和使用的實用工具。
附錄
-
基本的 JShell 指令:
-
/help 或 /:
- 顯示 JShell 的幫助資訊,列出所有可用的指令。
- /help <指令> 顯示特定指令的詳細說明,例如 /help /list。
-
/exit:
- 退出 JShell 環境。
-
/list 或 /l:
- 列出所有已經輸入的程式碼片段,包括宣告、方法、類別等。
- /list -all 列出所有程式碼片段,包括隱藏的(如自動產生的)。
- /list <編號> 列出指定編號的程式碼片段。
-
/vars:
- 列出所有已定義的變數及其值。
- /vars <變數名稱> 列出特定變數的值和類型。
-
/methods:
- 列出所有已定義的方法。
-
/types:
- 列出所有已定義的類別、介面、枚舉等類型。
-
/edit 或 /e:
- 打開一個編輯器來編輯指定的程式碼片段。
- /edit <編號> 編輯指定編號的程式碼片段。
- /edit <名稱> 編輯指定名稱的程式碼片段。
-
/drop:
- 刪除指定程式碼片段。
- /drop <編號> 刪除指定編號的程式碼片段。
- /drop <名稱> 刪除指定名稱的程式碼片段。
-
/reset:
- 重置 JShell 環境,清除所有已輸入的程式碼、變數、方法等。
-
/history 或 /h:
- 顯示命令歷史紀錄。
- /history <數字> 顯示最近的指定數量的命令歷史紀錄。
-
/help 或 /:
-
其他實用的 JShell 指令:
-
/import:
- 導入類別或套件。
- 例如:/import java.util.List
-
/save:
- 將目前的 JShell 狀態 (包括所有輸入的程式碼片段) 儲存到一個檔案。
- /save <檔案路徑> 例如 /save myjshell.jsh。
-
/open:
- 從檔案中讀取 JShell 程式碼,並在目前的環境中執行。
- /open <檔案路徑> 例如 /open myjshell.jsh。
-
/classpath 或 /cp:
- 顯示目前的 Classpath 設定。
- /classpath <路徑> 可以設定 Classpath。
-
/set:
- 設定 JShell 的選項,例如顯示模式、編輯器等。
- 例如: /set editor notepad (Windows) 或 /set editor vim (Linux/macOS)。
- /set feedback normal (設定回饋模式為一般)
-
/reload
- 重新執行所有已經輸入的程式碼。
-
/import:
沒有留言:
張貼留言