CtrlK
BlogDocsLog inGet started
Tessl Logo

tessl/maven-org-scala-lang-modules--scala-collection-compat

A library that makes some Scala 2.13 APIs available on Scala 2.11 and 2.12, facilitating cross-building Scala 2.13 and 3.0 code on older versions

Pending
Overview
Eval results
Files

java-interop.mddocs/

Java Collection Interoperability

Seamless bidirectional conversion between Scala and Java collections, enabling smooth interoperation with Java libraries and frameworks.

CollectionConverters Object

object CollectionConverters extends DecorateAsJava with DecorateAsScala

The main entry point for collection conversions, combining Java-to-Scala and Scala-to-Java conversion capabilities.

Core Import

import scala.jdk.CollectionConverters._

This import provides implicit extension methods for converting between Scala and Java collection types.

Scala to Java Conversions

DecorateAsJava Conversions

The following extension methods are available on Scala collections:

Iterable Conversions

// Extension methods added by DecorateAsJava
implicit class IterableHasAsJava[A](it: Iterable[A]) {
  def asJava: java.lang.Iterable[A]
}

implicit class BufferHasAsJava[A](b: mutable.Buffer[A]) {
  def asJava: java.util.List[A]
}

implicit class MutableSeqHasAsJava[A](seq: mutable.Seq[A]) {
  def asJava: java.util.List[A]
}

implicit class SeqHasAsJava[A](seq: Seq[A]) {
  def asJava: java.util.List[A]
}

implicit class MutableSetHasAsJava[A](s: mutable.Set[A]) {
  def asJava: java.util.Set[A]
}

implicit class SetHasAsJava[A](s: Set[A]) {
  def asJava: java.util.Set[A]
}

Map Conversions

implicit class MutableMapHasAsJava[K, V](m: mutable.Map[K, V]) {
  def asJava: java.util.Map[K, V]
}

implicit class MapHasAsJava[K, V](m: Map[K, V]) {
  def asJava: java.util.Map[K, V]
}

implicit class ConcurrentMapHasAsJava[K, V](m: concurrent.Map[K, V]) {
  def asJava: java.util.concurrent.ConcurrentMap[K, V]
}

Dictionary Conversions

implicit class DictionaryHasAsJava[K, V](d: mutable.Map[K, V]) {
  def asJavaDictionary: java.util.Dictionary[K, V]
}

implicit class PropertiesHasAsScala(p: java.util.Properties) {
  def asScala: mutable.Map[String, String]
}

Java to Scala Conversions

DecorateAsScala Conversions

The following extension methods are available on Java collections:

Iterable Conversions

// Extension methods added by DecorateAsScala
implicit class IteratorHasAsScala[A](it: java.util.Iterator[A]) {
  def asScala: Iterator[A]
}

implicit class EnumerationHasAsScala[A](e: java.util.Enumeration[A]) {
  def asScala: Iterator[A]
}

implicit class IterableHasAsScala[A](it: java.lang.Iterable[A]) {
  def asScala: Iterable[A]
}

implicit class CollectionHasAsScala[A](c: java.util.Collection[A]) {
  def asScala: Iterable[A]
}

implicit class ListHasAsScala[A](l: java.util.List[A]) {
  def asScala: mutable.Buffer[A]
}

implicit class SetHasAsScala[A](s: java.util.Set[A]) {
  def asScala: mutable.Set[A]
}

Map Conversions

implicit class MapHasAsScala[K, V](m: java.util.Map[K, V]) {
  def asScala: mutable.Map[K, V]
}

implicit class ConcurrentMapHasAsScala[K, V](m: java.util.concurrent.ConcurrentMap[K, V]) {
  def asScala: concurrent.Map[K, V]
}

implicit class DictionaryHasAsScala[K, V](d: java.util.Dictionary[K, V]) {
  def asScala: mutable.Map[K, V]
}

Usage Examples

Basic Conversions

import scala.jdk.CollectionConverters._
import java.util.{ArrayList, HashMap}

// Scala to Java
val scalaList = List(1, 2, 3, 4, 5)
val javaList: java.util.List[Int] = scalaList.asJava

val scalaMap = Map("a" -> 1, "b" -> 2)
val javaMap: java.util.Map[String, Int] = scalaMap.asJava

val scalaSet = Set("x", "y", "z")
val javaSet: java.util.Set[String] = scalaSet.asJava

// Java to Scala
val javaArrayList = new ArrayList[String]()
javaArrayList.add("hello")
javaArrayList.add("world")
val scalaBuffer = javaArrayList.asScala

val javaHashMap = new HashMap[String, Int]()
javaHashMap.put("one", 1)
javaHashMap.put("two", 2)
val scalaMutableMap = javaHashMap.asScala

Working with Java Libraries

import scala.jdk.CollectionConverters._
import java.util.stream.Collectors

