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
Related
I'm looking at this snippet:
val here: Array[Int] = rdd.collect()
println(here.toList)
... looking at the source for toList (on TraversableOnce) and Array (Array does not inherit TraversableOnce though), but I can't find the connection that will make Scala consider an Array as a TraversableOnce - if that is even what happens. Is there some implicit at work here? Is there a conversion via ArraySeq or WrappedArray? How does that toList work?
Array does not extend TraversableOnce, but it is implicitly convertible to IndexedSeq, which does!
This means that internally, the array is converted to a WrappedArray, then toList is called on this.
See here for more info:
http://www.scala-lang.org/docu/files/collections-api/collections_38.html
I have a Play app where I'd like to read a list of integers. The Configuration object returns Option[java.util.List[java.lang.Integer]] but I'd like to return the scala type Option[List[Int]].
I have used JavaConversions to return the scala List mylist.map(_.toList).
But I'm unsure about converting the underlying element type from java.lang.Integer to Int in a neat way and without using any additional libraries.
Any ideas?
Just map the list:
import scala.collection.JavaConverters._
mylist.map(_.asScala.toList.map(_.intValue))
(it's generally recommended to prefer JavaConverters, which add toJava and toScala methods, to JavaConversions).
Scala newbie here,
I'm using stanford's topic modelling toolkit
and it has a lazy iterable of type LazyIterable[(String, Array[Double])]
How should i iterate through all the elements in this iterable say it to print all these values?
I tried doing this by
while(it.hasNext){
System.out.println(it.next())
}
Gives an error
error: value next is not a member of scalanlp.collection.LazyIterable[(String, Array[Double])]
This is the API source -> iterable_name ->
InferCVB0DocumentTopicDistributions in
http://nlp.stanford.edu/software/tmt/tmt-0.4/api/edu/stanford/nlp/tmt/stage/package.html
Based on its source code, I can see that the LazyIterable implements the standard Scala Iterable interface, which means you have access to all the standard higher-order functions that all Scala collections implement - such as map, flatMap, filter, etc.
The one you will be interested in for printing all the values is foreach. So try this (no need for the while-loop):
it.foreach(println)
Seems like method invocation problem, just check the source code of LazyIterable, look at line 46
override def iterator : Iterator[A]
when you get an instance of LazyIterable, invoke iterator method, then you can do what you want.
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)
This question already has answers here:
What is the difference between JavaConverters and JavaConversions in Scala?
(4 answers)
Closed 8 years ago.
Looking at the code in JavaConversions and JavaConverters, I am unsure which the "correct" way (with 2.10) to convert between Java and Scala collections (in either direction) is.
There seem to be lots of #deprecated annotations.
Has a definitive answer from the Scala Team (Typesafe?) been published?
Thanks,
John
This is the poster child example for the dangers of import JavaConversions._:
scala> val m = Map(1 -> "one")
m: scala.collection.immutable.Map[Int,String] = Map(1 -> one)
scala> m.contains(1)
res0: Boolean = true
scala> m.contains("")
<console>:9: error: type mismatch;
found : String("")
required: Int
m.contains("")
^
scala> import collection.JavaConversions._
import collection.JavaConversions._
scala> m.contains("")
res2: Boolean = false
Instead of issuing a type error, the compiler converts the Scala Map to to a java.util.Map, which has a looser signature that accepts Object.
I don't know of any such proclamation, but you should just always use JavaConverters, i.e. the ones that require you to indicate conversions with .asScala and .asJava.
As I understand it, JavaConverters were brought in in 2.8.1 because the JavaConversions in 2.8 were dangerous and made it easy to accidentally convert things where you weren't expecting it.
The two works in a different way:
With JavaConverters your objects will be pimped into a class which support asScala and asJava, which let you programmatically convert your collection.
With JavaConversions, a Java/Scala collection will be automatically converted when required
The risk with the latter is to obtain wrong or unnecessary conversions paying a performance
fault. Additionally, at least in Scala 2.9 there is no caching of implicit conversion, i.e. if the same conversion is applied twice inside a method, the conversion code is called twice.
When you explicitely convert a collection, if you need it in the "Java" version, you will avoid to call twice .asScala in the same method.