# Java Interoperability — Scala

Source: https://www.geekswithgeeks.com/en/scala/s-java

> 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.

```scala
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.

**Quiz:** How should you handle a Java method that may return null?

- [ ] Call methods on it directly
- [x] 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).
