How to use scala.collection.immutable.List in a Java code
Use scala.collection.JavaConversions from inside of java.
For example to create a nested scala case class that requires a scala List in its constructor:
case class CardDrawn(player: Long, card: Int)
case class CardSet(cards: List[CardDrawn])
From Java you can use asScalaBuffer(x).toList() as follows:
import scala.collection.JavaConversions;
import java.util.ArrayList;
import java.util.List;
public CardSet buildCardSet(Set<Widget> widgets) {
List<CardDrawn> cardObjects = new ArrayList<>();
for( Widget t : widgets ) {
CardDrawn cd = new CardDrawn(t.player, t.card);
cardObjects.add(cd);
}
CardSet cs = new CardSet(JavaConversions.asScalaBuffer(cardObjects).toList());
return cs;
}
What an horrible comparison! I'll leave it to others to explain how to accomplish what you want, but here's a few reasons why this shouldn't even be tried:
- Scala's
List
is a persistent, immutable collection,ArrayList
is a mutable collection;- That means
ArrayList
must be copied before passed to methods that may change it, if the content must be preserved, while no such thing is necessary withList
; - It also mean that
ArrayList
support operations not possible inList
;
- That means
List
has constant-time prepend,ArrayList
has amortized constant-time append. Both have linear time the other operation.ArrayList
has constant-time indexed access,List
has linear time indexed access, which is not the intended mode of use anyway;List
should be used through self-traversing methods, such asforeach
,map
andfilter
, which use closures,ArrayList
is externally traversed through an iterator or index.
So, basically, each suck at the other's efficient operations, and the very algorithms used with one shouldn't be used with the other. Let's consider the very benchmark you propose:
create a scala List and add say 100 random numbers to it
You don't add elements to a Scala List
-- it is immutable. You create a new List
based on an existing List
and a new element. In the end, you'll have 100 different lists (of sizes 1 to 100), all of which can be used without changing the other. Meanwhile, if you add 100 elements to an ArrayList
, you'll have one ArrayList
of size 100. So, whatever the time difference is, each operation did something different.
Edit
I'm posting here a slightly different version of naten's code, which uses a method on List
itself to prepend an element, instead of calling a factory.
import scala.collection.immutable.*;
public class Foo {
public List test() {
List nil = Nil$.MODULE$; // the empty list
List one = nil.$colon$colon((Integer) 1); // 1::nil
List two = one.$colon$colon((Integer) 2); // 2::1::nil
System.out.println(one);
System.out.println(two);
return two;
}
}
And, in answer to your question to him, $colon$colon
is how Scala represents the method ::
in the JVM, that being the method used to prepend elements. Also, that method binds to the right instead of the left, reflecting the nature of the operation, which is why the comment is 1::nil
instead of nil::1
.
The empty list, Nil$.MODULE$
, is referenced instead of created anew because it's a singleton -- there's no way to create an empty list.
It's easier to use Java collections in Scala than the other way around, but since you asked:
import scala.collection.immutable.*;
public class foo {
public List test() {
List nil = Nil$.MODULE$; // the empty list
$colon$colon one = $colon$colon$.MODULE$.apply((Integer) 1, nil); // 1::nil
$colon$colon two = $colon$colon$.MODULE$.apply((Integer) 2, one); // 2::1::nil
System.out.println(one);
System.out.println(two);
return two;
}
}
This compiles with javac with scala-library.jar in the classpath:
javac -classpath /opt/local/share/scala-2.9/lib/scala-library.jar foo.java
You can invoke from the Scala REPL:
scala> (new foo).test
List(1)
List(2, 1)
res0: List[Any] = List(2, 1)
To use a Java collection from Scala, you don't have to do anything special:
scala> new java.util.ArrayList[Int]
res1: java.util.ArrayList[Int] = []
scala> res1.add(1)
res2: Boolean = true
scala> res1
res3: java.util.ArrayList[Int] = [1]