jshellをつかってみました。
サイトに載っているサンプル実行するなどでは十分使えました。わざわざIDEでプロジェクト作ってー、main作ってーってやらなくていいので楽でした。
ただクラスを何個か新規で定義するほどの規模になったら、ちゃんと開発環境構築して、デバックできるほうがいいのかな、と思いました。
■ JShellの概要
Java Shellツール(JShell)は、Javaプログラミング言語を学習したり、およびJavaコードのプロトタイプを作成するための対話型ツールです。JShellはRead-Evaluate-Print Loop (REPL)であり、入力時に宣言、文および式を評価し、ただちに結果を表示します。ツールは、コマンドラインから実行されます。
■JShellを使用する理由
JShellを使用すると、一度に1つずつプログラム要素を入力したり、ただちに結果を確認したり、必要に応じて調整できます。
Javaプログラムの開発には、通常、次のプロセスが含まれます。
・完全なプログラムを作成します。
・これをコンパイルして、エラーを修正します。
・プログラムを実行します。
・問題がある場所を調べます。
・これを編集します。
のプロセスを繰り返します。
JShellを使用すると、プログラム開発時にコードを試したり、オプションを容易に調べることができます。JShellセッションで、個々の文をテストしたり、様々なバリエーションのメソッドを試したり、よく知らないAPIを試すことができます。JShellはIDEに取ってかわるものではありません。プログラムの開発時に、コードをJShellに貼り付けてこれを試してから、動作するコードをJShellからプログラム・エディタまたはIDEに貼り付けます。
環境構築
java JDKのインストール
さすがにJDKはインストールしないとだめです。
ダウンロード
ここから、とりえず現時点で最新の20をダウンロードして、インストール。
使ってみよう
起動・停止
起動
コマンドプロンプトかpownershellで「jshell」と入力。
jshell
起動するとこんな感じ。
C:\xxxxx>jshell
| JShellへようこそ -- バージョン18
| 概要については、次を入力してください: /help intro
jshell>
停止
「/exit」と入力。
jshell> /exit
| 終了します
四則演算
jshell> 10 + 10
$1 ==> 20
jshell> (10 + 10) * 100
$2 ==> 2000
数値型について
jshell> 22 / 7
$4 ==> 3
基本、整数っぽい。
浮動小数点型にしたい時は、どちらかを浮動小数点型にする。
jshell> 22 / 7.0
$5 ==> 3.142857142857143
文字列演算
jshell> "ABC" + "DEF"
$3 ==> "ABCDEF"
比較演算
jshell> 1 == 1
$6 ==> true
jshell> 1 == 2 || 3 == 3
$1 ==> true
jshell> 1 == 2 || 3 == 3 && (4 == 5)
$2 ==> false
※文字列はString クラスの equals メソッドを使用ですよ。
メソッド
メソッド一覧
メソッド名のスペルわすれた!の時のために。
あとえば、文字列のメソッド一覧を表示したい時は
「"文字列".」と入力して、[TAB]キー。
※ドットの入力わすれないように。
jshell> "test".
charAt( chars() codePointAt( codePointBefore( codePointCount(
codePoints() compareTo( compareToIgnoreCase( concat( contains(
contentEquals( describeConstable() endsWith( equals( equalsIgnoreCase(
formatted( getBytes( getChars( getClass() hashCode()
indent( indexOf( intern() isBlank() isEmpty()
lastIndexOf( length() lines() matches( notify()
notifyAll() offsetByCodePoints( regionMatches( repeat( replace(
replaceAll( replaceFirst( resolveConstantDesc( split( startsWith(
strip() stripIndent() stripLeading() stripTrailing() subSequence(
substring( toCharArray() toLowerCase( toString() toUpperCase(
transform( translateEscapes() trim() wait(
jshell> "test".
メソッド
jshell> "test".toUpperCase()
$3 ==> "TEST"
jshell> Math.round(4.5)
$1 ==> 5
チェーンもOK。
jshell> "test".toUpperCase().charAt(2)
$2 ==> 'S'
変数も使えるぞ!
var [変数名] = [値]
jshell> var str1 = "ABC"
str1 ==> "ABC"
jshell> var str2 = "DEF"
str2 ==> "DEF"
jshell> str1 + str2
$5 ==> "ABCDEF"
型変換は不可能。
jshell> /var str1
| String str1 = "abc"
jshell> str1 = 1
| エラー:
| 不適合な型: intをjava.lang.Stringに変換できません:
| str1 = 1
| ^
型指定して変数宣言
jshell> String str3 = "XYZ"
str3 ==> "XYZ"
jshell> /var str3
| String str3 = "XYZ"
配列も宣言できる。
jshell> int[] array = {1, 2, 3}
array ==> int[3] { 1, 2, 3 }
jshell> array[0]
$13 ==> 1
宣言と代入のステートメントをわけることもOK。
jshell> String str4
str4 ==> null
jshell> str4 = "QWE"
str4 ==> "QWE"
メソッドも宣言できるぞ!
int addtion(int a, int b) {
return a + b;
}
jshell> int addtion(int a, int b) {
...> return a + b;
...> }
| 次を作成しました: メソッド addtion(int,int)
jshell> addtion(1,3)
$21 ==> 4
エラーが有る時は、メソッドブロック最後の「}」入力した時に、エラー表示される。
jshell> int addtion(int a, int b) {
...> return a + b
...> }
| エラー:
| ';'がありません
| return a + b
| ^
エラーになった場合は、「上矢印キー」を入力すると、メソッドの編集モードになるので、
エラー箇所を修正する。
メソッドはまずサクラエディタなのでコーディングして、それをコピペしたほうが楽です。
※インデントでタブ文字は禁止です。タブがあるとタブコマンドと認識されてエラーになる。インデントは半角スペースで。もちろんインデント無しでもOK。
サクラエディタで
int addtion(int a, int b) {
return a + b;
}
とコーディングして、jshellにコピペ、エンター。
jshell> int addtion(int a, int b) {
...> return a + b;
...> }
| 次を変更しました: メソッド addtion(int,int)
ステートメントをエディタで編集
既存のメソッドを編集する時は、上記のように外部エディタからコピペでもOK。
もしくは、編集したいステートメント番号を調べて「/edit [ID]」でもデフォルトエディタが起動される。
jshell> /list
1 : 1 + 2
2 : int addtion(int a, int b) {
return a + b;
}
/edit 2
エディタが起動される。
前方参照
JShellでは、未定義のメソッド、変数またはクラスを参照するメソッド定義が使用可能。
ワーニングにはなるが、未宣言の「RATE_SALES_TAX」を使うことが出来る。
// RATE_SALES_TAX未宣言状態で参照メソッド作成
jshell> int getSalesTax(int price) {
...> return (int)Math.floor(price * RATE_SALES_TAX);
...> }
| 次を作成しました: メソッド getSalesTax(int)。しかし、 variable RATE_SALES_TAXが宣言されるまで、起動できません
jshell> final double RATE_SALES_TAX = 0.1
RATE_SALES_TAX ==> 0.1
jshell> getSalesTax(100)
$8 ==> 10
クラスも定義できるぞ!
public class Person {
private String name;
public Person(final String name) {
this.name = name;
}
public String getName() {
return name;
}
}
jshell> public class Person {
...> private String name;
...> public Person(final String name) {
...> this.name = name;
...> }
...> public String getName() {
...> return name;
...> }
...> }
| 次を作成しました: クラス Person
jshell> Person aoki = new Person("AOKI");
aoki ==> Person@736e9adb
jshell> aoki.getName()
$11 ==> "AOKI"
外部モジュールもつかえるぞ!
必要なこと。
- jshell でクラスパス指定
- 使前にクラスをimport
ためしに、commons-lang3-3.12.0.jarのStringUtilを使ってみた。
クラスパス指定してjshell起動
外部モジュールのjarを指定。
jshell --class-path ./lib/commons-lang3-3.12.0.jar
起動した後であれば、「/env」コマンドでもOK。
jshell> /env --class-path ./lib/commons-lang3-3.12.0.jar
| 新しいオプションの設定と状態の復元。
インポート
jshell> import org.apache.commons.lang3.StringUtils;
使ってみる
jshell> StringUtils.isEmpty(null);
$2 ==> true
使えた。
複数行のステートメント
1ステートメントが長すぎて1行だと見づらい場合は、「(」を開いたままで改行するか、行の末尾を「.」で終わると複数入力可能です。
「(」を開いたままで改行
doSSometiong(A, B, C
D, E, F);
行の末尾を「.」で終わる
int sum = array.stream().
filter(element -> element.getParam1().equals("A")).
mapToInt(element -> element.getParam2()).
sum();
「.」先頭は別ステートメント扱いになりエラーになる。
サイトでのサンプルでメソッドチェーンを複数行で記載している場合、「.
」を先頭に記述しているのがほとんど。なのでコピペの際は気をつけること。
// エラーになる。
int sum = array.stream().
filter(element -> element.getParam1().equals("A"))
.mapToInt(element -> element.getParam2())
.sum();
コピペしたらエラーになった。
jshell> int sum = array.stream().
...> filter(element -> element.getParam1().equals("A"))
| エラー:
| 不適合な型: java.util.stream.Stream<MyClass>をintに変換できません:
| int sum = array.stream().
| ^--------------...
jshell> .mapToInt(element -> element.getParam2())
| エラー:
| 式の開始が不正です
| .mapToInt(element -> element.getParam2())
| ^
jshell> .sum();
編集モードを抜ける
編集モードの時、プロンプトは「...>」になっている。コピペ失敗なので編集モードを抜けたい時は、「Ctl+C」で抜ける。抜けた場合、作業中の変更は破棄されるので注意。
jshell> inat addtion(int a, int b) {
...>
「Ctl+C」
jshell> inat addtion(int a, int b) {
...>
jshell> <= 抜けた
jshellコマンド
宣言済みの変数の型と値を確認
特定のもの
/var [変数名]
jshell> /var str1
| String str1 = "abc"
宣言済みの変数全て
/vars
jshell> /vars
| long $1 = 5
| char $2 = 'S'
| String str2 = "DEF"
| String $5 = "ABCDEF"
| String str1 = "abc"
| String $9 = "SSSSDEF"
| String $11 = "abcDEF"
| int[] array = int[3] { 1, 2, 3 }
| int $13 = 1
| String str3 = "XYZ"
| String str4 = "QWE"
宣言済みのメソッドを確認
特定のもの
/method [メソッド名]
jshell> /method addtion
| int addtion(int,int)
宣言済みのメソッド全て
/methods
jshell> /methods
| void methodA()
| void methodB()
| int addtion(int,int)
削除
変数削除
/drop [変数名]
jshell> /drop str3
| 次を削除しました: 変数 str3
メソッド削除
/drop [メソッド名]
jshell> /drop methodA
| 次を削除しました: メソッド methodA()
import確認
/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.*
入力したステートメント一覧
/list
jshell> /list
1 : String str1 = "AAAA";
2 : String str2 = "BBBB";
3 : int addtion(int a, int b) {
return a + b;
}
4 : int i1 = 1;
エラーになったステートメントとかimportとか全部の場合はallオプションを付ける。
/list -all
jshell> /list -all
s1 : import java.io.*;
s2 : import java.math.*;
s3 : import java.net.*;
s4 : import java.nio.file.*;
s5 : import java.util.*;
s6 : import java.util.concurrent.*;
s7 : import java.util.function.*;
s8 : import java.util.prefs.*;
s9 : import java.util.regex.*;
s10 : import java.util.stream.*;
1 : String str1 = "AAAA";
2 : String str2 = "BBBB";
3 : int addtion(int a, int b) {
return a + b;
}
4 : int i1 = 1;
e1 : int i2 = "2"; <----★これエラーになったやつ
リセット
入力したステートメントを全てクリア。起動時に戻る。
/reset
リセットした直後
jshell> /list -all
s1 : import java.io.*;
s2 : import java.math.*;
s3 : import java.net.*;
s4 : import java.nio.file.*;
s5 : import java.util.*;
s6 : import java.util.concurrent.*;
s7 : import java.util.function.*;
s8 : import java.util.prefs.*;
s9 : import java.util.regex.*;
s10 : import java.util.stream.*;
コマンド一覧
タブ補完
コマンドやメソッド名は最後まで入力しなくても、何文字か入力してタブキーを押下すると補完してくれる。複数候補がある場合は、候補を表示してくれる。
jshell> /l[タブキー]
jshell> /list
候補が複数ある場合
jshell> me
methodA() methosB()
jshell> metho
おまけ
jdbc疎通確認してみた
AWS Aurora Postgresqlへ接続。
ドライバークラスパス設定
jshell --class-path ./lib/postgresql-42.4.0.jar
疎通確認
正常に接続できた時。
jshell> var conn = java.sql.DriverManager.getConnection("jdbc:postgresql://sp-work.cluster-xxxxxxxxxxx.ap-northeast-1.r
ds.amazonaws.com:5432/postgres", "user", "xxxxxx");
conn ==> org.postgresql.jdbc.PgConnection@74e52303
hostが見つからなくて失敗した時。
jshell> var conn = java.sql.DriverManager.getConnection("jdbc:postgresql://sp-work.hoge.com:5432/postgres", "postgres",
"xxxxxx");
| 例外org.postgresql.util.PSQLException: 接続試行は失敗しました。
| at ConnectionFactoryImpl.openConnectionImpl (ConnectionFactoryImpl.java:331)
| at ConnectionFactory.openConnection (ConnectionFactory.java:49)
| at PgConnection.<init> (PgConnection.java:223)
| at Driver.makeConnection (Driver.java:402)
| at Driver.connect (Driver.java:261)
| at DriverManager.getConnection (DriverManager.java:683)
| at DriverManager.getConnection (DriverManager.java:230)
| at do_it$Aux (#14:1)
| at (#14:1)
| 原因: java.net.UnknownHostException: sp-work.hoge.com
| at NioSocketImpl.connect (NioSocketImpl.java:564)
| at SocksSocketImpl.connect (SocksSocketImpl.java:327)
| at Socket.connect (Socket.java:633)
| at PGStream.createSocket (PGStream.java:241)
| at PGStream.<init> (PGStream.java:98)
| at ConnectionFactoryImpl.tryConnect (ConnectionFactoryImpl.java:109)
| at ConnectionFactoryImpl.openConnectionImpl (ConnectionFactoryImpl.java:235)
| ...
閉じる。
jshell> conn.close()
jshell>