Java

Java SE 9 の予習 その5

Java

Java SE 9 の予習 その5です。

今回は地味にアップデートを積み重ねている ProcessAPI をゴニョゴニョしてみました。

JDK 9 でどのようアップデートされたか試してみます。

まずプロセス ID が直感的に取得できるようになってます。

今までは次のような解りにくいコードを書かなければいけませんでした。

それが JDK 9 では ProcessHandle インターフェイスが用意され便利に使えるファクトリメソッドあるので次のように優しいコードで書くことができるようになりました。

実行中のプロセスIDとコマンドを取得するにはつぎのようなシンプルなコードになります。

static Stream<ProcessHandle> allProcesses​() メソッドで現在のプロセスから見えるすべてのプロセスのスナップショットを返します。

ただし、これは非同期で処理されるため注意が必要です。

スナップショットを作成したあとにプロセスの開始、終了などが問題になる場合も考えられます。

このコードの実行結果は次のようになります。(長いので途中省略してます。)

それでは JDK 9 から追加された public static interface ProcessHandle.Info インターフェイスについて調べてみましょう。

プロセスに関する情報のスナップショット。

プロセスの属性はオペレーティングシステムによって異なり、すべての実装で利用できるわけではありません。

プロセスに関する情報は、要求を行うプロセスのオペレーティングシステム権限によって制限されます。

もし値が利用可能であるなら、戻り型は明示的なテストとアクションを許す Optional<T> です。

ProcessHandle.Info info​() メソッドはプロセスに関する情報のスナップショットを返します。

ProcessHandle.Infoインスタンスには、利用可能なプロセスに関する情報を返すアクセサメソッドがあります。

Optional<String[]> arguments​() メソッドはプロセスの引数の文字列の配列を返します。(プロセスの引数の Optional<String[]>)

ただし、いくつかのプラットフォームでは、ネイティブアプリケーションは起動後に引数配列を自由に変更でき、このメソッドは変更された値のみを表示することがあります。

Optional<Instant> startInstant​() メソッドはプロセスの開始時刻を返します。(プロセスの開始時刻の Optional<Instant> です。)

Optional<Duration> totalCpuDuration​() メソッドはプロセスの累積合計 cputime を返します。(累積合計 cputime の Optional<Duration>)

Optional<String> user​() メソッドはプロセスのユーザーを返します。(プロセスのユーザーについての Optional<String>)

Optional<String> command​() メソッドはプロセスの実行可能パス名を返しています。(プロセスの実行可能パス名の Optional<String>)

Optional<String> commandLine​() メソッドはプロセスのコマンドラインを返します。(プロセスのコマンドラインの Optional<String>)

command() メソッドと arguments() メソッドが Optinal.empty でない Optional<String> を返す場合、これは単に空白で区切られた2つの関数の値を連結する便利なメソッドです。

それ以外の場合は、コマンドラインのベストエフォート、プラットフォーム依存の表現を返します。

ただし、システムの制限により、返された実行可能パス名と引数が一部のプラットフォームで切り捨てられることがあります。

実行可能なパス名には、完全なパス情報がない実行可能ファイルの名前のみが含まれている場合があります。

空白が異なる引数を区切っているのか、単一の引数の一部なのかは決まりません。

以上、ProcessHandle.Info の便利なアクセサメソッドを調べてみました。

今回のプログラムでは全て試してないのですが Windows だと情報取得できるけど Linux (Ubunts) だと取れないとかありました。

でも JDK 9 での ProcessAPI はこれだけでも開発者に優しくなったと思います。

それではいろいろゴニョゴニョしていきましょう。

次に任意のプロセス情報の取得を試してみます。

static Optional<ProcessHandle> of​(long pid) メソッドで Optional<ProcessHandle> を返します。

引数は当然プロセス ID です。

プロセスが存在しない場合は、 empty を返します。

このコードの実行結果は次のようになります。

次はカレントプロセスの情報を取得してみましょう。

static ProcessHandle current​() メソッドで現在のプロセスの ProcessHandle を返します。

API ドキュメントに次のような注意書きがあります。

ProcessHandle を使用して現在のプロセスを破棄することはできません。

代わりに System.exit を使用してください。

実行結果は次のようになります。

それでは子プロセス情報の取得を試してみます。

エディタを二つ起動させてみました。

Stream<ProcessHandle> children​() メソッドでカレントプロセスの直接の子のスナップショットを返します。

プロセスの直接のチルドレンであるプロセスの ProcessHandles の連続的なストリームを返すと言うことです。

注意すべきはプロセスが作られて、そして非同期に終わること。 プロセスが生きているという保証がありません。

このコードの実行結果は次のようになります。

次はプロセスの終了処理を試してみます。

先ほど起動したエディタを終了させてみましょう。

プロセスの終了処理にpublic abstract void destroy​() メソッドと public Process destroyForcibly​() メソッドをそれぞれ使ってみました。

public abstract void destroy​() メソッドはプロセスを終了させます。

このProcessオブジェクトが表す処理が正常に終了したか否かは実装依存です。

強制的なプロセス破棄がプロセスの即時終了と定義されるのに対して、正常終了はプロセスが正常に終了することを可能にします。

プロセスが生存していない場合、何も実行されません。

プロセスが終了すると、onExit() メソッドの CompletableFuture が完了します。

56行目の geditProcess1.waitFor(); の終了待ちがないと public boolean isAlive​() メソッドが true を返す場合があります。

JDK 9 からは public CompletableFuture<Process> onExit​() メソッドを使うのが良いのかもしれません。

シンプルに public abstract int waitFor​() メソッドを使って対応してしまいました。(^_^;

public Process destroyForcibly​() メソッドもプロセスを終了させます。

ただし、このプロセスオブジェクトによって表されたプロセスは強制的に終了させられます。

ProcessBuilder.start()およびRuntime.exec(java.lang.String)によって返されたProcessオブジェクトでこのメソッドを呼び出すと、強制的にプロセスが終了します。

プロセスが終了すると、onExit()のCompletableFutureが完了します。

プロセスはすぐに終了しないことがあります。つまり、isAlive() メソッドは destroyForcibly() メソッドが呼び出された後、短時間の間 true を返すことがあります。

こちらも waitFor​() メソッドを使って対応しました。

このコードの実行結果は次のようになります。

ここまで試してみて JDK 9 での ProcessAPI は OS に依存しないコードで美しく処理が可能となったようです。

次は public static List<Process> startPipeline(List<ProcessBuilder> builders) メソッドを使ったパイプライン処理をためしてみます。

先ず、ProcessBuilder クラスがどんなものか復習しておきましょう。

J2SE 5.0 (Tiger) から存在するクラスです。

このクラスは、オペレーティングシステムのプロセスを作成するために使用されます。

各 ProcessBuilder インスタンスは、プロセス属性のコレクションを管理します。

start() メソッドは、これらの属性を持つ新しい Process インスタンスを作成します。

同じインスタンスからstart() メソッドを繰り返し呼び出すと、同一または関連する属性を持つ新しいサブプロセスを作成できます。

public static List<Process> startPipeline(List<ProcessBuilder> builders) メソッドを呼び出して、各プロセスの出力を次のプロセスに直接送り新しいプロセスのパイプラインを作成することができます。

各プロセスにはそれぞれのProcessBuilderの属性があります。

各プロセスビルダは、次のプロセス属性を管理します。

  • コマンド、呼び出される外部プログラムファイルを示す文字列のリストとその引数(存在する場合)。
    有効なオペレーティング・システム・コマンドを表す文字列リストは、システムによって異なります。
    たとえば、各概念的な引数はこのリストの要素であるのが普通ですが、プログラムがコマンドライン文字列をトークン化することを期待されるオペレーティングシステムがあります。
    このようなシステムでは、Java実装では厳密に2つの要素を含む必要があります。
  • 環境変数は、変数から値へのシステム依存のマッピングです。
    初期値は、現在のプロセスの環境のコピーです。
  • 作業ディレクトリ。 デフォルト値は、現在のプロセスの現在の作業ディレクトリです。
    通常、システムプロパティ user.dir で指定されたディレクトリです。
  • 標準入力のソース。 デフォルトでは、サブプロセスはパイプからの入力を読み取ります。
    Java コードは、Process.getOutputStream() によって返される出力ストリームを介してこのパイプにアクセスできます。
    ただし、標準入力は redirectInput を使用して別のソースにリダイレクトされます。
    この場合、Process.getOutputStream() は null 出力ストリームを返します。
    • 書き込みメソッドは常に IOException をスローします。
    • close() メソッドは何もしない。
  • 標準出力と標準エラーの出力先です。 デフォルトでは、サブプロセスは標準出力と標準エラーをパイプに書き込みます。
    Javaコードは、Process.getOutputStream() メソッドおよびProcess.getErrorStream() メソッドによって返された入力ストリームを介してこれらのパイプにアクセスできます。
    ただし、標準出力と標準エラーは、redirectOutput と redirectError を使用して他の宛先にリダイレクトされます。
    この場合、Process.getInputStream() メソッドまたは Process.getErrorStream() メソッドは null 入力ストリームを返します。
    • 読み込みメソッドは常に-1を返します
    • 使用可能なメソッドは常に0を返します。
    • close() メソッドは何もしない。
  • redirectErrorStream プロパティ。最初は、このプロパティは false です。
    つまり、サブプロセスの標準出力とエラー出力は、2つの別々のストリームに送信され、Process.getInputStream() メソッドとProcess.getErrorStream() メソッドを使用してアクセスできます。
    値が true に設定されている場合は、次のようになります。
    • 標準エラーは標準出力とマージされ、常に同じ宛先に送信されます。
      (これにより、エラーメッセージを対応する出力と簡単に関連付けることができます)
    • 標準エラーと標準出力の共通の宛先は、redirectOutput を使用してリダイレクトできます。
    • サブプロセスの作成時に redirectError() メソッドで設定されたリダイレクトは無視されます。
    • Process.getErrorStream() メソッドから返されるストリームは常に null 入力ストリームになります

プロセスビルダの属性を変更すると、そのオブジェクトの start() メソッドによってその後に開始されたプロセスに影響しますが、以前に開始したプロセスや Java プロセス自体には影響しません。

ほとんどのエラーチェックはstart() メソッドによって実行されます。 start() メソッドが失敗するようにオブジェクトの状態を変更することは可能です。

たとえば、コマンド属性を空のリストに設定しても、start() メソッドが呼び出されない限り例外はスローされません。

このクラスは同期されていないことに注意してください。

複数のスレッドが同時にProcessBuilderインスタンスにアクセスし、少なくとも1つのスレッドが属性の1つを構造的に変更する場合は、外部と同期する必要があります。

ProcessBuilder クラスの API ドキュメントをザックリ調べてみました。

それでは public static List<Process> startPipeline​(List<ProcessBuilder> builders) メソッドについて API ドキュメントもザックリ読んでみます。

各ProcessBuilderのプロセスを開始し、標準出力ストリームと標準入力ストリームによってリンクされたプロセスのパイプラインを作成します。

各ProcessBuilderの属性は、各プロセスの開始時に標準出力が次のプロセスの標準入力に導かれることを除いて、それぞれのプロセスを開始するために使用されます。

最初のプロセスの標準入力と最後のプロセスの標準出力のリダイレクトは、それぞれのProcessBuilderのリダイレクト設定を使用して初期化されます。

他のすべてのProcessBuilderリダイレクトはRedirect.PIPEでなければなりません。

中間プロセス間のすべての入出力ストリームにはアクセスできません。

最初のプロセスを除くすべてのプロセスの標準入力は null 出力ストリームです。

最後のプロセスを除くすべてのプロセスの標準出力は null 入力ストリームです。

各 ProcessBuilder のredirectErrorStream は、それぞれのプロセスに適用されます。 true に設定すると、エラーストリームは標準出力と同じストリームに書き込まれます。

いずれかのプロセス起動で例外がスローされると、すべてのプロセスが強制的に破棄されます。

public static List<Process> startPipeline​(List<ProcessBuilder> builders) メソッドは、start() メソッドと同じように各 ProcessBuilder で同じチェックを実行します。

新しいプロセスは、command() メソッドによって与えられたコマンドと引数を、directory() メソッドによって与えられた作業ディレクトリ内で environment() メソッドによって与えられたプロセス環境で呼び出します。

このメソッドは、コマンドが有効なオペレーティングシステムコマンドであることをチェックします。

有効なコマンドはシステムによって異なりますが、コマンドは空でない文字列のリストでなければなりません。

一部のオペレーティングシステムでプロセスを開始するには、最小限のシステム依存環境変数セットが必要な場合があります。

その結果、サブプロセスは ProcessBuilder の environment() メソッド内の環境変数設定を超えて追加の環境変数設定を継承することがあります。

セキュリティマネージャが存在する場合、このオブジェクトのコマンド配列の最初のコンポーネントを引数として呼び出された public void checkExec​(String cmd) メソッドが呼び出されます。

これにより、SecurityException がスローされることがあります。

オペレーティングシステムのプロセスを開始することは、システムによって大きく異なります。 間違っていることがある多くのものの中には次のものがあります。

  • オペレーティングシステムのプログラムファイルが見つかりませんでした。
  • プログラムファイルへのアクセスが拒否されました。
  • 作業ディレクトリが存在しません。
  • コマンド引数に無効な文字(NULなど)があります

そのような場合、例外がスローされます。 例外の正確な性質はシステムに依存しますが、常にIOExceptionのサブクラスになります。

オペレーティングシステムがプロセスの作成をサポートしていない場合、UnsupportedOperationExceptionがスローされます。

このプロセスビルダを後で変更しても、返されるプロセスには影響しません。

このメソッドの引数は List<ProcessBuilder> で返り値は List<Process> です。対応する ProcessBuilder から開始されます。

これってコマンドをつなぐパイプを可能にしているだけですよね。

では、cat -n /home/yucchi/valhalla/README | head -n 34 | tail -n 11| cowsay -n -f ghostbusters を実行するコードを組んで確認してみましょう。

ちなみに Ubuntu の端末で実行すると下図のようになります。

3

プログラムのコードは下記のように組んでみました。

これを NetBeans IDE Dev 版 で実行すると下図のようになります。

0

見事に再現されています。

えっ? cowsay -n -f ghostbusters コマンドでエラーがでるって?

これは標準ではいってないので cowsay でググってインストールしてくださいね!

ちなみに 89行目からの処理は 91 行目にある public CompletableFuture<Process> onExit​() メソッドで返されるプロセスのための新しい CompletableFuture <Process> を利用してます。

public CompletableFuture<Process> onExit​() メソッドについてザックリ調べておきましょう。

プロセスの終了のためのCompletableFuture <Process> を返します。

CompletableFuture は、プロセス終了時に同期または非同期に実行される可能性のある依存する関数またはアクションをトリガーする機能を提供します。

プロセスが終了すると、CompletableFuture はプロセスの終了ステータスに関係なく完了します。

onExit() メソッドを呼び出すと、get() メソッドはプロセスが終了するのを待ち、プロセスを返します。

Future は、プロセスが完了したかどうかをチェックしたり、プロセスが終了するのを待つために使用できます。

CompletableFutureをキャンセルしても、プロセスには影響しません。

ProcessBuilder.start() メソッドから返されたプロセスは、プロセスの終了を待つための効率的なメカニズムを提供するために、デフォルトの実装をオーバーライドします。

onExit() メソッドを使用すると、追加の同時実行性とプロセス結果への便利なアクセスの両方を可能にする waitFor() メソッドの代替手段となります。

ラムダ式を使用して、プロセス実行の結果を評価することができます。

値が使用される前に他の処理が行われる場合、onExit() メソッドは現在のスレッドを解放し、値が必要な場合にのみブロックするのに便利なメカニズムです。

たとえば、2つのファイルを比較するプロセスを起動し、それらが同一であればブール値を取得します。

このプロセスは、ComputableFuture が完了して依存アクションが呼び出される前に、isAlive() メソッドで終了したことが観察されることがあります。

実装要件:
この実装は、正常に戻るまで別のスレッドでwaitFor()を繰り返し実行します。

waitFor() メソッドの実行が中断された場合、スレッドの割り込みステータスは保持されます。

waitFor() メソッドが正常に終了すると、CompletableFuture はプロセスの終了ステータスに関係なく完了します。

多数のプロセスが並行して待機している場合、この実装はスレッドスタックのための多くのメモリを消費する可能性があります。

外部実装はこのメソッドをオーバーライドし、より効率的な実装を提供する必要があります。

たとえば、基になるプロセスに委任するには、次のようにします。

以上 API ドキュメントをザックリ読んでみました。

これはいろいろな処理を順序立てて外部プログラムを利用する場合に有効かもしれませんね。(^_^)

このプログラムではただ単に使ってみただけで有効利用はなにもしていません。(^_^;

いろいろゴニョゴニョやってみたけど JDK 9 での ProcessAPI のアップデートは開発者に優しくなりました。

外部プログラムを利用する開発者にとって JDK 9 のリリースは待ち遠しいことでしょう。

最後にプログラム全体のコードを載せておきます。

お終い!

Java SE 9 の予習

Java SE 9 の予習 その2

Java SE 9 の予習 その3

Java SE 9 の予習 その4

Hatena タグ:

Java SE 9 の予習 その4

Java NetBeans

Java SE 9 の予習 その4です。

前回のエントリーの続きでおそらく今回も必要とされない無駄なお遊びとなります。

今回は JShell API を利用してアプリケーション内でスニペットの評価や実行を試してみます。

なお、今回のエントリーには 「Java SE 9のProject Kulla、JShellの動作とJShell API (3/4)(JShell API)」の記事を参考にさせていただきました。

ほとんどプログラムは丸写し状態になっていますので元記事をまず読んで理解してこのお遊びプログラムを堪能していただければ幸いです。

下記プログラムは普通に19行目のコンストラクタ内で JShell.create() メソッドによりオブジェクトを生成します。

1

スニペットの評価実行は29行目の eval(String snipetSource) メソッドでおこなわれます。(折り畳んでいるので隠れてます。)

( 最後にいろいろゴニョゴニョ遊んだコードを載せますので行番号はずれてしまいますが参考にしてくださいませ。)

List<SnippetEvent> eval(String snipetSource) メソッドで SnippetEvent オブジェクトを取得します。

JavaDoc では 戻り値:この評価によって直接的または間接的に発生したイベントのリスト となっています。

つまり、ステータスや値です。

種類は、jdk.​jshell.​Snippet クラスの public Kind kind() メソッドで取得します。

戻り値である jdk.jshell.Snippet.Kind は jdk.​jshell.​Snippet のサブクラスを示します。

jdk.jshell.Snippet.Kind は jdk.​jshell.​Snippet クラスの public static enum Kind extends Enum<Kind> となっています。

つまり種類は jdk.​jshell.​Snippet クラスのイミュータブルプロパティです。

jdk.​jshell.​Snippetクラスには 種類を補足するための  public SubKind subKind() メソッドも用意されています。

これは jdk.​jshell.​Snippet クラスの  public static enum SubKind extends Enum<SubKind> を返します。

これはユーザーへのフィードバックに役立ちます。

これは種類の詳細な情報を取得するのに利用されます。

ステータスの取得には jdk.​jshell.​SnippetEvent クラスの public Status status() メソッドを使用します。

戻り値は jdk.​jshell.​Snippet クラスの public static enum Status extends Enum<Status> です。

これは JShell ステート内の動的プロパティです。

したがって JShell クエリで取得されます。

ステータスには次の7つの状態があります。

DROPPED:スニペットは、JShell.drop(Snippet)への明示的な呼び出しのために非アクティブです。

NONEXISTENT:スニペットはまだ存在しないため、非アクティブです。

OVERWRITTEN : 新しいスニペットに置き換えられているため、このスニペットは無効です。

RECOVERABLE_DEFINED:スニペットは、(現在のJShell状態のコンテキストで)回復可能な未解決の参照やその他の問題が本体内にある可能性のある宣言スニペットです。

RECOVERABLE_NOT_DEFINED:スニペットは、(現在のJShell状態のコンテキストで)回復可能な未解決の参照やその他の問題がある可能性のある宣言スニペットです。

REJECTED:スニペットは、初期評価時にコンパイルに失敗し、JShell状態のさらなる変更で有効になることができないため、非アクティブです。

VALID:スニペットは有効なスニペット(現在のJShell状態のコンテキスト内)です。

このプログラムではステータスが VALID でなければ jdk.​jshell.​JShell クラスの public Stream<Diag> diagnostics(Snippet snippet) メソッドでスニペットの最新評価の診断を取得します。

そして jdk.​jshell.​Diag クラスの public abstract String getMessage(Locale locale) メソッドで指定されたロケールのローカライズされたメッセージを返します。

実際のメッセージは実装依存です。 ロケールがnullの場合、デフォルトのロケールを使用します。

値の取得には、jdk.​jshell.​SnippetEvent クラスの public String value() メソッドを使います。

戻り値は成功した実行の結果値。

実行されなかった場合、または例外がスローされた場合、値はnullです。

以上、だいたいこんな感じで JShell API を楽しんでいきたいと思います。

動かすスニペットは例の「よく見かけるネタ IntegerCache 問題」です。

これだけだとさみしいので FunctionalInterface を利用した挨拶プログラムも JShell API で動かしてみましょう。

非常にシンプルなスニペットの実行となります。

Import statement、FunctionalInterface、などのステータス、値、種類などの情報を正確に取得できれば OK です。

では、このプログラムの実行結果を見てみましょう。

FunctionalInterface は、ただの Interface として識別されるようです。

IntegerCache 問題 もちゃんと false となっています。

3

これだと普通すぎて面白くないですよね。

日本ではもうすぐ Java SE 9 がリリースされようという時代に End Of Life となった Java SE 7 でプロフラムを組まなければいけない

涙無くしては語れない非常に過酷な環境に置かれているプログラマが多く存在するらしい。

そこでそういう可愛そうなプログラマのためにコンパイラオプションを JDK7 にし、

IntegerCache 問題で遊ぶために JVM オプションに -XX:AutoBoxCacheMax=128 を設定して実行してみます。

JShell オブジェクトの生成を JShell.create() メソッドから JShell.builder() メソッドに変更します。

4

5

コンパイラオプションの設定は

jdk.​jshell.​JShell.​Builder クラスの public Builder compilerOptions(String… options) メソッドと使い設定します。

可変長引数の使い方が独特で思いっきりドツボにはまったのは内緒です。

JVM オプションの設定は

jdk.​jshell.​JShell.​Builder クラスの public Builder remoteVMOptions(String… options) メソッドを使い設定します。

後は入出力の設定です。

これらは連鎖初期化で使用するため Builderインスタンスを返します。

最後に jdk.​jshell.​JShell.​Builder クラスの public JShell build() メソッドで JShell ステートエンジンを構築します。

これはすべてのJShell機能のエントリーポイントです。

これにより、実行のためのリモートプロセスが作成されます。

それではコンパイラオプションと JVM オプションが正しく機能するかプログラムを走らせてみましょう。

6

うわぁぁ!!

正しく期待通りの動作となったが何故か目から涙がこぼれそうに・・・

IntegerCache 問題の実行結果も true となり正しく JVM オプションが設定されたようです。

これだけで天の邪鬼な私のお遊びは終了です。

ここから先は思い込みでサプライズさせてもらったお話しです。

先のプログラムにコンパイラオプションと JVM オプションを設定しない元の状態に戻して下記スニペットの実行コードを追加してみました。

JShell では import 文を必要としないパッケージが何故か存在します。

java.util.Arrays もその一つだから無事にプログラムは実行されるだろうと思っていました。

7

((((;゜Д゜)))))))  なんと! ERROR! EXPRESSION [ シンボルを見つけられません・・・ ]

