Метод ненаучного тыка: введение в JShell

Отпраздновав релиз Java 9, теперь вы задумались, как она может улучшить вашу жизнь? Если модули сейчас нужны не всем, то вошедший в «девятку» инструмент JShell пригодится очень многим — а с этим текстом удобнее начинать его использовать.

Что это вообще такое?

Всем нам случалось разбираться с Java способом «посмотрим-ка, что выдаст такой код». Но при этом раздражает необходимость ради пары строк создавать полноценный класс, компилировать его и запускать. JShell создан, чтобы упростить такое «исследовательское программирование». Это REPL (read-eval-print loop): пишешь отдельные выражения, и после каждого тут же видишь результат. Профессионалам становится удобнее, а новички могут не биться с разбега лбом о «public static void main(String[] args)» и осваивать язык с самых простых конструкций.

Казалось бы, если всё так просто, то и текст читать не надо, бери да пиши код. Но у JShell есть и не совсем очевидные возможности (особенно для тех, кто не пользовался ранее другими REPL). Поэтому мы описали многие из них.

Ну и как этим пользоваться?

JShell — консольное приложение, входит в состав JDK 9, запускается командой jshell и дальше ждёт, пока вы введёте в командную строку свои сниппеты (самодостаточные фрагменты кода). И вот что стоит знать, начиная их вводить.

В сниппете можно объявить переменную, а можно даже не объявлять. Если просто написать значение, JShell сам создаст так называемую scratch variable и присвоит ей это значение, позволив обращаться к нему позже. Вот как выглядят оба варианта:

Если написать «2+2», создадут scratch variable типа int и запишут в неё «4», а если «2 + 2.0», то переменная будет double со значением «4.0». В общем, разбалуем всех выводом типов.

А если вас не устраивают названия scratch variables с их знаком доллара, но вы успели разбаловаться и писать типы переменных больше не хотите, есть средство и для вас. Если после ввода значения вместо Enter нажать Shift+Tab V, то JShell напишет тип переменной и заботливо поставит курсор там, где осталось вписать её название. Вот на этом скриншоте после «7+7» был нажат Enter, а после «8+8» — Shift+Tab V:

То, что действие происходит в командной строке, не означает, что каждый сниппет должен быть однострочником. Скажем, если начать писать метод, после нажатия на Enter инструмент осознает, что дело ещё не закончено, и обозначит перенос строки:

Точку с запятой в конце сниппета можно опустить (как на предыдущем скриншоте в вызове метода), JShell поймёт и простит. Но если она не в самом конце (как на предыдущем скриншоте в теле метода), тогда всё-таки надо, тут вам не Котлин.

Ещё одна интересная особенность — forward references. Если вы ссылаетесь на ещё не существующее — скажем, используете в методе ещё не объявленную переменную, как на скриншоте — то вежливо скажут «метод-то создан, но использовать его сможете не раньше, чем объявите эту переменную»:

В JShell есть свой набор команд. Вводятся они так же, как и сниппеты, но начинаются со слэша, так что не спутаешь. Их полный список можно увидеть по команде /?, а здесь разберём часть.

/list показывает все активные сниппеты текущей сессии (те, которые не выдали ошибку и не потеряли актуальность из-за введённого позже). По /list -start можно увидеть содержимое скрипта, который выполняется при запуске JShell (по умолчанию там импортируются ключевые вещи вроде java.util.*, но при желании скрипт запуска можно изменить). А по /list -all — вылезают вообще все сниппеты сессии, вот пример: буква «s» перед номерами у сниппетов из скрипта запуска, а «e» у выдавшего ошибку.

/set отвечает за настройки: например, изменять скрипт запуска надо командой /set start. А /set feedback регулирует разговорчивость JShell (жаль, не вполне как у робота из «Интерстеллара»). По умолчанию стоит режим normal, а если ввести /set feedback verbose, инструмент станет подробно комментировать каждый чих: «я создал scratch variable с названием $8, она типа int, туда я записал 5». Противоположность — режим /set feedback silent: переменную в аналогичной ситуации тоже создадут, но говорить вообще ничего не станут.

Первый вариант должен хорошо подойти новичкам, а второй удобен при копировании в JShell кода откуда-то извне. Вот обе этих крайности на одном скриншоте:

/save позволяет сохранить набор сниппетов в файл, а /open — загрузить из файла и исполнить. То есть тут не история «после закрытия JShell всё превращается в тыкву», можно делать целые мини-проекты — собственно, в Oracle рассчитывают, что одним из вариантов использования будет итеративное прототипирование.

/edit помогает в том случае, когда командной строки всё-таки недостаточно: с помощью этой команды можно открыть во внешнем редакторе или все существующие сниппеты, или один конкретный. А у уже знакомой команды /set есть вариант /set editor, позволяющий заменить дефолтный редактор на любимый.

Три команды помогают повторить сниппет. Можно вызвать сниппет по номеру, под которым он фигурирует в /list — тогда вводите /номер. Если хочется «тот, который был столько-то сниппетов назад» — то /-«столько-то». А если повторить последний, то /!. Ещё может помочь поиск по истории, открывающийся по Ctrl+R. Ну и, конечно, простое нажатие на кнопку «вверх» в командной строке никто не отменял.

И для сниппетов, и для команд работает автодополнение по Tab. Если у того, что вы уже ввели, есть только один вариант дополнения, то JShell сразу дополнит до него. Так что не требуется целиком писать “System.currentTimeMillis()”: уже на “System.cu” альтернатив не остаётся. А если альтернативы есть, JShell покажет их все. Если вы проснулись в холодном поту и поняли, что не помните стандартные методы Object, можете сделать так:

Ещё два приятных нюанса, связанных с автодополнением. Во-первых, если оно видит несколько вариантов, но их первые буквы совпадают, то эти буквы вам сразу допишут. То есть при виде «System.out.p» JShell не только назовёт варианты «print()», «println()» и «printf()», но и сразу дополнит строку до «print». Мелочь, конечно, но ощущение, как будто заботливая бабушка одеяло подтыкает!

А во-вторых, если вы пишете команду (не сниппет), и вариант дополнения остаётся только один, можете вообще обойтись без табуляции и просто не дописывать до конца. Вот как это работает с «/set feedback verbose» (и вот как перестаёт работать, если слишком рано остановиться и ещё будет оставаться неоднозначность):

На этом список возможностей не заканчивается, но не станем превращать введение в доскональное руководство. Если хочется большего, можно открыть User’s Guide на сайте Oracle или посмотреть скринкаст от архитектора JShell Роберта Филда. А мы напоследок напомним обложку выдуманной книги о том, как важен в обучении метод тыка:

Tags from the story
, ,