Scala 3: Using Java Collections in Scala

This is an excerpt from the Scala Cookbook, 2nd Edition. This is Recipe 3.10, Using Java Collections in Scala.

Problem

You’re using Java classes in a Scala application, and those classes either return Java collections, or require Java collections in their method calls, and you need to integrate those with your use of Scala collections.

Solution

Use the extension methods of the scala.jdk.CollectionConverters object in your Scala code to make the conversions work. For example, if you have a method named getNumbers in a public Java class named JavaCollections:

// java
public static List<Integer> getNumbers() {
    return new ArrayList<Integer>(List.of(1,2,3));
}

You can convert that Java list to a Scala Seq in your Scala code like this:

// scala
import scala.jdk.CollectionConverters._
import java.util.List

def testList =
    println("Using a Java List in Scala")
    val jlist: java.util.List[Integer] = JavaCollections.getNumbers
    // jlist.getClass is "class java.util.ArrayList"

    // note that this is `Seq[Integer]` and not `Seq[Int]`:
    val slist: Seq[Integer] = jlist.asScala.toSeq
    slist.foreach(println)

Similarly, if you have a Java method that returns a Map:

// java
public static Map<String, String> getPeeps() {
    return new HashMap<String, String>(Map.of(
        "Captain", "Kirk",
        "Mr.", "Spock"
    ));
}

You can convert that to a Scala Map like this:

// scala
import scala.jdk.CollectionConverters._
import java.util.{Map => JavaMap}
import scala.collection.mutable.{Map => ScalaMap}

@main def testMap =
    println("use a Java Map in Scala")
    val jmap: JavaMap[String,String] = JavaCollections.getPeeps
    val smap: ScalaMap[String,String] = jmap.asScala
    for (k,v) <- smap do println(s"key: '$k', value: '$v'")

Similarly, this example shows how to convert a Java Properties object to a Scala Map:

// [1] create and populate a Java Properties object
val javaProps = new java.util.Properties
javaProps.put("first_name", "Charles")
javaProps.put("last_name", "Carmichael")

// [2] convert Java Properties to Scala Map
import scala.jdk.CollectionConverters._
val scalaProps = javaProps.asScala
println(scalaProps)

The println statement in that code prints output like this:

Map(last_name -> Carmichael, first_name -> Charles)

Discussion

This recipe shows how to perform collections conversions in Scala. To perform conversions in your Java code, see the next recipe.

Type conversions

The first example in the Solution shows how to create a Scala Seq[Integer] from a Java java.util.List<Integer>:

val slist: Seq[Integer] = jlist.asScala.toSeq

Assuming that you really want a Seq[Int] — and not Seq[Integer] — you’ll need to add an Integer to Int conversion process to your code:

def integer2Int(i: Integer): Int = i

val jlist2: java.util.List[Integer] = MyJavaClass.getNumbers()
val slist2: Seq[Int] = jlist2.asScala.map(i => integer2Int(i)).toSeq

That code does the following:

  • Creates jlist2 as a java.util.List[Integer]

  • Converts that code to a Scala Buffer[Integer] using asScala

  • Converts that Buffer[Integer] to a Buffer[Int] with the map method and integer2Int function

  • Creates the final Seq[Int] with the toSeq call

Conversion methods

Code like this works because of conversion methods in the CollectionConverters object. The two-way conversions provided by the scala.jdk.CollectionConverters object shows the two-way conversions that are possible using the asScala and asJava methods.

Table 1. The two-way conversions provided by the scala.jdk.CollectionConverters object

Scala collection Java collection

scala.collection.Iterable

java.lang.Iterable

scala.collection.Iterator

java.util.Iterator

scala.collection.mutable.Buffer

java.util.List

scala.collection.mutable.Set

java.util.Set

scala.collection.mutable.Map

java.util.Map

scala.collection.concurrent.Map

java.util.concurrent.ConcurrentMap

For example, you can convert a Scala Buffer to a Java List using asJava, and perform the opposite conversion using asScala.

Additional two-way conversions, including specially-named methods shows additional two-way conversions. The conversions to Scala are supported with asScala, and the specially-named extension methods let you convert the Scala collections to Java collections.

Table 2. Additional two-way conversions, including specially-named methods

Scala collection Java collection

scala.collection.Iterable

java.util.Collection (via asJavaCollection)

scala.collection.Iterator

java.util.Enumeration (via asJavaEnumeration)

scala.collection.mutable.Map

java.util.Dictionary (via asJavaDictionary)

One-way conversions (Scala to Java) that are provided by the CollectionConverters class lists one-way conversions that are possible with asJava.

Table 3. One-way conversions (Scala to Java) that are provided by the CollectionConverters class

Scala collection Java collection

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

One-way conversions that are provided with asScala lists one-way conversions that are possible with asScala.

Table 4. One-way conversions that are provided with asScala

Scala collection Java collection

java.util.Properties

scala.collection.mutable.Map[String,String]

See Also