collections

Java と Scala 間のコレクションの変換

Scala と同様に、Java にも豊富なコレクションライブラリがある。両者には多くの共通点がある。例えば、両方のライブラリともイテレータ、Iterable、集合、マップ、そして列を提供する。しかし、両者には重要な違いもある。特に、Scala では不変コレクションに要点を置き、コレクションを別のものに変換する演算も多く提供している。

時として、コレクションを一方のフレームワークから他方へと渡す必要がある。例えば、既存の Java のコレクションを Scala のコレクションであるかのようにアクセスしたいこともあるだろう。もしくは、Scala のコレクションを Java のコレクションを期待している Java メソッドに渡したいと思うかもしれない。Scala は JavaConversions オブジェクトにより主要なコレクション間の暗黙の変換 (implicit conversion) を提供するため、簡単に相互運用できる。特に以下の型に関しては、双方向変換を提供する。

Iterator               <=>     java.util.Iterator
Iterator               <=>     java.util.Enumeration
Iterable               <=>     java.lang.Iterable
Iterable               <=>     java.util.Collection
mutable.Buffer         <=>     java.util.List
mutable.Set            <=>     java.util.Set
mutable.Map            <=>     java.util.Map
mutable.ConcurrentMap  <=>     java.util.concurrent.ConcurrentMap

このような変換を作動させるには、JavaConversions オブジェクトからインポートするだけでいい:

scala> import collection.JavaConversions._
import collection.JavaConversions._

これで Scala コレクションとそれに対応する Java コレクションの自動変換が行われる。

scala> import collection.mutable._
import collection.mutable._
scala> val jul: java.util.List[Int] = ArrayBuffer(1, 2, 3)
jul: java.util.List[Int] = [1, 2, 3]
scala> val buf: Seq[Int] = jul
buf: scala.collection.mutable.Seq[Int] = ArrayBuffer(1, 2, 3)
scala> val m: java.util.Map[String, Int] = HashMap("abc" -> 1, "hello" -> 2)
m: java.util.Map[String,Int] = {hello=2, abc=1}

内部では、このような変換は全ての演算を委譲する「ラッパー」オブジェクトを作ることで実現されている。そのため、Java と Scala の間でコレクションを変換してもコレクションはコピーされることはない。興味深い特性として、例えば Java 型から対応する Scala 型に変換して再び Java 型に逆変換するといった、ラウンドトリップを実行した場合、始めた時と同一のオブジェクトが返ってくるというものがある。

Scala コレクションの中には、Java 型に変換できるが、逆変換はできないというものもある。それらは以下の通り:

Seq           =>    java.util.List 
mutable.Seq   =>    java.utl.List
Set           =>    java.util.Set 
Map           =>    java.util.Map 

Java は可変コレクションと不変コレクションを型で区別しないため、例えば scala.immutable.List からの変換は、上書き演算を呼び出すと UnsupportedOperationException を発生する java.util.List を返す。次に具体例で説明する:

scala> jul = List(1, 2, 3)
jul: java.util.List[Int] = [1, 2, 3]
scala> jul.add(7)
java.lang.UnsupportedOperationException
        at java.util.AbstractList.add(AbstractList.java:131)