Mixin Script Function in JavaFX Part 3
BufferedReader in JavaFX と Mixin Script Function in JavaFX Part 2 で BufferedReader を JavaFX で安全に利用するための方法について紹介してきましたが、少し 他のスクリプト言語を意識しすぎて、良くも悪くも JavaFX らしさを失っていたことに今更ながら ふと気がついてしまった。
と言うのも...
JavaFX では Java の 拡張 for 文 に似た for 式 が用意されています。
前回 紹介したサンプルコードは わざわざ、他のスクリプト言語のマネなんかしなくても、以下のようにちゃんと標準で用意されている for 式 だけで実現できてしまうのです。
この方が JavaFX らしいですね。
JavaFX の for は Java や その他の言語 とは異なり、文ではなく、式なので、ちゃんと結果も返してくれます。
初めはちょっと違和感があるものの結構使える。
Main.fx
public class Main extends $ {} public function run() { // ファイルの内容を標準出力 var r = new FileReader("test.txt"); try { for (line in $R(r)) println(line); } finally { r.close(); } // ファイルの内容を Window へ出力 r = new FileReader("test.txt"); try { Stage { scene: Scene { content: VBox { content: for (line in $R(r)) Text { content: line } } } } } finally { r.close(); } }
前回との違いは _R クラスで Iterable を実装して、for 式で利用できるようにしたことです。
詳細は Cast to sequence in JavaFX でも紹介しましたが...
JavaFX の for 式でループできるのは 配列 と Iterable ですので、Iterable を実装すれば、for 式で反復処理できるのです。
ただ、ちよっと残念なのは、呼び出し側で 入力ストリームの close() を呼び出さなくてはならないこと。
Iterator で 確実に 入力ストリームの close() を呼び出す方法が思いつかない...
考えられる手としては
その理由としては
- Iterator#next() が何らかの理由で最終回まで実行されない可能性がある。
- Iterator#finalize() は仕様上呼び出されるかどうかわからない。
- FX.addShutdownAction(function()) は実行タイミングが遅すぎる。
まぁ、子供の頃、親に言われたように「開けたら閉める!!」と言うことで 呼び出し側で close() しましょう。
$.fx
public mixin class $ {} protected function $R(r: Reader) { _R { reader: r }; } protected class _R extends Iterable { public-init var reader: Reader; override function iterator(): Iterator { Iterator { var r = new BufferedReader(reader); var s: Object = r.readLine(); override function hasNext(): Boolean { s != null; } override function next(): Object { var ret = s; s = r.readLine(); // next line return ret; } override function remove(): Void { throw new java.lang.UnsupportedOperationException(); } } } }