Java の List を Clojure の List にするはなし
Clojure の特長の一つに Java との親和性の高さがあります。 Clojure のプログラム中では Java のオブジェクトやメソッドを Clojure の関数やコレクションと同じくらい簡単に扱うことができるのです。この親和性の高さを支えているのが Java のコレクションと Clojure のコレクションとの相互運用性です。
この記事では、Java のコレクション 1 を Clojure プログラム中で扱う方法について解説します。 Scala についてはねこはる先生が Java の List を Scala の List にするはなし をまとめていますので、合わせてご覧ください。
Java の List を Clojure で使う
Java の List を Clojure で使うのは簡単です。 Java の List は シーケンスっぽい ので、 map や filter などのシーケンス関数にそのまま渡すことができます。何もしなくてもそのまま使えます。
user> (def xs (doto (ArrayList.) (.add 1) (.add 2) (.add 3))) #<Var@32364687: [1 2 3]> user> (class xs) java.util.ArrayList user> (->> (map #(* % 7) xs) (filter odd?) (reduce +)) 28
Java の Set や Map なども同様にシーケンスっぽいので、何もしなくてもそのままシーケンス関数で使うことができます。
user> (import 'java.util.TreeSet) java.util.TreeSet user> (def ys (doto (TreeSet.) (.add 1) (.add 4) (.add 11))) #<Var@3536d41f: #{1 4 11}> user> (class ys) java.util.TreeSet user> (count (filter odd? ys)) 2
Java の List を Clojure のベクタにする
Java のコレクションを Clojure のコレクションに変換するには into が便利です。空の Clojure コレクションを用意して、それに Java のコレクションを注ぎ込むだけです。
user> (class xs) java.util.ArrayList user> xs [1 2 3] user> (def v (into [] xs)) #<Var@33e27fc6: [1 2 3]> user> (class v) clojure.lang.PersistentVector user> (def q (into clojure.lang.PersistentQueue/EMPTY xs)) #<Var@4c04b2d7: <-(1 2 3)-<> user> q <-(1 2 3)-< user> (class q) clojure.lang.PersistentQueue
変換先の Clojure コレクションがベクタかセットである場合は、 into の代わりに vec, set 関数をそれぞれ使うこともできます。
user> xs [1 2 3] user> (class xs) java.util.ArrayList user> (def v' (vec xs)) #<Var@44584fa5: [1 2 3]> user> v' [1 2 3] user> (class v') clojure.lang.PersistentVector user> (def s' (set xs)) #<Var@420215a4: #{1 3 2}> user> s' #{1 3 2} user> (class s') clojure.lang.PersistentHashSet
Clojure の List を Java の List にする
Clojure のリスト、ベクタ、セット、キュー、シーケンスは j.u.Collection の読取専用メソッドを全て実装しているので、リードオンリーで扱う限りは Java のコレクションに変換しなくても j.u.Collection オブジェクトとして使えます。 Java のコレクションに変更する場合でも、 Clojure のコレクションを Java コレクションのコンストラクタにそのまま渡すだけで変換できます。
user> (comment "Clojure のベクタから Java のリストへ") nil user> (def jl (ArrayList. [1 2 3 5 7 8 9])) #<Var@52efcd0: [1 2 3 5 7 8 9]> user> (class jl) java.util.ArrayList user> (comment "Clojure のベクタから Java のセットへ") nil user> (def js (TreeSet. [1 1 2 3 4 4 4 9])) #<Var@6f53ce56: #{1 2 3 4 9}> user> (class js) java.util.TreeSet
くわえて、Clojure のマップは j.u.Map を実装しているので、そのまま Java のマップのコンストラクタに渡すことができます。
user> (import 'java.util.HashMap) java.util.HashMap user> (def jm (HashMap. {"foo" 1, "bar" 2, "baz" 1})) #<Var@bbc8803: {"bar" 2, "baz" 1, "foo" 1}> user> (class jm) java.util.HashMap
おわりに
Java のコレクションがシーケンスっぽいこと
Java のコレクションは into で Clojure のコレクションに変換できること
Clojure のコレクションは Java コレクションのコンストラクタで Java のコレクションに変換できること
をみてきました。この特長のおかげで、Java のコレクションインタフェースを理解した「お行儀のよい」ライブラリであれば Clojure で簡単に扱うことができます。
Footnotes:
1
`java.util.*` のコレクションクラス