JShell API を利用する場合はおもてなしは無しなのか!?

8

しかたないから import 文を追記してみた。

9

今度は期待通りの動作で実行された。

10

ついでだから enum も試してみた。

11

ちゃんと enum 認識していた。

12

実は Linux 環境の NetBeans IDE だからちゃんと日本語対応されているのですが

Windows 環境だと日本語は文字化けしてしまいます。

13

セレブデベロッパーご愛用の IntelliJ IDEA (2017.2 EAP)でも Windows環境での JShellAPI で日本語は文字化けしてしまう。

これは Java SE 9 リリースまでに修正されるのだろうか?

14

ちなみに Windows のコマンドプロンプトからの実行は文字化けしません。

15

以上、JShell API を無駄に使って遊んでみたエントリーでした。

お終い!

おっと!JShell API と戯れた記念コードを載せておきますね。

実行結果は次のようになります。

run:
import java.time.LocalTime;
<< Single-Type-Import Declaration. >>
@FunctionalInterface
interface Greeting<T, R> {
R apply(T time, R message);

        default void sayGreeting(String greeting) {
            greeting(greeting);
        }

        private void greeting(String greeting) {
            System.out.println(greeting + ” from JShellAPI.”);
        };
}
<< Created Interface: Greeting >>
LocalTime now = LocalTime.now();
<< A variable declaration with an initializer expression. >>
now ==> 17:28:24.474604
int hour = now.getHour();
<< A variable declaration with an initializer expression. >>
hour ==> 17
Greeting<Integer, String> greeting
                = (time, message) -> 4 <= time && time < 11 ? “Good morning!”
                        : 11 <= time && time < 18 ? “Good afternoon!”
                                : “Good evening!”;
