Scala with Java Interop
Scala runs on the JVM and compiles to the same bytecode as Java. This means Scala and Java can call each other directly — no wrappers, no translation layer, no performance cost. You can use any Java library from Scala code, and you can call Scala code from Java projects. This interoperability is one of Scala's biggest practical advantages.
Using Java Libraries from Scala
// Java's standard library works directly in Scala
import java.util.{ArrayList, HashMap, Date}
import java.time.{LocalDate, LocalDateTime}
import java.io.{File, FileReader, BufferedReader}
import java.net.URL
// Java ArrayList
val javaList = new ArrayList[String]()
javaList.add("Scala")
javaList.add("Java")
javaList.add("Kotlin")
println(javaList.get(0)) // Scala
println(javaList.size()) // 3
// Java HashMap
val javaMap = new HashMap[String, Int]()
javaMap.put("a", 1)
javaMap.put("b", 2)
println(javaMap.get("a")) // 1
// Java time API
val today = LocalDate.now()
println(today) // 2024-07-15 (current date)
val dateTime = LocalDateTime.now()
println(dateTime.getHour) // current hour
Converting Between Scala and Java Collections
Scala and Java collections are different types. Use scala.jdk.CollectionConverters to convert between them:
import scala.jdk.CollectionConverters._
// Scala → Java
val scalaList = List("a", "b", "c")
val javaList = scalaList.asJava // java.util.List[String]
val scalaMap = Map("x" -> 1, "y" -> 2)
val javaMap = scalaMap.asJava // java.util.Map[String, Int]
val scalaSet = Set(1, 2, 3)
val javaSet = scalaSet.asJava // java.util.Set[Int]
// Java → Scala
val backToScala: List[String] = javaList.asScala.toList
val backToMap: Map[String, Int] = javaMap.asScala.toMap
println(backToScala) // List(a, b, c)
println(backToMap) // Map(x -> 1, y -> 2)
Scala List ──asJava──► java.util.List
◄─asScala──
Scala Map ──asJava──► java.util.Map
◄─asScala──
Calling Java Methods from Scala
// Java String methods work directly on Scala Strings
val s = "Hello, World!"
s.toUpperCase() // Java method
s.substring(7) // Java method
s.indexOf("W") // Java method: 7
s.replace("World", "Scala") // Java method
// Java Math
val sqrt = java.lang.Math.sqrt(144.0) // 12.0
val abs = java.lang.Math.abs(-42) // 42
val max = java.lang.Math.max(10, 20) // 20
// Java StringBuilder
val sb = new java.lang.StringBuilder()
sb.append("Hello")
sb.append(", ")
sb.append("World")
println(sb.toString) // Hello, World
Implementing Java Interfaces in Scala
import java.util.Comparator
// Implement Java Comparator interface in Scala
val byLength: Comparator[String] = (s1: String, s2: String) =>
s1.length.compareTo(s2.length)
val words = new java.util.ArrayList[String]()
words.add("banana")
words.add("fig")
words.add("apple")
words.add("kiwi")
java.util.Collections.sort(words, byLength)
println(words) // [fig, kiwi, apple, banana]
// Implement Runnable
val task: Runnable = () => println("Running in a thread!")
val thread = new Thread(task)
thread.start()
Using Scala from Java
// Scala object and class
object ScalaUtils:
def greet(name: String): String = s"Hello, $name!"
def square(n: Int): Int = n * n
// In Java code:
// String msg = ScalaUtils.greet("Alice"); // ScalaUtils$.MODULE$.greet("Alice")
// int sq = ScalaUtils.square(5);
// For better Java interop, use @JvmStatic:
object BetterUtils:
@main def nothing(): Unit = ()
@annotation.static
def greet(name: String): String = s"Hello, $name!"
// Now Java can call: BetterUtils.greet("Alice")
Handling Java null in Scala
import java.util.{HashMap, Optional}
val javaMap = new HashMap[String, String]()
javaMap.put("key1", "value1")
// Java .get() can return null
val result: String = javaMap.get("missing") // null in Java!
// Wrap with Option to make it safe
val safe: Option[String] = Option(javaMap.get("missing")) // None
val found: Option[String] = Option(javaMap.get("key1")) // Some("value1")
println(safe) // None
println(found) // Some(value1)
// Java Optional ↔ Scala Option
val javaOpt: java.util.Optional[String] = java.util.Optional.of("hello")
val scalaOpt: Option[String] = javaOpt.toScala // import scala.jdk.OptionConverters._
Scala Annotations for Java Interop
import scala.annotation.varargs
import scala.beans.BeanProperty
class Person(@BeanProperty var name: String, @BeanProperty var age: Int)
// Generates Java-style getName(), setName(), getAge(), setAge()
// From Java: person.getName(), person.setAge(30)
class Logger:
@varargs
def log(messages: String*): Unit =
messages.foreach(println)
// From Java: logger.log("a", "b", "c") — works as Java varargs
Popular Java Libraries in Scala Projects
Java Library Use in Scala projects
─────────────────── ──────────────────────────────────────
Apache Commons String utils, I/O, math
Google Guava Collections, caching, concurrency
Jackson JSON serialization
Log4j / SLF4J Logging
JDBC drivers Database connectivity
Spring (some parts) Dependency injection
JUnit Testing (though ScalaTest is preferred)
Practical: Calling a Java I/O Library
import java.nio.file.{Files, Paths}
import java.nio.charset.StandardCharsets
import scala.jdk.CollectionConverters._
// Write using Java NIO
Files.write(
Paths.get("output.txt"),
"Hello from Scala using Java NIO!".getBytes(StandardCharsets.UTF_8)
)
// Read all lines using Java NIO → convert to Scala List
val lines: List[String] =
Files.readAllLines(Paths.get("output.txt"), StandardCharsets.UTF_8).asScala.toList
println(lines) // List(Hello from Scala using Java NIO!)
