Как использовать scala.collection.immutable.List в коде Java - PullRequest
14 голосов
/ 05 июля 2011

Мне нужно написать код, который сравнивает производительность Java ArrayList с Scala List.Мне трудно заставить Scala List работать в моем Java-коде.Может кто-нибудь опубликовать настоящий простой пример "Привет, мир", как создать Scala List в коде Java (в файле .java) и добавить к нему, скажем, 100 случайных чисел?

PS: IЯ неплохо разбираюсь в Java, но никогда не использовал Scala.

Ответы [ 4 ]

22 голосов
/ 31 августа 2013

Используйте scala.collection.JavaConversions изнутри Java.

Например, чтобы создать вложенный класс падежа scala, для которого в своем конструкторе требуется список scala:

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;
}
14 голосов
/ 05 июля 2011

Использовать коллекции Java в Scala проще, чем наоборот, но так как вы спросили:

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

Это компилируется с javac с scala-library.jar в classpath:

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)

Чтобы использовать коллекцию Java из Scala, вам не нужно делать ничего особенного:

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]
14 голосов
/ 05 июля 2011

Какое ужасное сравнение! Я оставлю это другим, чтобы объяснить, как выполнить то, что вы хотите, но вот несколько причин, почему это даже не следует пытаться:

  1. Scala's List - это постоянная неизменная коллекция, ArrayList - изменчивая коллекция;
    1. Это означает, что ArrayList должно быть скопировано перед передачей методам, которые могут его изменить, если содержимое должно быть сохранено, хотя с List;
    2. Это также означает, что ArrayList операции поддержки невозможны в List;
  2. List имеет постоянное время, ArrayList амортизирует постоянное время. Оба имеют линейное время другой операции.
  3. ArrayList имеет индексированный доступ с постоянным временем, List имеет индексированный доступ с линейным временем, который в любом случае не предназначен для использования;
  4. List следует использовать с помощью методов самообхода, таких как foreach, map и filter, которые используют замыкания, ArrayList извлекается извне через итератор или индекс.

Так что, по сути, каждый сосет эффективные операции другого, и сами алгоритмы, используемые с одним, не должны использоваться с другим. Давайте рассмотрим тот самый эталон, который вы предлагаете:

создать список Scala и добавить, скажем, 100 случайные числа к нему

Вы не добавляете элементы в Scala List - он неизменен. Вы создаете новый List на основе существующего List и нового элемента. В итоге у вас будет 100 различных списков (размером от 1 до 100), каждый из которых можно использовать, не меняя другой. Между тем, если вы добавите 100 элементов к ArrayList, у вас будет один ArrayList размера 100. Таким образом, независимо от разницы во времени, каждая операция делает что-то свое.

Редактировать

Я публикую здесь немного другую версию кода Натена, который использует метод на 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$, вместо ссылки создается заново, потому что это одиночный файл - создать пустой список невозможно.

0 голосов
/ 05 июля 2011

Я думаю, что самый простой способ - начать с Java-интерфейса и реализовать его в Scala. Например, создайте реализацию java.util.List для списка scala в scala. Обычно так:

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

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

}
...