<< A variable declaration with an initializer expression. >>
greeting ==> $Lambda$17/555826066@a67c67e
String message = null;
<< A variable declaration with an initializer expression. >>
message ==> null
greeting.sayGreeting(greeting.apply(hour, message));
Good afternoon! from JShellAPI.
<< Statement: Snippet:StatementKey#7-greeting.sayGreeting(greeting.apply(hour, message)); >>

(○・ω・)ノ———————————————————-)

Integer x = 128;
<< A variable declaration with an initializer expression. >>
x ==> 128
Integer y = 128;
<< A variable declaration with an initializer expression. >>
y ==> 128
void equivalenceTest(Integer x, Integer y) { System.out.println(x == y); }
<< Created Method: equivalenceTest(Integer,Integer) >>
equivalenceTest(x, y);
false
<< Statement: Snippet:StatementKey#11-equivalenceTest(x, y); >>
(○・ω・)ノ———————————————————-)

import java.util.Arrays;
<< Single-Type-Import Declaration. >>
String str;
<< A variable declaration without initializer. >>
str ==> null
str = “Java”;
<< An assignment expression. >>
str ==> “Java”
String[] elems = str.split(“”);
<< A variable declaration with an initializer expression. >>
elems ==> String[4] { “J”, “a”, “v”, “a” }
System.out.println(Arrays.toString(elems));
[J, a, v, a]
<< Statement: Snippet:StatementKey#16-System.out.println(Arrays.toString(elems)); >>
Arrays.stream(elems).forEach(System.out::println);
J
a
v
a
<< Statement: Snippet:StatementKey#17-Arrays.stream(elems).forEach(System.out::println); >>
(○・ω・)ノ———————————————————-)

public enum JavaPlusYou {

    Japanese(“あなたとJAVA,今すぐダウンロード”),
    English(“JAVA+YOU, DOWNLOAD TODAY!”);

    private final String downloadNow;

    private JavaPlusYou(final String downloadNow) {
        this.downloadNow = downloadNow;
    }

    public String getDownloadNow() {
        return downloadNow;
    }

}
<< Created Enum: JavaPlusYou >>
for (JavaPlusYou jpy : JavaPlusYou.values()) {
            System.out.println(jpy + “: ” + jpy.getDownloadNow());
        }
Japanese: あなたとJAVA,今すぐダウンロード
English: JAVA+YOU, DOWNLOAD TODAY!
<< Statement: Snippet:StatementKey#19-for (JavaPlusYou jpy : JavaPlusYou.values()) {
            System.out.println(jpy + “: ” + jpy.getDownloadNow());
        } >>
(○・ω・)ノ———————————————————-)

System.out.println(System.getProperty(“java.vm.version”));
9-ea+169
<< Statement: Snippet:StatementKey#20-System.out.println(System.getProperty(“java.vm.version”)); >>
System.out.println(System.getProperty(“java.class.version”));
53.0
<< Statement: Snippet:StatementKey#21-System.out.println(System.getProperty(“java.class.version”)); >>
(○・ω・)ノ———————————————————-)

