Sponsored Link •
|
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
:
... import scala.collection.mutable.{Set => MutableSet} import java.util.{Set => JavaSet} import scala.collection.JavaConversions._ class GetGadgets(val ids: java.lang.Iterable[Id[Gadget]]) extends Getter[JavaSet[GadgetView]] { def gadgets: MutableSet[Gadget] = repo.find(Gadget.ID, ids) override def exec = gadgets map { g => g view false } }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:
import java.util.{Map => JavaMap} import scala.collection.JavaConversions._ class EntityIdentity {... def allProperties: Map[String, String] = Map("shortName" -> entityNameShortForm, "longName" -> etityNameLongForm, "emailSuffix" -> emailSuffix, "domainName" -> domainName) def allPropertiesForJava: JavaMap[String, String] = allPropertiesThis may be a little bit awkward, but still writing code in Java is a temporary nuisance, right?
Have an opinion? Be the first to post a comment about this weblog entry.
If you'd like to be notified whenever Vlad Patryshev adds a new entry to his weblog, subscribe to his RSS feed.
Vlad Patryshev was born in Russia, graduated from Leningrad University, majoring in Algebra; His studies combined practical programming with interests in category and topos theory. He spent 7 years at Borland, 3.5 years at Google, and is now at Telenav, investigating the brave new mobile world. |
Sponsored Links
|