// Processing with Java Streams
def processWithJavaStreams(data: List[String]): List[String] = {
  data.asJava
    .stream()
    .filter(_.startsWith("A"))
    .map(_.toUpperCase)
    .collect(Collectors.toList())
    .asScala
    .toList
}

// Using Java concurrent collections
import java.util.concurrent.ConcurrentHashMap

val concurrentMap = new ConcurrentHashMap[String, Int]()
concurrentMap.put("count", 0)

val scalaView = concurrentMap.asScala
scalaView.update("count", scalaView("count") + 1)

Interop with Java Frameworks

import scala.jdk.CollectionConverters._

// Example: Working with Spring Framework collections
class SpringService {
  import org.springframework.util.MultiValueMap
  
  def processMultiValueMap(javaMap: MultiValueMap[String, String]): Map[String, List[String]] = {
    javaMap.asScala.view.mapValues(_.asScala.toList).toMap
  }
}

// Example: Working with Jackson JSON processing
import com.fasterxml.jackson.databind.ObjectMapper

def parseJsonToScala(json: String): Map[String, Any] = {
  val mapper = new ObjectMapper()
  val javaMap = mapper.readValue(json, classOf[java.util.Map[String, Any]])
  javaMap.asScala.toMap
}

Bidirectional Data Flow

import scala.jdk.CollectionConverters._

class DataProcessor {
  // Accept Java collections, process in Scala, return Java collections
  def processData(javaInput: java.util.List[String]): java.util.Map[String, java.util.List[String]] = {
    javaInput.asScala
      .groupBy(_.charAt(0).toString)
      .view.mapValues(_.asJava)
      .toMap
      .asJava
  }
  
  // Accept Scala collections, use Java processing, return Scala collections
  def processWithJavaTools(scalaInput: List[Int]): List[Int] = {
    import java.util.Collections
    
    val javaList = scalaInput.asJava
    Collections.sort(javaList)
    Collections.reverse(javaList)
    javaList.asScala.toList
  }
}

Working with Properties

import scala.jdk.CollectionConverters._
import java.util.Properties

// Load system properties as Scala map
val systemProps: mutable.Map[String, String] = System.getProperties.asScala

// Create Properties from Scala map
val config = Map(
  "server.port" -> "8080",
  "database.url" -> "jdbc:h2:mem:test"
)

val properties = new Properties()
config.foreach { case (k, v) => properties.setProperty(k, v) }

// Or using asJavaDictionary
val scalaMap = mutable.Map("key1" -> "value1", "key2" -> "value2")
val dictionary = scalaMap.asJavaDictionary

Iterator and Enumeration Conversions

import scala.jdk.CollectionConverters._
import java.util.{Vector, StringTokenizer}

// Java Iterator to Scala Iterator
val javaVector = new Vector[String]()
javaVector.add("a")
javaVector.add("b")
javaVector.add("c")

val scalaIterator = javaVector.iterator().asScala
scalaIterator.foreach(println)

// Java Enumeration to Scala Iterator
val tokenizer = new StringTokenizer("hello,world,scala", ",")
val tokens = tokenizer.asScala.toList  // List("hello", "world", "scala")

Performance Considerations

View-Based Conversions

The conversions provided by CollectionConverters create lightweight wrappers rather than copying data:

val scalaList = List(1, 2, 3, 4, 5)
val javaList = scalaList.asJava  // No copying - creates a wrapper
val backToScala = javaList.asScala  // Also no copying

// Changes through one view affect the other (for mutable collections)
val scalaMutableList = mutable.ListBuffer(1, 2, 3)
val javaView = scalaMutableList.asJava
javaView.add(4)
println(scalaMutableList)  // ListBuffer(1, 2, 3, 4)

When to Copy

Sometimes you need to create independent copies:

import scala.jdk.CollectionConverters._

val scalaList = List(1, 2, 3)
val javaListCopy = new java.util.ArrayList(scalaList.asJava)  // Independent copy

val javaMap = new java.util.HashMap[String, Int]()
javaMap.put("a", 1)
val scalaMapCopy = javaMap.asScala.toMap  // Independent immutable copy

Migration Notes

  • In Scala 2.13+, use scala.jdk.CollectionConverters instead of the deprecated JavaConverters
  • The asJava/asScala methods create lightweight wrappers, not copies
  • For mutable collections, changes through one view affect the other
  • For independent copies, explicitly create new collections from the converted views

Install with Tessl CLI

npx tessl i tessl/maven-org-scala-lang-modules--scala-collection-compat

docs

annotation-backports.md

backported-collections.md

collection-extensions.md

collection-factories.md

index.md

iterator-size-ops.md

java-interop.md

map-extensions.md

method-chaining.md

option-converters.md

resource-management.md

string-parsing.md

tile.json