Summary
While Scala can work with Java collections, and Java, more or less, can work with Scala collections, for sanity sake they better should be kept separate. So how do Java and Scala code exchange collections?
Advertisement
If you try to combine Java code with Scala in your application, everything seems to go fine until you bump into big differences between Java collections and Scala collections. A Scala Traversable is not Java Iterable and vice versa; maps are different, etc. So, in practice, you have to do conversion.
Fortunately, there are pretty good implicit converters in Scala 2.8; what remains is to use them properly.
I'll show a couple of pretty self-explaining examples here.
Here our Scala code returns a Set to Java:
package com.company.user
import java.util.{Set => JavaSet}
import scala.collection.JavaConversions._
class GetAllGadgets(withHistory: Boolean) extends Getter[JavaSet[GadgetView]] {
overide def execute = allGadgets map { g => g view withHistory }
}
process is declared in (a Java interface) as returning JavaSet; so an implicit conversion is applied to the set produced by mapping allGadgets using g => g.view(withHistory) transformation.
Here's how a unittest may look like:
final Gadget gadget = new Gadget("test gadget");
GetAllGadgets query = new GetAllGadgets(true);
Mockery mockery = new Mockery();
final GadgetStorage storage = mockery.mock(GadgetStorage.class);
query.setStorage(storage);
mockery.checking(new Expectations() {{
one(storage).allGadgets(); will(returnValue(Sets.newHashSet(gadget)));
}});
Set<GadgetView> result = query.exec();
assertEquals(1, result.size());
assertEquals("test gadget", result.iterator().next().getName());
In the following example, the Scala class takes a Java Iterable and returns a Java Set:
What happens here: we explicitly show that we accept a Java Iterable, but all other conversions are implicit.
First, storage.find(Gadget.ID, ids) is a Java code; it returns a Java Set. This set is implicitly transformed into scala.collection.mutable.Set, known in the code under an alias of MutableSet, for clarity.
Then process transform the set into a set of views, same as in the previous example - and converts the result, implicitly, to java.util.Set, just because such is the signature of the method process.
A Java programmer would probably complain about not having the result of process explicitly defined right here. Well... the language is Scala, not Java. Wind of change.
In an unfortunate case when we need both Scala and Java collections, we will have to declare two methods, like in the example below: