在 JavaOne 2016 的主题演讲中,Java 平台组的首席架构师 Mark Reinhold 指出 Java 9 并不仅仅是 Jigsaw,针对 Java 9,一共包含了 85 个 JEP 。我在这里会关注一个他所强调的 Java 新特性, JEP 222 ,那就是 Java shell(也被称为 JShell)。
借助 JShell,Java 9 能够让开发人员使用 REPL(Read-Eval-Print loop),这是一个交互式的工具,它会计算用户的输入并打印输出,输出的内容要么是一个值要么是一个状态变更。
JShell 是什么?
JShell 是一个 API 和工具,它能够帮助计算代码片段的值。代码片段必须要遵循 Java 语言规范(Java Language Specification,JLS)的语法。JShell 也能够执行查询和命令。命令和片段的区别在于,命令要以一个斜线开头,可以参考如下的样例:
jshell> /import | import java.util.* | import java.io.* | import java.math.* | import java.net.* | import java.util.concurrent.* | import java.util.prefs.* | import java.util.regex.*
JShell 状态其实是模仿了一个 JVM 实例。JShell 会借助编译器 API(Compiler API)来进行代码分析、tab 代码补全和原始代码片段的解析,它使用 Java 调试接口(Java Debug Interface,JDI)实现了代码替换功能。
如果用户不喜欢交互式界面的话,还可以使用批量脚本。
JavaOne 上展现的 JShell 样例
在介绍 Reinhold JavaOne 上的样例之前,我想要补充一句,如果你使用最新版本的 Java 9 SDK 并输入java –version
的话,那么会发现现在的版本号字符串会有所变更,如下所示:
$ java -version java version "9-ea" Java(TM) SE Runtime Environment (build 9-ea+136) Java HotSpot(TM) 64-Bit Server VM (build 9-ea+136, mixed mode)
我们可以与旧的格式进行对比:
java version "1.8.0_91" Java(TM) SE Runtime Environment (build 1.8.0_91-b14) Java HotSpot(TM) 64-Bit Server VM (build 25.91-b14, mixed mode)
这种变更是由 JEP 223 所引入的新模式带来的。目前的版本字符串更易于解析,并且更符合当前行业实践所强调的语义化版本(Semantic Versioning)。这种新的模式能够帮助我们更容易地识别主版本(major)、小版本(minor)或安全升级的发布版本。
在上面的样例中,预发布识别符( ea
——读作“早期访问”)前面会有一个“-”,紧接着是一个“+”号,随后是这次构建所对应的构建号(136
)。
回到样例上来,如果你在命令行输入“jshell
”的话,将会看到如下所示的 JShell 提示:
$ jshell | Welcome to JShell -- Version 9-ea | For an introduction type: /help intro jshell>
如果你输入一个像下面这样的简单 String 声明,就能看到所有可调用的方法(包括重载的方法):
jshell> String x = "foo bar baz" x ==> "foo bar baz" jshell> x. charAt( chars() codePointAt( codePointBefore( codePointCount( codePoints() compareTo( compareToIgnoreCase( concat( contains( contentEquals( endsWith( equals( equalsIgnoreCase( getBytes( getChars( getClass() hashCode() indexOf( intern() isEmpty() lastIndexOf( length() matches( notify() notifyAll() offsetByCodePoints( regionMatches( replace( replaceAll( replaceFirst( split( startsWith( subSequence( substring( toCharArray() toLowerCase( toString() toUpperCase( trim() wait( jshell> x.substring(4,7) $3 ==> "bar" jshell> Arrays.asList(x.split("")) $5 ==> [f, o, o, , b, a, r, , b, a, z] jshell> Arrays.asList(x.split(" ")) $6 ==> [foo, bar, baz]
上面的样例展现了临时变量($3、$5 和 $6),如果需要的话,它们可以用于后续表达式的计算。
jshell> import java.util.stream.* jshell> $6.stream().filter(s -> s.startsWith("b")).collect(Collectors.toList()) $9 ==> [bar, baz]
在上例中,我们导入了java.util.stream
包,这样的话,在 Collectors 类上进行 tab 键提示的时候,就能得到它的方法列表。
结论
JShell 为 Java 带来了 REPL,在经典的 LISP 机器上,这是一项非常有用的特性。它能够帮助开发人员调试代码片段,避免了完整的编译、运行和调试流程。
查看英文原文: JavaOne 2016 – Audience Gets a Glimpse of the Power of JShell
评论