Пакет jdk.jshell

Предоставляет интерфейсы для создания инструментов, таких как цикл Read-Eval-Print Loop (REPL), которые интерактивно оценивают "фрагменты" кода языка программирования Java. Где "фрагмент" представляет собой единственное выражение, оператор или объявление. Данная функциональность может использоваться для повышения функциональности инструментов, таких как IDE, или может быть использована как самостоятельный инструмент.

JShell — это центральный класс. Экземпляр JShell хранит состояние оценки, которое включает как текущий набор исходных фрагментов, так и состояние выполнения, которое они произвели.

Каждый исходный фрагмент представлен экземпляром подкласса Snippet. Например, оператор представлен экземпляром StatementSnippet, а объявление метода — экземпляром MethodSnippet. Фрагменты создаются при вызове JShell.eval(String) с вводом, который включает один или несколько фрагментов кода.

Любое изменение статуса компиляции фрагмента сообщается с помощью SnippetEvent. Существует три основных типа изменений состояния фрагмента: он может быть создан с помощью eval, он может быть исключён из активного состояния источника с помощью JShell.drop(jdk.jshell.Snippet), и его состояние может быть обновлено в результате изменения состояния другого фрагмента. Например: учитывая js, экземпляр JShell, выполнение js.eval("int x = 5;") добавит переменную x в состояние источника и сгенерирует событие, описывающее создание VarSnippet для x. Затем выполнение js.eval("int timesx(int val) { return val * x; }") добавит метод в состояние источника и сгенерирует событие, описывающее создание MethodSnippet для timesx. Предположим, что 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). Эти события генерируются только eval и drop, значения возврата этих методов — список событий, сгенерированных этим вызовом. Таким образом, как в примере выше, события могут быть использованы без регистрации на получение событий.

Если вы поэкспериментируете с этим примером, вы увидите, что отказ от завершения оператора или объявления переменной с использованием точки с запятой просто приведёт к ошибке. Незавершенная запись (например, желаемый многострочный метод) также просто завершится ошибкой после одной строки. Утилиты в SourceCodeAnalysis предоставляют анализ границ и полноты источника для решения подобных случаев. SourceCodeAnalysis также предоставляет предлагаемые завершения ввода, что может быть использовано в автозаполнении (tab-completion).

Since:
9
Интерфейс Описание
SourceCodeAnalysis.CompletionInfo

Результат analyzeCompletion(String input).

SourceCodeAnalysis.Documentation

Документация для кандидата на продолжение ввода пользователя.

SourceCodeAnalysis.SnippetWrapper

Оборачивание фрагмента Java-исходного кода в допустимый исходный код Java верхнего уровня.

SourceCodeAnalysis.Suggestion

Кандидат на продолжение ввода пользователя.

Класс Описание
DeclarationSnippet

Группа всех фрагментов объявления: объявления переменных (VarSnippet), объявления методов (MethodSnippet) и объявления типов (TypeDeclSnippet).

Diag

Диагностическая информация для фрагмента.

ErroneousSnippet

Фрагмент кода, который не является допустимым кодом языка программирования Java.

ExpressionSnippet

Фрагмент для присваивания или выражения значения переменной.

ImportSnippet

Фрагмент для объявления импорта.

JShell

Двигатель состояния оценки JShell.

JShell.Builder

Библиотека для создания экземпляров JShell.

MethodSnippet

Фрагмент для определения метода.

PersistentSnippet

Группа фрагментов, которые сохраняются и влияют на будущий код.

Snippet

Фрагмент представляет собой фрагмент исходного кода Java, переданный JShell.eval(java.lang.String).

SnippetEvent

Описание изменения фрагмента.

SourceCodeAnalysis

Предоставляет утилиты анализа для входных данных исходного кода.

SourceCodeAnalysis.QualifiedNames

Список возможных квалифицированных имён.

StatementSnippet

Фрагмент для оператора.

TypeDeclSnippet

Фрагмент для определения типа (класса, интерфейса, перечисления или аннотационного интерфейса).

VarSnippet

Фрагмент для объявления переменной.

Перечисление Описание
Snippet.Kind

Описание общего типа фрагмента.

Snippet.Status

Описание текущего состояния фрагмента.

Snippet.SubKind

Детальный вид фрагмента.

SourceCodeAnalysis.Completeness

Описание полноты входных данных.

Исключение Описание
EvalException

Оборачивает исключение, брошенное в клиентском приложении.

JShellException

Базовый класс для исключений, сгенерированных JShell.

UnresolvedReferenceException

Исключение, сообщённое при попытке выполнить фрагмент RECOVERABLE_DEFINED.

© 1993, 2020, Oracle and/or its affiliates. All rights reserved.
Documentation extracted from Debian's OpenJDK Development Kit package.
Licensed under the GNU General Public License, version 2, with the Classpath Exception.
Various third party code in OpenJDK is licensed under different licenses (see Debian package).
Java and OpenJDK are trademarks or registered trademarks of Oracle and/or its affiliates.
https://docs.oracle.com/en/java/javase/11/docs/api/jdk.jshell/jdk/jshell/package-summary.html

Spec-Zone .ru
спецификации, руководства, описания, API