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:

  1. Scala's List is a persistent, immutable collection, ArrayList is a mutable collection;
    1. 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 with List;
    2. It also mean that ArrayList support operations not possible in List;
  2. List has constant-time prepend, ArrayList has amortized constant-time append. Both have linear time the other operation.
  3. ArrayList has constant-time indexed access, List has linear time indexed access, which is not the intended mode of use anyway;
  4. List should be used through self-traversing methods, such as foreach, map and filter, 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]