Skip to content
AgileLogics
5 min read

Java Interoperability

Prerequisites: Working with files

Scala compiles to JVM bytecode, so every Java library works directly.

Using Java classes

import java.time.{LocalDate, Period, DayOfWeek}
import java.util.UUID

@main def javaClasses(): Unit =
  val start = LocalDate.of(2025, 1, 15)
  val end = LocalDate.of(2025, 4, 22)
  println(Period.between(start, end))
  println(end.plusDays(10))
  println(end.getDayOfWeek == DayOfWeek.TUESDAY)
  println(UUID.nameUUIDFromBytes("ada".getBytes).toString.length)
  println(String.join(", ", "a", "b"))
P3M7D
2025-05-02
true
36
a, b

Converting collections

Java APIs return Java collections; convert at the boundary:

import scala.jdk.CollectionConverters.*

@main def converters(): Unit =
  val javaList = java.util.ArrayList[String]()
  javaList.add("x")
  javaList.add("y")

  val scalaList: List[String] = javaList.asScala.toList
  println(scalaList.map(_.toUpperCase))

  val backToJava: java.util.List[Int] = List(1, 2, 3).asJava
  println(backToJava.size())
  println(Map("a" -> 1).asJava.get("a"))
List(X, Y)
3
1

null from Java

Java methods may return null. Wrap such results in Option(...), which turns null into None:

@main def nulls(): Unit =
  val env = System.getenv("SURELY_NOT_SET_12345")
  println(env)
  println(Option(env).getOrElse("default"))
  println(Option(System.getProperty("java.version")).isDefined)
null
default
true

Calling Scala from Java

Scala classes are visible to Java too. A few tips keep them friendly: use @main or an object with def main, annotate varargs methods with @varargs, avoid Scala-only features (like default parameters and givens) in public APIs meant for Java, and offer Java collection types at the boundary.

What's next

Try the Intermediate Projects, then continue to Level 3 — Advanced: givens and type classes, advanced types, concurrency, and production Scala.