scalabeginner

Java Interop and Collections

Work with Java libraries from Scala: collection conversions, null safety, and API wrapping.

scala
import scala.jdk.CollectionConverters.*
import scala.jdk.OptionConverters.*
import java.util.{ArrayList, HashMap, Optional, Properties, Collections}
import java.nio.file.{Files, Path, Paths}
import java.time.{LocalDate, LocalDateTime}
import java.util.stream.Collectors

@main def run(): Unit =
  // ---- Collection Conversions ----
  // Scala -> Java
  val scalaList = List(1, 2, 3, 4, 5)
  val javaList: java.util.List[Int] = scalaList.asJava
  println(s"Java list: $javaList")

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

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

  // Java -> Scala
  val jList = new ArrayList[String]()
  jList.add("hello")
  jList.add("world")
  val sList: scala.collection.mutable.Buffer[String] = jList.asScala
  println(s"Scala buffer: $sList")

  val jMap = new HashMap[String, Int]()
  jMap.put("x", 10)
  jMap.put("y", 20)
  val sMap: scala.collection.mutable.Map[String, Int] = jMap.asScala
  println(s"Scala map: $sMap")

  // ---- Optional Conversions ----
  val jOptional: Optional[String] = Optional.of("hello")
  val sOption: Option[String] = jOptional.toScala
  println(s"\nOptional -> Option: $sOption")

  val sOpt: Option[Int] = Some(42)
  val jOpt: Optional[Int] = sOpt.toJava
  println(s"Option -> Optional: $jOpt")

  val empty: Option[String] = Optional.empty[String]().toScala
  println(s"Empty: $empty")

  // ---- Null Safety ----
  def nullSafe(s: String | Null): Option[String] =
    Option(s)  // None if null

  println(s"\nnullSafe(null): ${nullSafe(null)}")
  println(s"nullSafe(\"hi\"): ${nullSafe("hi")}")

  // ---- Java Streams -> Scala ----
  val numbers = java.util.stream.IntStream.range(1, 11)
  val doubled = numbers.boxed().iterator().asScala
    .map(_ * 2)
    .toList
  println(s"\nDoubled: $doubled")

  // ---- Java Time API ----
  val now = LocalDateTime.now()
  val tomorrow = LocalDate.now().plusDays(1)
  println(s"\nNow: $now")
  println(s"Tomorrow: $tomorrow")

  // ---- Properties ----
  val props = Properties()
  props.setProperty("host", "localhost")
  props.setProperty("port", "8080")
  val propsMap: Map[String, String] = props.asScala.toMap
  println(s"\nProperties: $propsMap")

  // ---- Using Java APIs idiomatically ----
  // Wrap Java API returning null
  def findEnv(key: String): Option[String] =
    Option(System.getenv(key))

  println(s"\nHOME: ${findEnv("HOME")}")
  println(s"FAKE: ${findEnv("FAKE_VAR_XYZ")}")

  // Files
  val tmpDir = Files.createTempDirectory("scala-test")
  val tmpFile = tmpDir.resolve("test.txt")
  Files.writeString(tmpFile, "Hello from Scala!")
  val content = Files.readString(tmpFile)
  println(s"\nFile: $content")
  Files.delete(tmpFile)
  Files.delete(tmpDir)

Use Cases

  • Using Java libraries from Scala
  • Collection conversion for interop
  • Null-safe Java API wrapping

Tags

Related Snippets

Similar patterns you can reuse in the same workflow.