ビルド成功(合計時間: 4秒)

Hatena タグ: ,

Java SE 9 の予習 その3

Java

Java SE 9 の予習 その3です。

今回のエントリーは JShell です。

JShell は多くの開発者から期待されておりネット上に情報があふれています。

特に「最新Java情報局」の連載記事は解りやすくお勧めです。

そこで今回のエントリーは「こんな使い方はしないだろう」という内容のものを書きます。

つまり、ただのお遊びです

でもネット上でこの情報を見ることができるのは此処だけかもしれませんよ。(^_^;

それだけ必要がない無駄な情報と言えます。

それでは過去のエントリーをまずご覧ください。

よく見かけるネタ IntegerCache 問題

Java ではよく知られている IntegerCache 問題です。

これは JVM オプションを設定することにより変更が可能です。

-XX:AutoBoxCacheMax=<size>

これを JShell で設定してうごかしてみたいと思いませんか?

思わない・・・ そう、普通は思いませんよね。

でも、私は天の邪鬼な人間なのでどうすればいいか必死になってググりました。

でもヒットせず twitter で泣きながらつぶやいたら「ジャバチョットデキル」優しい人達に救われました。

JShell は「Java SE 9のProject Kulla、JShellの動作とJShell API」の記事「JShellの動作」にあるように

JShell process と Java process のふたつの JVM が立ち上がっています。

つまり、JShell process からリモート JVM の Java process にコンパイルされたバイトコードを渡し実行した結果を返してもらっているようです。

だからリモート JVM に JVM オプションを設定しなければなりません。

まず、JShell を起動します。

a1

次に IntegerCache 問題のコードを入力していきます。

a2

ちゃんと false となっています。

これを true にするために下記の JVM オプションを JShell 起動コマンドに追加します。

-R-XX:AutoBoxCacheMax=128

a3

期待通りに true になってくれました。

次はプログラムから JShell API を使ってみようと思います。

今回のようにリモート JVM オプションを設定したり、コンパイルオプションを設定してみました。

またプログラムから JShell API を使うときに思い込みから「あれれ?」となったことも。

ちょっと今日は遅くなってしまったので次回にそれらは書く予定です。

それでは G’Night! Zzz…

Java SE 9 の予習

Java SE 9 の予習 その2

Hatena タグ:

Java SE 9 の予習 その2

Java

Java SE 9 の予習 その2です。

Java SE 8 でインタフェースにデフォルトメソッドと静的メソッドが実装できるようになりました。

しかし、使い勝手はお世辞にも良いとは言えませんでした。

Java でプログラムを組む上で重要なのはインタフェースの設計にあるからです。

デフォルトメソッドが実装された理由は Java SE 8 でインタフェースにメソッドを追加すると実装クラスに与える影響が大きく既存のプログラムに破綻を生じるケースも考えられたからです。

そんな事情からインタフェースにデフォルトメソッドが追加され実装がインタフェースにされるようになりました。

Java SE 9 からはさらにプライベートメソッドが実装できるようになります。

これでデフォルトメソッドの実装内容の非公開にしたい所をインタフェース経由で公開してしまうようなことは無くなります。

とりあえずプログラムを組んで動作確認をしてみました。

 

このプログラムの実行結果は次のようになります。

I ate strawberry cake. It was very delicious.
I ate tiramisu cake.
I will eat another TiramisuCake.
I ate cheese cake.
I will eat another cheese cake.
I ate chocolate cake.

Java SE 9 ではこのような小さな改良がたくさんあるようです。(^_^)

Java SE 9 の予習

Hatena タグ:

Java SE 9 の予習

Java

今日は私の○X回目の誕生日です。

今年は忘れられずにお祝いのプレゼントまでいただきました。(^_^)

いくつになっても誕生日を祝ってもらえるのは嬉しいものです。

と言うわけでお誕生日記念として今年の夏にリリース予定の Java SE 9 の予習をはじめます。

Java SE 9 と言えば Project Jigsaw, Project Kulla (JShell) が目玉となっています。

これらはこれから日本語での情報もたくさん出てくると思うので後回しとします。(既に最新Java情報局で記事があります。)

故に Java SE 9 を使うのであれば必要最低限これだけは覚えておきたいことを自分用メモとして載せておきます。

完全に自分用のメモです!

static <E> List<E> of()

Returns an immutable list containing zero elements. See Immutable List Static Factory Methods for details.

Type Parameters:
E – the List’s element type

Returns:
an empty List
 

public Stream<T> stream()

If a value is present, returns a sequential Stream containing only that value, otherwise returns an empty Stream.

API Note:
This method can be used to transform a Stream of optional elements to a Stream of present value elements:
 
     Stream<Optional<T>> os = ..
     Stream<T> s = os.flatMap(Optional::stream)
 
Returns:
the optional value as a Stream

 

static <T> Stream<T> ofNullable(T t)

Returns a sequential Stream containing a single element, if non-null, otherwise returns an empty Stream.

Type Parameters:
T – the type of stream elements

Parameters:
t – the single element

Returns:
a stream with a single element if the specified element is non-null, otherwise an empty stream

 

public void ifPresentOrElse(Consumer<? super T> action, Runnable emptyAction)

If a value is present, performs the given action with the value, otherwise performs the given empty-based action.

Parameters:
action – the action to be performed, if a value is presentemptyAction – the empty-based action to be performed, if no value is present

Throws:
NullPointerException – if a value is present and the given action is null, or no value is present and the given empty-based action is null.

 

public Optional<T> or(Supplier<? extends Optional<? extends T>> supplier)

If a value is present, returns an Optional describing the value, otherwise returns an Optional produced by the supplying function.

Parameters:
supplier – the supplying function that produces an Optional to be returned

Returns:
returns an Optional describing the value of this Optional, if a value is present, otherwise an Optional produced by the supplying function.

Throws:
NullPointerException – if the supplying function is null or produces a null result

 

public static <T,A,R> Collector<T,?,R> filtering(Predicate<? super T> predicate, Collector<? super T,A,R> downstream)

Adapts a Collector to one accepting elements of the same type T by applying the predicate to each input element and only accumulating if the predicate returns true.

API Note:
The filtering() collectors are most useful when used in a multi-level reduction, such as downstream of a groupingBy or partitioningBy. For example, given a stream of Employee, to accumulate the employees in each department that have a salary above a certain threshold:
 
Map<Department, Set<Employee>> wellPaidEmployeesByDepartment
   = employees.stream().collect(
     groupingBy(Employee::getDepartment,
                filtering(e -> e.getSalary() > 2000,
                          toSet())));
 
A filtering collector differs from a stream’s filter() operation. In this example, suppose there are no employees whose salary is above the threshold in some department. Using a filtering collector as shown above would result in a mapping from that department to an empty Set. If a stream filter() operation were done instead, there would be no mapping for that department at all.

Type Parameters:
T – the type of the input elements
A – intermediate accumulation type of the downstream collector
R – result type of collector

Parameters:
predicate – a predicate to be applied to the input elements
downstream – a collector which will accept values that match the predicate

Returns:
a collector which applies the predicate to the input elements and provides matching elements to the downstream collector

 

public static <T,U,A,R> Collector<T,?,R> flatMapping(Function<? super T,? extends Stream<? extends U>> mapper, Collector<? super U,A,R> downstream)

Adapts a Collector accepting elements of type U to one accepting elements of type T by applying a flat mapping function to each input element before accumulation. The flat mapping function maps an input element to a stream covering zero or more output elements that are then accumulated downstream. Each mapped stream is closed after its contents have been placed downstream. (If a mapped stream is null an empty stream is used, instead.)

API Note:
The flatMapping() collectors are most useful when used in a multi-level reduction, such as downstream of a groupingBy or partitioningBy. For example, given a stream of Order, to accumulate the set of line items for each customer:
 
Map<String, Set<LineItem>> itemsByCustomerName
   = orders.stream().collect(
     groupingBy(Order::getCustomerName,
                flatMapping(order -> order.getLineItems().stream(),
                            toSet())));
 
Type Parameters:
T – the type of the input elements
U – type of elements accepted by downstream collector
A – intermediate accumulation type of the downstream collector
R – result type of collector

Parameters:
mapper – a function to be applied to the input elements, which returns a stream of results
downstream – a collector which will receive the elements of the stream returned by mapper

Returns:
a collector which applies the mapping function to the input elements and provides the flat mapped results to the downstream collector

 

default Stream<T> takeWhile(Predicate<? super T> predicate)

Returns, if this stream is ordered, a stream consisting of the longest prefix of elements taken from this stream that match the given predicate. Otherwise returns, if this stream is unordered, a stream consisting of a subset of elements taken from this stream that match the given predicate.
 
If this stream is ordered then the longest prefix is a contiguous sequence of elements of this stream that match the given predicate. The first element of the sequence is the first element of this stream, and the element immediately following the last element of the sequence does not match the given predicate.

If this stream is unordered, and some (but not all) elements of this stream match the given predicate, then the behavior of this operation is nondeterministic; it is free to take any subset of matching elements (which includes the empty set).

Independent of whether this stream is ordered or unordered if all elements of this stream match the given predicate then this operation takes all elements (the result is the same as the input), or if no elements of the stream match the given predicate then no elements are taken (the result is an empty stream).

This is a short-circuiting stateful intermediate operation.

API Note:
While takeWhile() is generally a cheap operation on sequential stream pipelines, it can be quite expensive on ordered parallel pipelines, since the operation is constrained to return not just any valid prefix, but the longest prefix of elements in the encounter order. Using an unordered stream source (such as generate(Supplier)) or removing the ordering constraint with BaseStream.unordered() may result in significant speedups of takeWhile() in parallel pipelines, if the semantics of your situation permit. If consistency with encounter order is required, and you are experiencing poor performance or memory utilization with takeWhile() in parallel pipelines, switching to sequential execution with BaseStream.sequential() may improve performance.

Implementation Requirements:
The default implementation obtains the spliterator of this stream, wraps that spliterator so as to support the semantics of this operation on traversal, and returns a new stream associated with the wrapped spliterator. The returned stream preserves the execution characteristics of this stream (namely parallel or sequential execution as per BaseStream.isParallel()) but the wrapped spliterator may choose to not support splitting. When the returned stream is closed, the close handlers for both the returned and this stream are invoked.

Parameters:
predicate – a non-interfering, stateless predicate to apply to elements to determine the longest prefix of elements.

Returns:
the new stream

 

default Stream<T> dropWhile(Predicate<? super T> predicate)

Returns, if this stream is ordered, a stream consisting of the remaining elements of this stream after dropping the longest prefix of elements that match the given predicate. Otherwise returns, if this stream is unordered, a stream consisting of the remaining elements of this stream after dropping a subset of elements that match the given predicate.
 
If this stream is ordered then the longest prefix is a contiguous sequence of elements of this stream that match the given predicate. The first element of the sequence is the first element of this stream, and the element immediately following the last element of the sequence does not match the given predicate.

If this stream is unordered, and some (but not all) elements of this stream match the given predicate, then the behavior of this operation is nondeterministic; it is free to drop any subset of matching elements (which includes the empty set).

Independent of whether this stream is ordered or unordered if all elements of this stream match the given predicate then this operation drops all elements (the result is an empty stream), or if no elements of the stream match the given predicate then no elements are dropped (the result is the same as the input).

This is a stateful intermediate operation.

API Note:
While dropWhile() is generally a cheap operation on sequential stream pipelines, it can be quite expensive on ordered parallel pipelines, since the operation is constrained to return not just any valid prefix, but the longest prefix of elements in the encounter order. Using an unordered stream source (such as generate(Supplier)) or removing the ordering constraint with BaseStream.unordered() may result in significant speedups of dropWhile() in parallel pipelines, if the semantics of your situation permit. If consistency with encounter order is required, and you are experiencing poor performance or memory utilization with dropWhile() in parallel pipelines, switching to sequential execution with BaseStream.sequential() may improve performance.

Implementation Requirements:
The default implementation obtains the spliterator of this stream, wraps that spliterator so as to support the semantics of this operation on traversal, and returns a new stream associated with the wrapped spliterator. The returned stream preserves the execution characteristics of this stream (namely parallel or sequential execution as per BaseStream.isParallel()) but the wrapped spliterator may choose to not support splitting. When the returned stream is closed, the close handlers for both the returned and this stream are invoked.

Parameters:
predicate – a non-interfering, stateless predicate to apply to elements to determine the longest prefix of elements.

Returns:
the new stream

 

static IntStream iterate(int seed, IntPredicate hasNext, IntUnaryOperator next)

Returns a sequential ordered IntStream produced by iterative application of the given next function to an initial element, conditioned on satisfying the given hasNext predicate. The stream terminates as soon as the hasNext predicate returns false.
 
IntStream.iterate should produce the same sequence of elements as produced by the corresponding for-loop:

     for (int index=seed; hasNext.test(index); index = next.applyAsInt(index)) {
         …
     }
 

The resulting sequence may be empty if the hasNext predicate does not hold on the seed value. Otherwise the first element will be the supplied seed value, the next element (if present) will be the result of applying the next function to the seed value, and so on iteratively until the hasNext predicate indicates that the stream should terminate.

The action of applying the hasNext predicate to an element happens-before the action of applying the next function to that element. The action of applying the next function for one element happens-before the action of applying the hasNext predicate for subsequent elements. For any given element an action may be performed in whatever thread the library chooses.

Parameters:
seed – the initial element
hasNext – a predicate to apply to elements to determine when the stream must terminate.
next – a function to be applied to the previous element to produce a new element

Returns:
a new sequential IntStream

 

static <T> Stream<T> iterate(T seed, Predicate<? super T> hasNext, UnaryOperator<T> next)

Returns a sequential ordered Stream produced by iterative application of the given next function to an initial element, conditioned on satisfying the given hasNext predicate. The stream terminates as soon as the hasNext predicate returns false.
 
Stream.iterate should produce the same sequence of elements as produced by the corresponding for-loop:

     for (T index=seed; hasNext.test(index); index = next.apply(index)) {
         …
     }
 

The resulting sequence may be empty if the hasNext predicate does not hold on the seed value. Otherwise the first element will be the supplied seed value, the next element (if present) will be the result of applying the next function to the seed value, and so on iteratively until the hasNext predicate indicates that the stream should terminate.

The action of applying the hasNext predicate to an element happens-before the action of applying the next function to that element. The action of applying the next function for one element happens-before the action of applying the hasNext predicate for subsequent elements. For any given element an action may be performed in whatever thread the library chooses.

Type Parameters:
T – the type of stream elements

Parameters:
seed – the initial element
hasNext – a predicate to apply to elements to determine when the stream must terminate.
next – a function to be applied to the previous element to produce a new element

Returns:
a new sequential Stream

 

API ドキュメントが英語しかないのが残念(>_<)

正式リリースされる頃には日本語版が出ることを祈ろう!

Java SE 8 からの痒いところに手が届いたようなアップデートだけどかなり便利になる。

なぜ初めからこうしなかったんだろうと思うほどに。

でも zip, pair はまだ無いまま・・・

Java SE 10 まで待つことになるのか必要ないと判断されたのか?

他にもいろいろ細かいところが良くなっているようだから正式リリースが楽しみですね!

Hatena タグ:

« 古い記事