第7章 Nashorn JavaScript エンジンの活用 : 問題 2 : jjs でラムダ式
問題
jjs を実行し、Stream ライブラリを使用して次の問題に対する解法をインタラクティブに求めよ
あるファイルに含まれている長い単語(12文字より長い)を、重複なしで全てソートして表示せよ
解答
まず、Stream
の要素をコンソールに表示して元のStream
を返す JavaScript の関数pr
を定義する
function pr(stream) { return stream.peek(function(x) { print(x) }) .collect(java.util.stream.Collectors.toList()) .stream(); }
注)実際には1行で記述する
関数pr
を使うと、(無限 Stream に対応できないが)Stream を生成するたびに中身を確認できる
では、第2章で使った "不思議の国のアリス" のテキストファイルでトライしてみよう
jjs での入力 | コメント |
---|---|
var path = java.nio.file.Paths.get('alice.txt') | ファイルのパス |
var binary = java.nio.file.Files.readAllBytes(path) | ファイルの読み込み |
var contents = new java.lang.String(binary) | 文字列へ変換 |
var words = contents.split(/\W+/) | 単語に分割 |
var list = java.util.Arrays.asList(words) | 配列 → List<String> |
var st = list.stream() | 単語の Stream |
st = st.filter(function(w) w.length > 12) | 長い単語を抽出 |
st = st.distinct() | 重複を除去 |
st = st.sorted() | ソート |
st.forEach(function(w) { print(w) }) | 表示 |
得られた結果は、次のとおり
CONSEQUENTIAL Contributions International MERCHANTIBILITY Multiplication Redistributing Redistribution affectionately circumstances contemptuously contributions conversations disappointment electronically extraordinary identification inquisitively nonproprietary opportunities redistributing redistribution representations straightening transcription uncomfortable uncomfortably unenforceability
おまけ
いや~、この練習問題ははまりました
■ 文字列contents
を単語に分解するところ
var contents = new java.lang.String(binary)
としたのでcontents
のデータ型はjava.lang.String
だと思い込んでました
そこで、単語に分解するsplit
はjava.lang.String
のメソッド
public String[] split(String regex)
になると思い
var words = contents.split("[\P{L}]+")
とやったのです
ところがcontents
は、マーシャリングされて JavaScript の文字列になっているので、split
メソッドに渡す引数は JavaScript の正規表現オブジェクトでなければならず
var words = contents.split(/\W+/)
が正しいんですね
… 引数に文字列を渡したときにエラーが起これば早く気づいたんですが
■ 配列words
からjava.util.stream.Stream
を得るところ
配列 → List<String> → Stream<String>
と二段階で Stream をゲットしているが、java.util.Arrays
クラスのstream
メソッドを使えば一発じゃないの…
ところが
jjs> var st = java.util.Arrays.stream(words) java.lang.RuntimeException: java.lang.NoSuchMethodException: Can't unambiguously select between fixed arity signatures [(double[]), (int[]), (long[]), (java.lang.Object[])] of the method java.util.Arrays.stream for argument types [jdk.nashorn.internal.objects.Na tiveArray]
となっちゃいます
つまり “overload されていて、どのメソッドを選んでいいのか分からない” ということであえなく撃沈
Java.to
メソッドを使って型変換すればいいのだが、別に配列が欲しい訳ではないのでList
経由にしました
さらに問題
このインタラクティブな取り組み方は、普通のワークフローと比較してどうか?
解答
問題 1 と違って、それほど楽ではなかった
ラムダ式ないし Stream のフィルターは遅延実行なので、その場で中身を確認できない
かと言って中身を表示すると、それは終端操作なので Stream が閉じてしまい何もできなくなる
Stream の中身を確認する関数pr
を定義してからは楽になったが、ここまでするぐらいなら Java でいいかなというのが本音である