00.scala2014. 3. 28. 13:34
반응형

While working on a new Scala application, I just ran into a situation where a Java class I was using returned a Java List to me. I wasn't exactly thinking too hard at that moment, and didn't realize it was actually a Java List until I tried to use the foreach method on it, and Eclipse balked at me.

Suddenly I ran into a common problem in Scala: When you're using Java classes from Scalaapplications, those Java class will return Java collections. You can then either use them as the Java collections that they are (such as using a Java Iterator), or cast them to Scala collections.

Easily converting Java collections to Scala collections

Amazingly, to use methods like foreach, map, filter, find, and so on with my Java List, all I had to do was add this one import statement to my Scala application:

import scala.collection.JavaConversions._

Once I did that, I could suddenly use a foreach method on my List.

Let's take a quick look at how this works with the Scala command line tool (the Scala REPL). First, we'll create a java.util.List as normal, and see what the REPL shows:

scala> var list = new java.util.ArrayList[Int]()
list: java.util.ArrayList[Int] = []

scala> list.add(1)
res1: Boolean = true

scala> list.add(2)
res2: Boolean = true

Now, if I try to use the foreach method on the Java list, it will fail, as expected:

scala> list.foreach
<console>:9: error: value foreach is not a member of java.util.ArrayList[Int]
             list.foreach
                   ^

However, if I now add the magic JavaConversions import statement to my Scala code:

import scala.collection.JavaConversions._

I can then "magically" use the foreach method on my Java List object:

list.foreach { i => println(i) }
1
2

Scala, Java List, foreach, map, filter - How it works

I just started learning Scala in 2011, and it looks like programmers long before me realized the need for the Java to Scala collection conversions, and added this functionality in Scala 2.8. I haven't dug into the source code behind the scenes to see how this magic works, but I just found a nice discussion of the background at the Graham Hacking Scala website.

Graham mentions several interesting points in that article, including these notes:

If we look a bit further into the Scala API, we'll see that there's also a trait called Seq, which is a slightly better parallel to Java's List than the Iterable or Traversable traits. So what you really want to end up with when you bring your Java List into your Scala code is a Scala Seq, not a Scala List.

Conversions between Java and Scala collections with JavaConversions

While I'm on this topic, I'll conclude with a few links to the Scala website, where you can find more information:

As you can see from that second link, the JavaConversions object currently supports the following Java to Scala collections conversions:

scala.collection.Iterable <=> java.lang.Iterable
scala.collection.Iterable <=> java.util.Collection
scala.collection.Iterator <=> java.util.{ Iterator, Enumeration }
scala.collection.mutable.Buffer <=> java.util.List
scala.collection.mutable.Set <=> java.util.Set
scala.collection.mutable.Map <=> java.util.{ Map, Dictionary }
scala.collection.mutable.ConcurrentMap <=> java.util.concurrent.ConcurrentMap

Important for my current project, the following one-way conversions are also offered:

scala.collection.Seq         => java.util.List
scala.collection.mutable.Seq => java.util.List
scala.collection.Set         => java.util.Set
scala.collection.Map         => java.util.Map
java.util.Properties         => scala.collection.mutable.Map[String, String]

In summary, I hope this brief tutorial on converting Java collections, such as a List, to Scala collections, has been helpful.

Posted by 1010