Tuesday, June 9, 2015

Today I learned... JavaConverters vs. JavaConversions

I have some Scala code that interops with Java code. I had previously used

import scala.collection.JavaConversions._

to support auto-conversion of collections, allowing me to call a method expecting a Java collection by passing it a Scala collection, and the other way around.

Today I refactored my code so this conversion happens explicitly.

I got rid of the JavaConversions import and instead added this:

import scala.collection.JavaConverters._

Then whenever I need code that expects a Java collection but I have a Scala collection, I call myScalaCollection.asJava, and when I do it the other way around, I call myJavaCollection.asScala.

It's less verbose and perhaps less magical, but I think it's easier to read the code and see what is going on. I'm controlling the conversion instead of letting the compiler do it for me, so I can be aware of any performance issues, etc. of possibly converting something back and forth needlessly.

There are some limitations. When you have a Scala queue, for example, a scala.collection.immutable.Queue[T], calling the implicit method .asJava converts it to a java.util.List, which is not exactly a queue! If you want a Java Queue, you'd have to new java.util.LinkedList(myScalaQueue.asJava), because LinkedList implements the Java Queue interface and takes in a java.util.List as a constructor argument.

It is also possible to implement this yourself by creating your own implicit method, e.g.:

import scala.collection.JavaConverters._
import scala.collection.Seq
import java.util.LinkedList

object ScalaSeqHelper {
  implicit class SeqImplicits(seq: Seq) {
    def asJavaLinkedList: LinkedList = {
      new LinkedList(seq.asJava)
    }
  }
}


Then if you import ScalaSeqHelper._, you can call .asJavaLinkedList on any Scala Seq (which includes the mutable and immutable Queue implementations) and get a Java LinkedList, which is also a Java Queue.

No comments:

Post a Comment