Как использовать scala.collection.immutable.List в коде Java

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

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

Ответ 1

Проще использовать коллекции 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 в пути к классам:

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]

Ответ 2

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

Например, для создания вложенного класса класса scala, для которого требуется 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;
}

Ответ 3

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

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

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

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

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

Edit

Я размещаю здесь немного другую версию кода naten, которая использует метод на List сам, чтобы добавить элемент вместо вызова 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;
  }
}

И, отвечая на ваш вопрос к нему, $colon$colon описывает, как scala представляет метод :: в JVM, являющийся методом, используемым для добавления элементов. Кроме того, этот метод связывается справа, а не слева, что отражает характер операции, поэтому комментарий 1::nil вместо nil::1.

Пустой список, Nil$.MODULE$, ссылается вместо созданного заново, потому что он singleton - нет способа создать пустой список.

Ответ 4

Я думаю, что самый простой маршрут - начать с интерфейса 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

}