पाठ 23 / 25
Java Interoperability
Call Java from Scala and convert collections, nulls and checked exceptions.
Using the Java ecosystem
Scala compiles to JVM bytecode, so any Java library can be used directly: import the classes, construct objects and call methods as usual. A few differences need care. Nulls: Java APIs may return null, so wrap results with Option(value); Scala 3's optional explicit-nulls mode makes nullability visible in types. Collections: convert with import scala.jdk.CollectionConverters.*, then javaList.asScala and scalaList.asJava. Functional interfaces: Scala lambdas convert automatically to Java SAM types such as Runnable, Comparator and java.util.function.Function. Checked exceptions do not exist in Scala; Java exceptions propagate normally, so wrap risky calls in Try or Using. scala.util.Using manages AutoCloseable resources like try-with-resources. Annotations such as @throws and @BeanProperty help Java callers. Java streams convert with scala.jdk.StreamConverters, and CompletableFuture converts to Future with scala.jdk.FutureConverters. Modern JDK features such as virtual threads (Java 21) are available from Scala too.
Calling Java APIs safely
Collection conversion, Option for nulls, Using for resources.
import scala.jdk.CollectionConverters.*
import scala.util.{Try, Using}
import java.nio.file.{Files, Path}
import java.time.{LocalDate, ZoneId}
import java.util.concurrent.Executors
val javaList: java.util.List[String] = java.util.List.of("pune", "delhi")
val cities: List[String] = javaList.asScala.toList.map(_.capitalize)
val backToJava: java.util.List[String] = cities.asJava
val home: Option[String] = Option(System.getenv("APP_HOME")) // null becomes None
val lineCount: Try[Int] = Using(Files.newBufferedReader(Path.of("orders.csv"))) { reader =>
reader.lines().count().toInt // reader is always closed
}
val today = LocalDate.now(ZoneId.of("Asia/Kolkata"))
val sorted = new java.util.ArrayList[String](javaList)
sorted.sort((a, b) => b.compareTo(a)) // a Scala lambda as a Java Comparator
val executor = Executors.newVirtualThreadPerTaskExecutor() // JDK 21+ virtual threads
try
val job: java.util.concurrent.Callable[String] = () => s"report for $today"
val task = executor.submit(job) // typed Callable avoids overload ambiguity
println(task.get())
finally executor.shutdown()A bilingual colleague
Scala is a bilingual colleague who reads every Java document fluently. They just translate a few habits: "might be null" becomes "maybe" (Option), and Java lists become Scala lists before working with them.
त्वरित जाँच: How should you handle a Java method that may return null?
- Call methods on it directly
- Wrap it with Option(value) so null becomes None
- Catch NullPointerException everywhere
- Convert it to a String
Answer
Wrap it with Option(value) so null becomes None — Option(x) converts null to None and anything else to Some(x).