模块 jdk.jshell

包 jdk.jshell


jdk.jshell
提供用于创建工具的接口,例如 Read-Eval-Print Loop (REPL),它以交互方式评估 Java 编程语言代码的“片段”。其中“片段”是单个表达式、语句或声明。此功能可用于增强 IDE 等工具,也可独立使用。

JShell 是中心类。 JShell 的实例保存评估状态,即当前源代码片段集和它们生成的执行状态。

每个源代码片段都由 Snippet 的子类实例表示。例如,语句由 StatementSnippet 的实例表示,方法声明由 MethodSnippet 的实例表示。当使用包含一个或多个代码片段的输入调用 JShell.eval(String) 时,将创建片段。

代码段编译状态的任何更改都会用 SnippetEvent 报告。片段的状态有三种主要的变化:它可以用 eval 创建,它可以用 JShell.drop(jdk.jshell.Snippet) 从活动源状态中删除,并且它的状态可以由于另一个片段中的状态变化而更新.例如:给定 jsJShell 的实例,执行 js.eval("int x = 5;") 会将变量 x 添加到源状态,并将生成一个事件,描述为 x 创建 VarSnippet 。然后执行 js.eval("int timesx(int val) { return val * x; }") 将向源状态添加一个方法,并将生成一个事件,描述为 timesx 创建 MethodSnippet 。假设 varx 保存由第一次调用 eval 创建的代码片段,执行 js.drop(varx) 将生成两个事件:一个用于将变量代码片段的状态更改为 DROPPED ,另一个用于更新方法代码片段(现在有一个未解析的对 x 的引用)。

当然,对于 API 的任何一般应用,输入都不是固定的字符串,而是来自用户。下面是一个非常简单的示例,说明如何使用 API 来实现 REPL。

 
   import java.io.ByteArrayInputStream;
   import java.io.Console;
   import java.util.List;
   import jdk.jshell.*;
   import jdk.jshell.Snippet.Status;

   class ExampleJShell {
     public static void main(String[] args) {
       Console console = System.console();
       try (JShell js = JShell.create()) {
         do {
           System.out.print("Enter some Java code: ");
           String input = console.readLine();
           if (input == null) {
             break;
           }
           List<SnippetEvent> events = js.eval(input);
           for (SnippetEvent e : events) {
             StringBuilder sb = new StringBuilder();
             if (e.causeSnippet() == null) {
               // We have a snippet creation event
               switch (e.status()) {
                 case VALID:
                   sb.append("Successful ");
                   break;
                 case RECOVERABLE_DEFINED:
                   sb.append("With unresolved references ");
                   break;
                 case RECOVERABLE_NOT_DEFINED:
                   sb.append("Possibly reparable, failed ");
                   break;
                 case REJECTED:
                   sb.append("Failed ");
                   break;
               }
               if (e.previousStatus() == Status.NONEXISTENT) {
                 sb.append("addition");
               } else {
                 sb.append("modification");
               }
               sb.append(" of ");
               sb.append(e.snippet().source());
               System.out.println(sb);
               if (e.value() != null) {
                 System.out.printf("Value is: %s\n", e.value());
               }
               System.out.flush();
             }
           }
         } while (true);
       }
       System.out.println("\nGoodbye");
     }
   }
  
 

要注册状态更改事件,请使用 JShell.onSnippetEvent(java.util.function.Consumer) 。这些事件仅由 evaldrop 生成,这些方法的返回值是该调用生成的事件列表。因此,如上例所示,可以在不注册接收事件的情况下使用事件。

如果你试验这个例子,你会发现如果不能用分号终止一个语句或变量声明将会失败。未完成的条目(例如所需的多行方法)也将在一行之后失败。 SourceCodeAnalysis 中的实用程序提供源边界和完整性分析以解决此类情况。 SourceCodeAnalysis 还提供建议的输入补全,可能用于制表符补全。

自从:
9