2017

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 タグ:

Windows 10 Creators Update インストールエラー 0x8007042B-0x4000D

Computer Windows

Windows 10 Creators Update を適用しようとしてドツボにはまった。(>_<。)

そろそろインストールが終わることだろうと思ったら 0x8007042B-0x4000D というエラーコードが出て元の状態にロールバックされてました。

error

なんだこれは!と思いながら思考停止でもう一度アップデートを試みました。

が、結果は同じ・・・

しかたないからエラーコードを調べてみたら 0x800xxxxx から始まるエラーコードは一般的なオペレーティングシステムエラーを表しているそうです。

Windows アップグレードプロセスに特有なものではないということなので私のシステムに問題が潜んでいるようです。

さらに調べていくと 0x8007042B-0x4000D というエラーコードはファイルシステム、アプリケーション、ドライバーに問題があるそうです。

必要のないサービスを全て止めてインストールができたという記事も見ましたし、ユーザープロファイルの移行が上手くいかなかった例もありました。

ここで冷静になり、このシステムで問題になりそうなところはと考えたところ・・・ ありました!

個人情報ファイルを詰め込んだフォルダに思いっきりセキュリティロックをかけていたのを忘れていました。

一時的にこのフォルダのセキュリティロックを外し Creators Update を適用したところすんなりとアップデートできました。

こんなミスをして大切な時間を無駄にしたかと思うと目から汗がでてきます。

そういうことで、もう寝ます。D’Night! Zzz…

Hatena タグ:

東京西川 エンジェルフロートを買ってみた。

General

私は今まで枕を選ばないタイプだったのですが先日まで愛用していたそば殻枕が痛んできたので枕を買い換えました。

買い換えた枕は睡眠の研究をしているところのお勧めタイプのもので有名なメーカーのものでした。

詰め物はパイプと綿となっており真ん中がへこんで横向きになったときの為に両サイドが高くなっているよくあるような製品でした。

枕の高さも低め、普通、高めと選べるようになっていて私は低めか普通が好みなので普通を選択しました。

このようなタイプの枕は初めてで今までのそば殻枕より快適に眠れるだろうと期待しておりました。

しかし、普通の高さを選んだのにもかかわらず沈み込みが少なく高く感じました。

この手の枕は気道を確保し熟睡できることが売りになっているのですが私には合いませんでした。

朝起きたときに首に違和感があり、慣れてないからだろうと使い続けていると首のこりが酷くなってきました。

そして一週間ほど使った朝に衝撃の事態が発生しました。

なんと、朝起きたら目がぼやけてよく見えなくなりました。

はじめは目やにかゴミでも入ったのかと安易に思ったのですがどうもおかしい・・・

そしてとんでもないことに気付きました。

左目の視界の上半分と左2割くらいがグレーアウトして見えない!

なんだこれは!

私の目は機械で接触不良でも起こしてしまったか? なんてパニックに陥りました。

何度瞬きをしても、目をこすってみてもグレーアウトしてます。

どうしたらいいんだろう・・・と不安になりながら今日は会社を休んで目医者に診てもらいに行こうと思い、とりあえず朝食食べてから連絡をいれようと冷静になり落ち着こうとしました。

早朝から目医者は開いてないからゆっくり見えにくくなった目を酷使するようだけどネットでこのような症状を調べてみることにしました。

調べだして暫くしたらグレーアウトしていた部分がモザイクがかかったように見えだしてやがて正常に見えるようになりました。

時間にして20分くらいの出来事でした。

少し、ほっとしましたが気になるので調べたところ黒内障と症状が似ているようです。

会社を休んで目医者に診てもらいに行こうかと思ったけど休日になるまで様子をみることにしました。

それから一度もこのような症状は出なかったのですが念の為に目医者にいってきました。

検査をいろいろしてもらった結果何も異常は無しということで安心しました。

このような症状は首の血流が悪くなると起こる場合があるそうです。

私の場合思い当たるのは枕を変えて首のこりが酷くなっていたのが原因かもしれません。

あと、ストレスや睡眠不足でもなる場合があるそうです。

とりあえず恐ろしい病でなくてよかった!

さて、買ったばかりの枕なのですがこんなことがあるともう使いたくなくなります。

前に使っていたそば殻の枕と同じようなものを購入しようかと思ったのですが、なんか負けた感が漂うのでここは人気と評価の高い枕を調べて購入することにしました。

いろいろ調べたところ「東京西川 エンジェルフロート」という低反発っぽい柔らかそうな枕があることを知りました。

低反発枕が話題になった頃に購入して使ったことがあるのですが冬は良かったのですが夏は蒸れて暑くて駄目でした。

エンジェルフロートはたくさんの空気孔を設けることにより通気性を向上させ蒸れ対策をされてます。

高さの調節も4分割のウレタンシートで調節できます。

とは言え、低め、ふつう、高めと3種類はじめからラインナップされているので至れり尽くせりです。

「天使のほっぺの、やさしいタッチ。」

「表面はやさしいタッチ、ベースはしっかりサポート」

このうたい文句が枕なんてどうでもいいと思っていた私に「この枕で寝てみたい」と思わせてくれました。

ただ、お値段が・・・高い たかが枕にこんなにお金を使いたくないなぁな・・なんて思ったりもしましたが今回のような怖い思いは二度としたくないので購入しました。

1

2

このような綺麗な化粧箱にはいってます。

実物はこのように見た目はごくありふれた感じです。

3

だけど触ってみると「おおっ!」と感動します。

天使のほっぺと表現するだけのことはあって上品な柔らかさです。

また肌触りが良い!

枕カバーを付けずにこのまま使いたいくらいです。

ただ、この枕のサイズが特殊で 33 X 60 X10 センチです。

奥行きが狭いので頭のサイズが大きめの人は不向きかもしれません。

それよりもこの枕に合う枕カバーが見当たらない。

専用側地と対応枕カバーがあるのですがどちらも高価です。

 

枕カバーは少しだけ安価なものもあります。

私は専用側地と対応枕カバーも購入することにしましたがこれらは届くまで時間がかかるようなのでニトリの「ピッタリニットまくらカバー」というリーズナブルな商品を使うことにしました。

4

やっぱり専用品でないのでピッタリとまではいきませんね。

肌触りは悪くないのですが安っぽいTシャツを巻いたような感じになってしまいました。

専用枕カバーが届くまではこれでいきます。

肝心の枕の使い心地は良好です。(^_^)

枕の高さは普通を選んだので10センチですが沈み込みがちょうど良い具合で満足です。

やはり凝った作りのまくらはそれだけの価値がありますね。

それでは、 G’night!

Zzz…


« 古い記事 新しい記事 »