Convert Scala Set into Java (java.util.Set)? - scala

I have a Set in Scala (I can choose any implementation as I am creating the Set. The Java library I am using is expecting a java.util.Set[String].
Is the following the correct way to do this in Scala (using scala.collection.jcl.HashSet#underlying):
import com.javalibrary.Animals
var classes = new scala.collection.jcl.HashSet[String]
classes += "Amphibian"
classes += "Reptile"
Animals.find(classes.underlying)
It seems to be working, but since I am very new to Scala I want to know if this is the preferred way (any other way I try I am getting a type-mismatch error):
error: type mismatch;
found : scala.collection.jcl.HashSet[String]
required: java.util.Set[_]

If you were asking about Scala 2.8, Java collections interoperability is supplied by scala.collection.JavaConversions. In this case, you want JavaConversions.asSet(...) (there's one for each direction, Java -> Scala and Scala -> Java).
For Scala 2.7, each scala.collection.jcl class that wraps a Java collection has an underlying property which provides the wrapped Java collection instance.

Since Scala 2.12.0 scala.collection.JavaConversions is deprecated:
Therefore, this API has been deprecated and JavaConverters should be used instead. JavaConverters provides the same conversions, but through extension methods.
And since Scala 2.8.1 you can use scala.collection.JavaConverters for this purpose:
import scala.collection.JavaConverters._
val javaSet = new java.util.HashSet[String]()
val scalaSet = javaSet.asScala
val javaSetAgain = scalaSet.asJava

For 2.7.x I highly recommend using: http://github.com/jorgeortiz85/scala-javautils

Note that starting Scala 2.13, package scala.jdk.CollectionConverters replaces deprecated packages scala.collection.JavaConverters/JavaConversions._:
import scala.jdk.CollectionConverters._
// val scalaSet: Set[String] = Set("a", "b")
val javaSet = scalaSet.asJava
// javaSet: java.util.Set[String] = [a, b]
javaSet.asScala
// scala.collection.mutable.Set[String] = Set(a, b)

In Scala 2.12 it is possible to use : scala.collection.JavaConverters.setAsJavaSet(scalaSetInstance)

Related

Error while importing scala.collection.breakOut

I am getting this error in IntelliJ:
object breakOut is not a member of package collection
import scala.collection.{breakOut, mutable}
Can you suggest me which package I should add or if the can share the code for breakOut class maybe defining it will work ?
breakOut was in the Scala standard library until Scala 2.13. You shouldn't need to depend on any additional libraries. In Scala 2.13 and later, you should remove that parameter and explicitly convert to the required type, e. g. using toList, toMap, toSet or whatever it is that's required.

Does Scala's JavaConverters produce incomplete result?

Following code converts Scala List into java.util.List (Tested in Scala 2.11)
import scala.collection.JavaConverters._
val a = List(1, 2, 3)
val b = a.asJava
However, the conversion result seems incomplete. Because some methods in java.util.List do not work.
scala> b.remove(2)
java.lang.UnsupportedOperationException
at java.util.AbstractList.remove(AbstractList.java:161)
... 29 elided
My workaround is as follows:
val c = new java.util.ArrayList(a.asJava)
This works but seems redundant in API-design perspective.
Is this the correct way of using asJava method?
Why does Scala's JavaConverters produce incomplete result?
Because some methods in java.util.List do not work.
These methods are explicitly optional, because java.util.List covers both mutable and immutable lists, and some of implementations in Java standard library don't support them either:
Removes the first occurrence of the specified element from this list, if it is present (optional operation)...
Throws: ... UnsupportedOperationException - if the remove operation is not supported by this list
Same for other Java collection interfaces. So the result does completely satisfy the interface.
It appears that what you're getting from the asJava is an immutable list, as you've started with an immutable Scala list. Try the following
val a = List(1,2,3).to[scala.collection.mutable.ListBuffer].asJava

How to get a list with the Typesafe config library

I'm trying in Scala to get a list from a config file like something.conf with TypeSafe.
In something.conf I set the parameter:
mylist=["AA","BB"]
and in my Scala code I do:
val myList = modifyConfig.getStringList("mylist")
Simple configuration parameters works fine but could somebody give me an example of how to extract a list?
As #ghik notes, the Typesafe Config library is Java based, so you get a java.util.List[String] instead of a scala.List[String]. So either you make a conversion to a scala.List:
import collection.JavaConversions._
val myList = modifyConfig.getStringList("mylist").toList
Or (probably less awkward) you look for a Scala library. The tools wiki links at least to these maintained libraries:
Configrity
Bee Config
(Disclaimer: I don't use these, so you will have to check that they support your types and format)
For the record, since Scala 2.12 JavaConversions are deprecated so you can:
import collection.JavaConverters._
val myList: List[String] = modifyConfig.getStringList("mylist").asScala.toList
You can try my scala wrapper https://github.com/andr83/scalaconfig - it supports reading native scala types directly from config object. In your case it will look:
val myList = modifyConfig.as[List[String]]("mylist")
Starting Scala 2.13, the standard library provides Java to Scala implicit list conversions via scala.jdk.CollectionConverters:
import scala.jdk.CollectionConverters._
val myList: List[String] = conf.getStringList("mylist").asScala.toList
This replaces deprecated packages scala.collection.JavaConverters/JavaConversions.

How to convert a Java TreeMap to a Scala SortedMap?

Following along with chapters and examples in "Scala for the Impatient", there's an exercise related to using a Java TreeMap as a Scala SortedMap. In the scala shell, I tried this:
var t: scala.collection.SortedMap[String,Int] = new java.util.TreeMap[String,Int]()
but I get an error message about type mismatch. Is there a simple way to do this?
Note: I did an import of scala.collection.JavaConversions._ and then did this:
var t: SortedMap[String,Int] = TreeMap[String,Int]()
This works, but variable t has type java.util.SortedMap, not scala.collection.SortedMap.
I haven't read that book, but you need to make your mind up. Is t a Scala SortedMap or is it a Java TreeMap?
A TreeMap isn't a SortedMap, so you can't assign one to a SortedMap variable without converting it. JavaConversions will do some conversions for you, including:
implicit def mapAsScalaMap [A, B] (m: Map[A, B]): Map[A, B]
Implicitly converts a Java Map to a Scala mutable Map.
However there's nothing to convert to a SortedMap.
If this conversion seems mysterious to you, the library designers would agree, so JavaConversions is deprecated in Scala 2.10, in favour of JavaConverters, which requires a specific .asScala method to do a conversion.
Unfortunately JavaConverters doesn't have anything to produce a SortedMap either (.asScala gives you a mutable.Map). So you need to rebuild the collection using its elements.
import collection.JavaConverters._
import collection.SortedMap
var t: SortedMap[String, Int] =
SortedMap[String, Int]() ++ new java.util.TreeMap[String,Int].asScala
Producing a new TreeMap in the code above is obviously a bit pointless because it's empty, but you should get the idea of how to deal with an existing one. If you don't have an existing one, just produce a new SortedMap in Scala.
import collection._
import JavaConverters._
var t: scala.collection.SortedMap[String,Int] =
new java.util.TreeMap[String,Int]().asScala.map(identity)(breakOut)

toArray in Scala 2.10 Milestone

The following Scala code works fine in Scala 2.9, but it generates compiler error in Scala 2.10 Milestone. Can anybody give me a hint how to create an ArrayTag:
type Lit = Array[Int]
var list = List[Lit].empty
list ::= Array(1,2,3)
list ::= Array(4,5)
val arr = list.toArray
Error message in Scala 2.10 is "No ArrayTag available for Lit".
Also, should I always create a new ArrayTag for new types?
Thank you.
That's a bug, I've lodged it: https://issues.scala-lang.org/browse/SI-5769