Java

CompletableFuture で遊ぶ

Java

あけましておめでとうございます!

ずいぶん遅い新年の挨拶となりますが本年もよろしくお願いします。

それでは新年1発目のネタは私の愛する Java です!

Java 8 の新機能である CompletableFuture の詳細が下記サイトで解説されはじめました。

詳解 Java SE 8 第19回 Concurrency Utilitiesのアップデート その1

Java 8 が正式リリースされる前から気にはなっていたのですが海外のサイトでも情報量が少なく英語がよく解らないので正しい使い方が解らずにいました。

おまけに Java API ドキュメントもその当時は日本語のものはありませんでした。

現在は日本語の API ドキュメントも用意されているのでうれしい限りです。

それではとりあえず何か適当にプログラムを組んでみることにします。

お正月ということでちょっとふざけた内容としました。

ネタがネタだけにごめんなさいと先に行っておきます。(ヲヒ

今回のネタは CompletableFuture を使ってプログラムを高速化するです。(そんな大袈裟なものじゃないし、使わなくても可能なのは秘密です。)

あなたは、ある IT 企業に勤めています。今回あるプロジェクトのリーダーを任されました。

あなたは何人かメンバーを選出しなければなりません。

そこで希望者を募ったところ、たくさんの魅力的な女性プログラマ達があなたを取り囲みました。

予想外の出来事にあなたは大喜びで全員をプロジェクトチームに加えようとしましたが・・・

なんと女性達は隣の女性をチームに加えるなら私は辞退すると言います。

たとえば、A子、B子、C子、D子、E子 と言う具合にあなたを中心に取り囲んでいるとしたら

A子をメンバーに加えると、B子、E子はチームに加えることは出来ないということです。

B子をメンバーに加えると、A子と C子はチームに加えることはできない。

困りました。

そこであなたは胸ポケットから「おっぱいスカウター」という秘密兵器を取り出し女性達のバストを計測できるようにしました。

そう、あなたは、おっぱい星人だったのです。

それを利用してチームに加える女性達のバストの合計値が最大になるように選出することにします。

これからもこういうことがちょくちょくあるかもしれないのであなたはプログラムを組むことにします。

さて、あなたならどんなプログラムを組むでしょう?(Java 8 で組むこと)

女性プログラマ達のバストのサイズは配列に乱数を生成して格納します。

配列の要素数は女性プログラマの人数となります。

さて、あなたならどんなコードを書くでしょうか?

最も簡単な例は次のようなコードになると思います。

デバッグ用に必要の無いものがありますが気にしないでください。

一見、実にシンプルでいて合理的なように見えます。

それでは動かしてみます。

1

順番に処理されているのが解ります。

処理時間は OppaiSearch クラスの getOppaiTask() メソッドの中のループ処理中にランダムなスリープを少し挟んでいるので気にしないでください。

このプログラムを高速化するには getOppaiTask() メソッドを並行処理してしまうのが手っ取り早いですね!

そこで CompletableFuture を使って楽に高速化してみます。

OppaiAlien クラスを次のように変更します。

見慣れないコードがありますね。

次のように supplyAsync() メソッドを使って CompletableFutureオブジェクトを生成します。

CompletableFuture<Integer> future0 = CompletableFuture.supplyAsync(() -> oppai_0.getOppaiTask());
CompletableFuture<Integer> future1 = CompletableFuture.supplyAsync(() -> oppai_1.getOppaiTask());

そして supplyAsync() メソッドで作った二つの CompletableFutureオブジェクト を非同期で処理させます。

supplyAsync() メソッドは API ドキュメントでは次のように説明されています。

public static <U> CompletableFuture<U> supplyAsync(Supplier<U> supplier)

ForkJoinPool.commonPool()で実行されているタスクが指定されたサプライヤを呼び出して取得した値を使用して非同期的に完了する新しいCompletableFutureを返します。

それでは次にこれらから得られる値の大きなほうが最終的な結果となります。

実はこのプログラムはちょっと遊びが入っているので本来の目的だけを達成するには次のコードで完了させることができます。

try {
    System.out.println(“おっぱいのサイズの最大総和は ” + Math.max(future0.get(), future1.get()) + “です。”);
    System.out.println(“プログラムを終了します。”);
    } catch (InterruptedException | ExecutionException ex) {
    Logger.getLogger(OppaiAlien.class.getName()).log(Level.SEVERE, null, ex);
}

get() メソッドは処理が完了するまで待つので両方の非同期処理の結果を取得してから Math.max() メソッドは実行されます。

このプログラムでは thenCombine() メソッドを使って、CompletableFuture<Integer> future0 と CompletableFuture<Integer> future1 の両方の処理が終わるまで待って

それらを使って処理をして結果を返すようにしています。

// 両方の処理が終わってから計算値が大きい方を返す。
CompletableFuture<Integer> f = future0.thenCombine(future1, (f0, f1) -> {
    System.out.println(Thread.currentThread().getName() + ” : CompletableFuture<Integer> f”);
    return Math.max(f0, f1);
});

thenCombine() メソッドは API ドキュメントによると次のように説明されています。

public <U,V> CompletableFuture<V> thenCombine(CompletionStage<? extends U> other,
                                              BiFunction<? super T,? super U,? extends V> fn)

このステージと指定された他のステージの両方が正常終了した際に実行される新しいCompletionStageを返します(実行時には、指定された関数の引数として2つの結果が使用される)。

それでは先に進みましょう。

このプログラムではさらに余計なことをしています。

get() メソッドにタイムリミットを設定しました。(^_^;)

result = f.get(3, TimeUnit.SECONDS);

タイムアウトしたら

f.complete(-1);

と、CompletableFuture<Integer> f に –1 を設定します。

実はこのプログラムではこんなことをせずにタイムアウトが発生したら result に –1 を代入すればいいだけなんですが complete() メソッドを使いたかったからこうなっただけです。( ̄。 ̄;)

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

2

Fork/Join Framework が使われて並行処理されているのが解ります。

また、両方の処理が完了されてから最終的な処理もされているのが確認できます。

今回の目的である並行処理によるプログラムの高速化を CompletableFuture を使ってすることができました。(^_^)

ただ、これでいいのか?それとももっと良い使い方があるのかは不明です。

これからの 詳解 Java SE 8 第19回 Concurrency Utilitiesのアップデート の記事に注目していきましょう!

ここからはおまけです。

今回のプログラムでは両方の処理が完了するのを待ってました。

先に終了した方を表示するだけの場合も試してみます。

最終処理をこちらに変更します。

applyToEither() メソッドを使います。

これはどちらかが処理結果を得られれば、その結果を指定された関数に渡します。

// 処理が早く終わった方を返す。
CompletableFuture<Integer> f = future0.applyToEither(future1, x -> {
    return x;
});

applyToEither() メソッド は API ドキュメントでは次のように説明されています。

public <U> CompletableFuture<U> applyToEither(CompletionStage<? extends T> other,
                                              Function<? super T,U> fn)

このステージまたは指定された他のステージが正常に完了したときに、対応する結果を指定された関数への引数に設定して実行される新しいCompletionStageを返します。

それでは実行結果を見てみましょう。

3

まだ片方しか処理が終わってないのに最終処理がされているのが確認できます。

目的のプログラムとしては駄目ですが、あくまで参考ということで!

間違い、もしくはもっと COOL な方法があれば教えていただければ幸いです。

Hatena タグ:

NetBeans IDE から SSH 接続で GitHub を使ってみた。

Java NetBeans Ubuntu

お盆休みも今日が最後になったのにダラダラして終わることになった。(^_^;

ビール飲んでグダグダしながらこんなことを今さらしていたので記念にエントリーしておく。

最初に GitHub に新しいリポジトリを作成する。

そしてまだ SSD 公開鍵を設定してなければ設定しておく。

1

 

NetBeans IDE で新規プロジェクトを作成する。

2

 

Git ローカルリポジトリを作成する。

3

 

ローカルリポジトリを作成する場所を指定する。

4

 

出力ウィンドウでローカルリポジトリが作成されたことが解る。

5

 

プロジェクトウィンドウでもリポジトリのバッジが付いたことが確認できる。

6

 

HelloGitHub.java ファイルを add する。

7

 

そしてコミットする。

8

 

コミットされるファイルを確認し、解りやすいメッセージを書いておく。

GitHub は公開だと全世界と繋がるので地球標準の英語でメッセージを書いておくと良いことがあるかもしれない。

9

 

ローカルリポジトリにコミットした状態を Git リポジトリ・ブラウザで確認。

まだ寂しい状態であることが一目で解りますね。(ちょっと表現がおかしいけど気にしない。プレミアム・モルツのせいだ!)

10

 

それではリモートリポジトリにプッシュしましょう。

11

 

はじめてリモートリポジトリに接続する場合は下図のように必要事項を設定します。

これは SSH 接続を利用しています。(OpenSSH)

一度設定してしまえば後はラクチン、ラクチンです。

12

 

接続が完了すると下図のような画面が表示されます。

16

 

チェックをいれて次へ進めます。

17

 

終了ボタンを押してプッシュを実行します。

18

 

リモートリポジトリへのプッシュが完了したことを Git リポジトリ・ブラウザで確認します。

19

 

疑り深い人は GitHub のサイトをブラウザで開いて確認してみてください。

20

 

さらにソースコードを編集します。

21

 

変更されたことが色づけとバージョンラベルで確認できます。

22

 

さっきと同様にローカルリポジトリをコミットします。

23

 

そしてリモートリポジトリへプッシュします。

今度は先ほど設定したリモートリポジトリが選択されているので「次へ」ボタンを押すだけです。

24

 

25

 

26

 

さて、疑り深い人は GitHub のサイトをブラウザで開いて確認ですね。

27

 

完璧ですね。

28

 

ついでに履歴も確認。

29

 

30

 

NetBeans IDE で Git をそれなりに使うには十分ですね。

ただ、大規模なプロジェクトだと専用のツールを使ったほうが痒いところに手が届きます。

必要十分な機能は備えているみたいなんでやっぱり NetBeans IDE は素晴らしい!

Hatena タグ: ,,

Ubuntu で Java を使うためにすること

Java Ubuntu

完全無欠の自分用のφ(..)メモメモです。

Linux よく解らないので適当にやってます。

間違ってる、もしくはおかしなことをやっている可能性大なので何かの拍子に「ゆっちのBlog」にたどり着いた方はご注意くださいませ。

 

Oracle の Java をインストールします。

スクリーンショットのようにコマンドを入力していけば簡単にインストールできます。

a1

 

a2

 

a3

 

Java SE 7 をインストールします。

a4

 

確認画面が表示されます。

a5

 

ライセンスに同意できるなら <はい> を選択してインストールを進めます。

a6

 

インストール完了です。

a7

 

次に、Java SE 8 をインストールします。

a8

 

これも簡単にインストールが終了します。

a9

 

update-alternatives コマンドを使うために help を表示させてみましょう。

b1

 

では、java で登録されているものを表示させてみます。

さっきインストールした Java SE 7 と Java SE 8 が登録されてます。(勝手に!)

b2

 

では、open JDK でビルドした自家製?の Java を登録してみます。

c1

 

もう一度 java で登録リストを表示させてちゃんと登録できているか確認します。

ちゃんと登録できてます!

c2

 

ついでに javac も登録しておきましょう。

c4

 

update-alternatives –config <登録名> で対話式で切り替えが可能となります。

今回はこれを使いたくないので削除します。

java を削除して確認します。

削除されたのでエラーが表示されました。

d1

 

同様に javac も削除し、確認します。

d2

 

Java と javac のバージョン確認コマンドを打ち込みます。

パスが設定されていないので次のようになります。

e1

 

パスを設定するために ~/.bashrc を編集します。

これ root になってやってしまったけど一般ユーザーでできるはず。

f1

 

私の場合次のような環境設定をしました。

JAVA_HOME はインストールした場所によって変わりますのでご自分の環境にあわせて Path 設定をおこなってください。

f2

 

確認です。

g1

h1

 

はっきりいって面倒くさい!

Windows の PATH 設定のほうが遙かに楽だね。

Linux で GUI 操作によって簡単に設定を変更できるものがあるかもしれないけどネットでググったら

update-alternatives –config <登録名> で変更している人がほとんどだった。

 

おまけ

Linux は使いづらくて取っつきにくいという印象がありますよね。

それを少しでも緩和するために私は moebuntu という素晴らしいものを導入しました。

下の画像は私のデスクトップのスクリーンショットです。

これだけ見ると Windows より Ubuntu の勝ちです! (^_^;

Screenshot from 2014-08-03 20_18_12

Hatena タグ: ,

Java Developer Connection のプログラマチャレンジ Vol.2

Java JavaFX

この前のエントリーの続きです。

前回は検索ファイルのハイライト表示が Swing のように簡単にできそうにないとしてあきらめてました。

JavaFX8 で導入された TextFlow を使えば実現できるんじゃないかと思っていたところ Twitter で TextFlow で、できるんじゃないかと教えていただいたので早速チャレンジしてみました。

結果からいうと Swing の JTextPane より柔軟性に優れ、テキストの装飾の自由度も遙かに JavaFX8 の TextFlow のほうが高いです。

0

ただし、編集できないです。(>_<。)

編集とかする必要があれば使い慣れているエディタを使うことになるだろうから良しとしましょう。(^_^;

あと JavaFX では CSS を使ってプログラムの見栄えを良くしたり、ちょっとしたエフェクトをかけたりすることができます。

例えば、Node の上にマウスカーソルがのったら、出たら、押されたら、 それらの処理を Java コードで書くと次のようになります。(たぶん、、、)

11

 

これを CSS を使うとどうなるか。

Button の例を次に示します。

12

これは Button 全てに適用させてます。

めっちゃ楽です!

Button それぞれにエフェクトを変えたい場合は ID を設定して個別の記述すればいいだけです。

CSS is Great!

しかし、こんなに便利で簡単に大きな効果を得られるのにネット上では CSS の情報はかなり少ないです。

今回かなりネットサーフィンしてあーでもない、こうでもないと悩みました。

その中で TabPane に Tab がいっぱいになってポップアップリストビューが表示されたときのチェックマークの色を変えたかったのですがどれだけ探しても解決方法をみつけることはできませんでした。

1

それと WebView のスクロールバーもマウスがのったらグラデーションするようにしたかったのですが何故かできませんでした。

なんで WebView だけ?

まだまだ JavaFX 解らないことだらけなのに CSS まで(>_<。)

でも、楽しいからもっと時間がほしい! (*^▽^*)

あと、ついでにこんなどうでも良いような(迷惑な)こともやってみました。

2

SubScene を透過させてみました。

プログラム本体を移動させて表示させると 3D マスコット(そんな良いもんじゃ無い!)みたいですね。

3

上の Label と Button は普通の Scene なのでこれを取っちゃえば面白いことができそうです。

3D 時計を作ってある時間に 3D の鳩が画面に出てきてポッポ、ポッポと鳴き出すとか(なんのこっちゃ!)

発想力が貧相だな・・・

なにはともあれ、楽しめたので Happy だ!

動画も貼っておきますので興味のある方はみてくださいませ!

 

JavaFX is Great!

Hatena タグ: ,

Java Developer Connection のプログラマチャレンジ

Java JavaFX

Java Developer Connection テクニカルティップって覚えている人っていますよね?

そこでプログラマチャレンジってのがあって当時私もチャレンジしてみたのですが

簡単そうで難しかった思い出があります。

そもそも当時の Java はタブにコンポーネントを貼れないため閉じるボタンをタブじゃないところに置かなくてはいけませんでした。

非常にダサかったです。

現在リリースされている Java8 では次世代 UI の JavaFX8 が使えますので最新の Java8 を使って作ってみました。

ちょっと予定していた機能を実装できなかったり、Java8 の Files.wark メソッドでの探索処理ではまったりでたくさん泣きました。

結局、完成には至りませんでしたがそこそこできたので良しとします。(ヲヒ

大文字、小文字を区別するかしないか

サブディレクトリも検索するかどうかをチェックボックス付きのメニューアイテムで選択できるようにしました。

ディレクトリチューザーを開くようにして容易に検索場所を指定できるようにしました。

1

 

PathMatcher を使っているのでエディタブルな ComboBox を利用して複数の拡張子を指定できるようにしました。

検索対象のファイルのリストをタブにまとめました。

そしてリストビューにファイルのパスを表示するようにしました。

2

 

リストビューのパスを選択するとそのファイルの表示をするようにしました。

swing では検索ワードを色をつけて太字とすることが可能だったのですが JavaFX ではどうしたらいいか解りませんでした。

TextFlow を使えばなんとかなるのかなって思ってみたのですがちょっと解決方法が思いつきませんでした。(残念!

3

 

そこで、それならば代わりに印刷機能を付けちゃおうって思ってやってみたのですが・・・

これまた、頭がドッカーン!!

何故か印刷ダイアログのキャンセルボタン、もしくはウィンドゥの閉じるボタンを押しても印刷してくれるという・・・

凄すぎるよ!JavaFX8 の PrintAPI

おまけに一枚分しか印刷できない。(たぶんこれは私の理解不足です。

4

 

あと、以前のエントリーで Java8 の Files.wark メソッドが便利だと書いたのですが訂正します。

使いづらいです!

java.nio.file.AccessDeniedException で仕事放棄します。(;´Д`)

しかたないので Java7 の古い API でグルグルまわしました。

基本的な機能はだいたいできたので良しとします。

あとは音とかアラートダイアログとかアバウトとか細かい作業なのでどうでもいいです。

どうせ自分専用だしね! (^_^)

あれから12,3年くらい経つのかな?

ずいぶん良くなった!

Java 最高!

Hatena タグ: ,

« 古い記事 新しい記事 »