02.05 JShell—Java 9及後續版中用於快速原型設計的新REPL工具

原文: https://www.jdon.com/50823

REPL代表

Read-Eval-Print-Loop。聽起來有點神秘,但它只是編程語言的交互式shell的一個奇特名稱。如今,許多語言已經提供了REPL。即使在JVM Groovy上,Kotlin,Scala和Clojure也已經擁有它。從版本9開始的Java最終有自己的REPL,稱為JShell

好吧,所以Java終於擁有了它新的閃亮的REPL。但它有什麼好處呢?好吧,簡而言之,它允許您將獨立的Java代碼片段寫入控制檯(READ),立即執行它們(EVAL),然後查看結果(PRINT)並繼續記住您已編寫的內容(LOOP)。如果您想快速嘗試一段代碼,草擬算法,檢查某些方法如何處理異常輸入,為您的博客帖子創建和測試代碼片段,它是一個完美的工具。您只需快速嘗試一些一次性代碼並立即看到結果。最好的部分是 - 它不需要大多數Java樣板。

雖然原型設計和快速代碼驗證很重要,但還有另一個原因可以讓REPL變得有用。特別是在一個冗長的語言中,如Java等樣板文件。想象一下,您正在教授Java初學者。你需要寫一個簡單的hello world程序,只打印到控制檯?可以使用帶main方法的類。問題是您需要向學生展示他們現在不需要擔心的許多概念,例如類,方法,靜態,字符串數組等。然後,當您進行更改時,您需要重新編譯並重新運行整個系統。

交互式控制檯不需要使用main類,並立即顯示輸出。您可以嘗試各種結構,並快速查看結果。您不需要任何IDE。您可以使用最少的設置和對所有高級概念的最少知識開始編程,當時只學習一個構造。這種高門檻也導致許多學校和機構放棄Java作為編程語言選擇的介紹。教育方面實際上是JEP222中所述功能的主要動機。

運行JShell

JShell與JDK 9+安裝捆綁在一起。它駐留在JDK \\ bin文件夾中。例如在Windows上它可以在這裡:

C:\\Program Files\\Java\\jdk-9.0.4\\bin\\jshell.exe

要直接從控制檯運行它,請確保將JDK \\ bin添加到您的PATH。然後只需運行jshell命令。現在,讓我們使用詳細模式-v,這將有助於我們更好地瞭解幕後發生的事情。或者,您可以直接從bin目錄運行可執行文件。最後一個選項是使用IDE集成。

如果你使用IntelliJ IDEA,你不必擔心在類路徑上使用JShell,因為IDEA直接在IDE中提供了與JShell開箱即用的出色集成。您將獲得所有有用的功能,例如代碼完成,語法突出顯示,錯誤檢測等。

若要從IDEA訪問JShell,去工具→JShell控制檯...。

C:\\Users\\vojtech> jshell -v
| Welcome to JShell -- Version 10.0.1
| For an introduction type: /help intro
jshell>

現在您處於交互模式,JShell會評估您編寫的任何內容。要退出JShell只需鍵入/exit。

表達式

從JShell開始的最簡單方法是編寫一個簡單的表達式。它可以是一個簡單的數學表達式:

jshell> 7*(3+12)
$1 ==> 105
| created scratch variable $1 : int

如您所見,表達式立即被評估,結果將打印到控制檯。無需先聲明任何變量。然而,為方便起見,我們創建了一個名為$ 1的臨時變量,我們可以從現在開始使用它。請注意,變量的類型被推斷為int。

然而,表達不限於如上所述的簡單數學表達式。這不會很有用。你幾乎可以用Java做任何事情。

jshell> Math.sqrt($1)+7
$2 ==> 17.246950765959596

首先,請注意我們能夠使用上一個示例中的$ 1變量。在每個命令之間保留狀態。另一個值得注意的特性是,正如您所看到的,在大多數情況下,分號是可選的。

變量

即使JShell在未將返回值分配給任何變量時為我們聲明變量,通常最好聲明自己的變量。如果僅為了描述性命名。您可以將它們聲明為局部變量。

jshell> int myVariable = 42

一段時間後,您可能會混淆已經聲明的變量以及它們的值。這是一個特定的命令 - 只需鍵入/vars。

如果您已經使用Java 10,則可以使用 var而不是顯式聲明類型

方法

