JavaのListはScalaのfor文でそのまま使えない

こんなエラーで30分ハマった。foreach文使ってないのに、なんでforeachという単語がでてくるかに早く着目すべきだった。このエラーは「for文で使える型じゃないよ」という意味合いのようです。

value foreach is not a member of java.util.Set[String]

実際にエラーがでたコード

import com.mongodb.Mongo
import com.mongodb.DB
import com.mongodb.DBCollection
import com.mongodb.BasicDBObject
import com.mongodb.DBObject
import com.mongodb.DBCursor

object MG {
	
	def main(args: Array[String]) = {
		val m = new Mongo("localhost", 27017)
		val db = m.getDB("mydb")
		val colls = db.getCollectionNames() //(1)
		for (s <- colls) {
			println(s)
		}
	}
	
}

MongoDBのJavaチュートリアル見てScalaで書いてたんだけど、エラーが消えない。


型がおかしいことにはすぐ気づいたので、(1)の戻り値が不明確なのかなとか思い、

val colls: java.util.Set[String]

とか型推論に頼らず、直指定で書いてみたり、import文なおしてみたりしたけどダメ。型の指定が不明確なのは関係なかったです。getCollectionNames()は、java.util.Set[String]を返すのですが、それをそのままfor文に使っちゃダメということでした。
Scalaのfor文はscala.collection.Listやscala.collection.Setでならそのまま使えるけど、java.util.Listやjava.util.Setでは使えません。
同じListでも実装が別物だし、"Scalaのfor文"なので、当然JavaAPIに合わせてるわけじゃなく、Scala標準APIに合わせているはずですよね。


この場合、JavaのListをScalaのListへと変換してあげる必要があります。

import com.mongodb.Mongo
import com.mongodb.DB
import com.mongodb.DBCollection
import com.mongodb.BasicDBObject
import com.mongodb.DBObject
import com.mongodb.DBCursor
import scala.collection.JavaConversions._ //(2)

object MG {
	
	def main(args: Array[String]) = {
		val m = new Mongo("localhost", 27017)
		val db = m.getDB("mydb")
		val colls = db.getCollectionNames()
		for (s <- asSet(colls)) { //(3)
			println(s)
		}
	}
	
}

(2)で変換用の関数をimportして、(3)でasSet()関数使えば解決。対象がListならasList()関数。
なお、Scala2.7系ではscala.collection.jcl.Conversionsでした。関数名も違います。2.8系からscala.collection.JavaConversionsとなったので、注意してください。