Mixing Java and Scala code in the software

Zuleny Estaba
Analytics Vidhya
Published in
5 min readApr 3, 2020

In this article, I will show some examples of how we can mix Scala and Java code in the same software, but first, we will define what each language is for

Java is a programming language that has as its main characteristic the focus on object orientation (OO). This refers to a method of programming and design that the language can have.

Although there are many interpretations about what object orientation is, a first idea is to design the software so that the different types of data they use are linked to their operations. Thus, data and code (functions or methods) are combined into entities called objects.

As for Scala, this is a functional programming language (FP), so functions are also variable, and you can pass them on to other functions. You can write your code using OO, FP or combine them in a hybrid style. The source code for Scala is compiled into “.class” files that run on the JVM.

For some developers, Scala may initially be a complicated language, but I believe it is worth learning because being scalable provides the great advantage of being able to solve the same type of problem in different ways.

Is it possible to mix Scala and Java code?

Yes, there is the ability to mix both types of code. It is possible to create an SBT project, put Scala code in src/main/scala and java code in src/main/java in the same project and make it work.

When I have had to interact with both languages the biggest problem was the differences between their collections and libraries, normally this can be solved through the JavaConversions object. We can always find features that can be done in Scala but not in Java, so Java has certain limitations concerning Scala.

Collections to be used in a Java class of a Scala application

You’re using Java classes in a Scala application, and those classes either return Java collections or require Java collections in their method calls.

Use the methods of Scala’s JavaConversions object to make the conversions work. For instance, the java.util.ArrayList class is commonly used in Java applications, and you can simulate receiving an ArrayList from a method in the REPL, like this

def nums = {
var list = new java.util.ArrayList[Int]()
list.add(1)
list.add(2)
list
}

Even though this method is written in Scala when it’s called, it acts just as though it was returning an ArrayList from a Java method:

val list = nums
java.util.ArrayList[Int] = [1, 2]

However, because it’s a Java collection, I can’t call the foreach method:
list.foreach(println)

Error: value foreach is not a member of java.util.ArrayList[Int] list.foreach(println)

This error can be fixed by importing the JavaConversions object. This way the ArrayList above acquires the foreach method it needs to execute, generating the following output:

scala> import scala.colletion.JavaConversions._import scala.colletion.JavaConversions._scala> list.foreach(println)
1
2

Example of JavaConversions methods:

The following is an example of the getNumbers() method that we can imagine is created in a Java class

Next, imagine that we want to call the getNumbers() method from the Scala code in the following way:

val numbers = JavaExamples.getNumbers()
numbers.foreach(println) // this won’t work
//What will happen is that the compiler will generate the following error:
value ‘foreach’ is not a member of java.util.List[Integer]

This is because we must import JavaConversions.asScalaBuffer before we run it again. When we do this, we explicitly call the asScalaBuffer method

Explicit call

import scala.collection.JavaConversions.asScalaBufferval numbers = asScalaBuffer(JavaExamples.getNumbers)
numbers.foreach(println)
// prints ‘scala.collection.convert.Wrappers$JListWrapper’
println(numbers.getClass)

Implied call

import scala.collection.JavaConversions.asScalaBuffer
val numbers = JavaExamples.getNumbers
numbers.foreach(println)// prints ‘java.util.ArrayList’
println(numbers.getClass)

The println calls (numbers.getClass) show that there is a slight difference in the result between explicit and implicit uses.

Using the call to the explicit method asScalaBuffer converts the number objects into an instance of collection.convert.Wrappers $ JListWrapper, while the implicit use shows that the numbers are ArrayList.

In practice you can use either approach, depending on your preference over working with implicit conversions; both allow you to call foreach, map and other Scala sequential methods.

You can repeat the same example using a Java map and HashMap. First, create this method in a JavaExamples class:

// java public static Map getPeeps() {
Map peeps = new HashMap();
peeps.put(“captain”, “Kirk”);
peeps.put(“doctor”, “McCoy”);
return peeps; }

Then, before calling this method from your Scala code, import the corresponding JavaConversions method:

import scala.collection.JavaConversions.mapAsScalaMap

You can then call the mapAsScalaMap method explicitly, or allow it to be called implicitly:

// explicit call val peeps1 = mapAsScalaMap(JavaExamples.getPeeps)
// implicit conversion val peeps2 = JavaExamples.getPeeps

Again, there is a difference between the types of objects on the map. In this case, peeps1, which used the explicit method call, has a collection type .convert.Wrappers $ JMapWrapper, while peeps2 has a java type .util.HashMap.

Note that the JavaConversions class has gone through several changes, although you will see a large number of conversion methods in your IDE, many of them are deprecated. See the latest Scaladoc for the JavaConversions object for updated information

The Scala JavaConverters object allows you to perform conversions similar to the examples shown, although they do not offer implicit conversions. Instead, they require you to explicitly call the asJava or asScala methods to perform the conversions. Be careful, because the object also contains many obsolete methods.

Below is a list of the interoperability between the Scala and Java collections:

scala.collection.Iterable <=> java.lang.Iterablescala.collection.Iterable <=> java.util.Collectionscala.collection.Iterator <=> java.util.{ Iterator, Enumeration }scala.collection.mutable.Buffer <=> java.util.Listscala.collection.mutable.Set <=> java.util.Setscala.collection.mutable.Map <=> java.util.{ Map, Dictionary }scala.collection.mutable.ConcurrentMap <=> java.util.concurrent.ConcurrentMap

In all cases, converting from a source type to a target type and back again will return the original source object, eg.

import scala.collection.JavaConversions._val sl = new scala.collection.mutable.ListBuffer[Int]
val jl : java.util.List[Int] = sl
val sl2 : scala.collection.mutable.Buffer[Int] = jl
assert(sl eq sl2)

In addition, the following one way conversions are provided:

scala.collection.Seq => java.util.Listscala.collection.mutable.Seq => java.util.Listscala.collection.Set => java.util.Setscala.collection.Map => java.util.Mapjava.util.Properties => scala.collection.mutable.Map[String, String]

I hope this article was helpful.

Finally, we recommend visiting the following sections of the Scala api for more details on object conversion.

References

(JavaConversions) https://www.scala-lang.org/api/2.9.3/scala/collection/JavaConversions$.html

((JavaConversions) https://www.scala-lang.org/api/current/index.html#scala.collection.JavaConversions$

(JavaConverters) https://www.scala-lang.org/api/current/index.html#scala.collection.JavaConverters$

--

--

Zuleny Estaba
Analytics Vidhya

Consultant and Speaker. Currently, I’m analysis of big data technology applications. Insisting on having a positive global impact through technology.