如何在Java代码中使用scala.collection.immutable.List

时间:2011-07-05 06:20:07

标签: java performance list scala

我需要编写一个代码来比较Java ArrayList与Scala List的性能。我很难让Scala List使用我的Java代码。有人可以发布一个真正简单的“hello world”示例,说明如何在java代码中创建Scala List(在.java文件中)并添加100个随机数吗?

PS:我非常擅长Java,但从未使用过Scala。

4 个答案:

答案 0 :(得分:22)

使用java内部的scala.collection.JavaConversions。

例如,要创建一个嵌套的scala case类,在其构造函数中需要一个scala List:

case class CardDrawn(player: Long, card: Int) 
case class CardSet(cards: List[CardDrawn]) 

从Java中你可以使用asScalaBuffer(x).toList(),如下所示:

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;
}

答案 1 :(得分:14)

在Scala中使用Java集合比在其他方面更容易,但是因为你问:

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;
  }
}

在类路径中使用scala-library.jar编译javac:

javac -classpath /opt/local/share/scala-2.9/lib/scala-library.jar foo.java

您可以从Scala REPL调用:

scala> (new foo).test
List(1)
List(2, 1)
res0: List[Any] = List(2, 1)

要使用Scala的Java集合,您不必执行任何特殊操作:

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]

答案 2 :(得分:14)

多么可怕的比较!我会把它留给其他人来解释如何完成你想要的东西,但这里有一些原因甚至不应该尝试这个:

  1. Scala的List是一个持久的,不可变的集合,ArrayList是一个可变的集合;
    1. 这意味着必须先复制ArrayList,然后才能传递给可能会更改它的方法,如果必须保留内容,而List则不需要这样做;
    2. 这也意味着在ArrayList;
    3. 中无法List支持操作
  2. List具有固定时间前置,ArrayList已分摊常量时间附加。两者都具有线性时间的其他操作。
  3. ArrayList具有固定时间索引访问权限,List具有线性时间索引访问权限,这无论如何都不是预期的使用模式;
  4. List应该通过自我遍历方法使用,例如使用闭包的foreachmapfilterArrayList在外部遍历迭代器或索引。
  5. 所以,基本上,每个人都会嘲笑对方的高效操作,并且与其中一个使用的算法不应该与另一个一起使用。让我们考虑你提出的基准:

      

    创建一个scala List并添加说100   随机数字

    您不向Scala List添加元素 - 它是不可变的。您可以根据现有List和新元素创建新的List。最后,您将拥有100个不同的列表(大小为1到100),所有这些列表都可以在不更改其他列表的情况下使用。同时,如果您向ArrayList添加100个元素,则您将拥有一个大小为100的ArrayList。因此,无论时间差异如何,每个操作都会做出不同的操作。

    修改

    我在这里发布了一个略有不同版本的naten代码,该代码使用List本身的方法来预先添加元素,而不是调用工厂。

    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;
      }
    }
    

    并且,在回答您的问题时,$colon$colon是Scala如何表示JVM中的方法::,它是用于预先添加元素的方法。此外,该方法绑定到右侧而不是左侧,反映了操作的性质,这就是评论为1::nil而不是nil::1的原因。

    引用空列表Nil$.MODULE$而不是重新创建,因为它是单例 - 无法创建空列表。

答案 3 :(得分:0)

我认为最简单的方法是从java接口开始并在scala中实现。例如,在scala中的scala列表周围创建一个java.util.List实现。通常是这样的:

class ScalaList[T](val ts: T*) extends java.util.List[T] {

  // Add all the methods, but implement only the neccessary ones
  // Add all ts

}