如上所述,您可以不需要在任何類中而是直接在根級別聲明變量,您可以對方法執行相同的操作。同樣,您不必擔心任何修飾符,例如public,static或final。您只需以返回類型和方法名稱開頭,並帶有可能的參數:

jshell> String sayHello(String name) {
...> return"Hello, my name is "+name;
...> }
| created method sayHello(String)
jshell> sayHello("Joe")
$7 ==> "Hello, my name is Joe"
| created scratch variable $7 : String

在上面的示例中,您可以看到我們聲明瞭一個方法然後調用它。請注意,與頂層不同,內部方法和類分號不是可選的。

常見的情況是當方法使用另一個尚未聲明的方法或變量時。它被稱為前向引用,JShell允許您這樣做。但是,在聲明所有依賴項之前,不能使用此類方法。

jshell> String myMethod(String name) {
...> return otherMethodNotDeclared();
...> }
| created method myMethod(String), however, it cannot be invoked until method otherMethodNotDeclared() is declared

與/vars變量類似,您可以列出所有當前聲明的方法/methods。

類型

頂級變量和方法很有用,但通常需要聲明和使用常規類,枚舉或接口。你可以像往常一樣,這裡沒有特定的JShell。請記住,在這種情況下需要分號。您可以通過/types列出所有聲明的類型。

jshell> class Person {
...> private String name;
// [more code here]
...> }
| created class Person

使用外部代碼

如上例所示定義所有類是一項繁瑣的任務。更重要的是,您通常希望使用JDK中已有的類甚至您自己的類。

對於JDK類,您可以import照常使用。為方便起見,默認情況下已導入許多常用類。不僅往常一樣java.lang,而且java.io,java.math,java.util或java.nio.file。您可以列出所有當前導入/import。

當然,如果JShell無法訪問所需的類,則導入將毫無用處。

您的類需要在類路徑上。第一種選擇是使用CLASSPATH環境變量。或者您可以在啟動JShell時指定classpath:

jshell --class-path foo-1.0.0.jar

您可以直接從jshell定義類路徑:

jshell> /env -class-path foo-1.0.0.jar

如果您使用的是Java 9模塊系統,則可以在啟動JShell時指定要導入的模塊:

jshell --add-modules some.module

例外

好消息是JShell可以很好地處理異常。每當發生異常時,JShell都會捕獲它,打印它並且您的會話不會終止。很酷的是,與常規Java不同,它不會強制您處理已檢查的異常,這會刪除大量的try-catch樣板。

保存並加載您的工作

當您在更復雜的用例中使用JShell時,能夠保存您的工作並在以後繼續使用通常很方便。或者只是保存您的會話以供將來參考。幸運的是JShell支持使用/save保存和加載會話/open :

jshell> /save myfile.jsh

jshell> /open myfile.jsh

雖然您可以直接在JShell控制檯中編寫和編輯所有內容,但它並不總是最好的方法。編輯可能繁瑣且繁瑣。使用專用的外部文本編輯器通常更好。要打開到目前為止在外部編輯器中輸入的所有代碼段,請鍵入/edit。

您可以配置自己的編輯器,一種方法是傳達環境變量JSHELLEDITOR。或者,您可以直接從JShell設置編輯器。使用-retain選項可在會話之間保留此設置。

jshell> /set editor myEditor -retain

如果您的編輯器未打開PATH,則需要提供可執行文件的完整路徑。

以編程方式使用JShell

一個非常有趣的選擇是將Java應用程序與JShell集成。您可以以編程方式創建JShell實例,然後在您的應用程序中使用它。所有必需的類都在jdk.jshell。首先,您需要創建一個JShell實例,然後您可以使用它來評估代碼片段。

JShell shell = JShell.create();
List<snippetevent> events = shell.;
/<snippetevent>

該eval方法評估代碼片段並返回在評估期間發生的

事件 列表。通過這些,您可以判斷是否發生了一些異常以及代碼段是否有效。要訪問有關代碼段本身的詳細信息,您需要調用snippetEvent.snippet()。

JShell shell = JShell.create();
List<snippetevent> events = shell.;
SnippetEvent event = events.get(0);
Snippet snippet = event.snippet();
Snippet.Kind kind = snippet.kind();
String source = snippet.source();
/<snippetevent>

要獲取代碼段的完整源代碼,您可以使用snippet.source()。

本篇就介紹這麼多了,後續專門開展一個系列,詳細的介紹JShell方方面面。


分享到:


相關文章: