概述

这篇文章是关于即将在Java 9发布中随JDK一同提供的交互式REPL(Read-Evaluate-Print-Loop)环境——jshell。对于不熟悉这个概念的人来说,REPL允许用户交互式地运行代码片段并查看其结果。

REPL可以在诸如快速验证想法或查找例如StringSimpleDateFormat格式化字符串等场景中派上用场。

运行

首先,我们需要运行REPL,这可以通过以下命令完成:

$JAVA_HOME/bin/jshell

如果希望获得更详细的Shell输出,可以使用-v标志:

$JAVA_HOME/bin/jshell -v

准备好后,我们将看到友好的欢迎消息和熟悉的Unix风格提示符出现在底部。

定义和调用方法

我们可以输入方法签名和实现来添加方法:

jshell> void helloWorld() { System.out.println("Hello world");}
|  created method helloWorld()

这里我们定义了一个常见的“Hello, World”方法。使用常规的Java语法可以调用它:

jshell> helloWorld()
Hello world

变量

可以使用标准的Java声明语法定义变量:

jshell> int i = 0;
i ==> 0
|  created variable i : int

jshell> String company = "Baeldung"
company ==> "Baeldung"
|  created variable company : String

jshell> Date date = new Date()
date ==> Sun Feb 26 06:30:16 EST 2017
|  created variable date : Date

注意,分号是可选的。变量也可以在未初始化的情况下声明:

jshell> File file
file ==> null
|  created variable file : File

表达式

任何有效的Java表达式都将被接受,表达式的计算结果将显示出来。如果没有提供结果的明确接收者,jshell会创建临时变量:

jshell> String.format("%d of bottles of beer", 100)
$6 ==> "100 of bottles of beer"
|  created scratch variable $6 : String

REPL在这里非常有帮助,它告诉我们它创建了一个名为$6的临时变量,值为“墙上挂着100瓶啤酒”,类型为String

多行表达式也是可能的。jshell足够智能,知道何时表达式不完整,并提示用户在新的一行继续输入:

jshell> int i =
   ...> 5;
i ==> 5
|  modified variable i : int
|    update overwrote variable i : int

请注意提示如何变为缩进的...>,表示表达式的延续。

命令

jshell提供了许多与执行Java语句无关的元命令。它们都以斜杠(/)开头,以便与正常操作区分开。例如,我们可以通过发出*/help/?*来请求列出所有可用命令。

让我们来看看其中的一些。

6.1. 导入

要列出当前会话中激活的所有导入,可以使用*/import*命令:

jshell> /import
|    import java.io.*
|    import java.math.*
|    import java.net.*
|    import java.nio.file.*
|    import java.util.*
|    import java.util.concurrent.*
|    import java.util.function.*
|    import java.util.prefs.*
|    import java.util.regex.*
|    import java.util.stream.*

如图所示,Shell已经开始自动添加了一些有用的导入。

6.2. 列表

在REPL中工作并不像拥有功能齐全的IDE那样方便:容易忘记变量的值、定义了哪些方法等等。要检查Shell的状态,可以使用*/var/methods/list/history:*。

jshell> /var
| int i = 0
| String company = "Baeldung"
| Date date = Sun Feb 26 06:30:16 EST 2017
| File file = null
| String $6 = "100 of bottles of beer on the wall"

jshell> /methods
| void helloWorld()

jshell> /list

 1 : void helloWorld() { System.out.println("Hello world");}
 2 : int i = 0;
 3 : String company = "Baeldung";
 4 : Date date = new Date();
 5 : File file;
 6 : String.format("%d of bottles of beer on the wall", 100)

jshell> /history

void helloWorld() { System.out.println("Hello world");}
int i = 0;
String company = "Baeldung"
Date date = new Date()
File file
String.format("%d of bottles of beer on the wall", 100)
/var
/methods
/list
/history

listhistory之间的区别在于,后者除了表达式还会显示命令。

6.3. 保存

要保存表达式历史,可以使用*/save*命令:

jshell> /save repl.java

这将把我们的表达式历史保存到与运行jshell命令时所在的目录相同的repl.java文件中。

6.4. 加载

要加载先前保存的文件,可以使用*/open*命令:

jshell> /open repl.java

加载后的会话可以通过执行*/var/method/list*进行验证。

6.5. 退出

当我们完成工作时,可以使用*/exit*命令关闭Shell:

jshell> /exit
|  Goodbye

再见,jshell

总结

在这篇文章中,我们探讨了Java 9的REPL环境。尽管Java已经存在了超过20年,但它可能稍显滞后。然而,它无疑将成为我们Java工具箱中的另一个有价值的工具。