Konwertowanie kolekcji Java na kolekcję Scala

88

Powiązane z pytaniem o przepełnienie stosu Scala odpowiednik nowego zestawu HashSet (kolekcja) , jak przekonwertować kolekcję Java ( java.util.Listpowiedzmy) na kolekcję Scala List?

W rzeczywistości próbuję przekonwertować wywołanie Java API na Springa SimpleJdbcTemplate , które zwraca java.util.List<T>, na niezmienny Scala HashSet. Na przykład:

val l: java.util.List[String] = javaApi.query( ... )
val s: HashSet[String] = //make a set from l

To wydaje się działać. Krytyka jest mile widziana!

import scala.collection.immutable.Set
import scala.collection.jcl.Buffer 
val s: scala.collection.Set[String] =
                      Set(Buffer(javaApi.query( ... ) ) : _ *)
oxbow_lakes
źródło

Odpowiedzi:

17

Twoja ostatnia sugestia działa, ale możesz też uniknąć używania jcl.Buffer:

Set(javaApi.query(...).toArray: _*)

Zauważ, że scala.collection.immutable.Setjest on domyślnie udostępniany dzięki Predef.scala.

Jorge Ortiz
źródło
9
Ta sugestia nie działa, gdy chcę zachować informacje o typie
oxbow_lakes
127

Na przyszłość: w Scali 2.8 można to zrobić w następujący sposób:

import scala.collection.JavaConversions._
val list = new java.util.ArrayList[String]()
list.add("test")
val set = list.toSet

setjest scala.collection.immutable.Set[String]po tym.

Zobacz również odpowiedź Bena Jamesa, aby uzyskać bardziej wyraźny sposób (użycie JavaConverters), który wydaje się być teraz zalecany.

robinst
źródło
Wygląda na to, że teraz JavaConversionsma pewne implikacje, które sprawiają, że toSetpołączenie nie jest konieczne.
Rajish
@Rajish Myślę, że lepiej, jeśli konwersja jest jawna (patrz stackoverflow.com/questions/8301947/ ... )
krookedking
masz rację, lepiej jest użyć importu scala.collection.JavaConverters._
Abhishek Sengupta
62

Jeśli chcesz być bardziej wyraźny niż JavaConversions pokazane w odpowiedzi robinst , możesz użyć JavaConverters:

import scala.collection.JavaConverters._
val l = new java.util.ArrayList[java.lang.String]
val s = l.asScala.toSet
Ben James
źródło
25

JavaConversions ( odpowiedź robinst ) i JavaConverters (odpowiedź Bena Jamesa ) zostały wycofane ze Scala 2.10 .

Zamiast JavaConversions użyj:

import scala.collection.convert.wrapAll._

zgodnie z sugestią aleksandr_hramcov .

Zamiast JavaConverters użyj:

import scala.collection.convert.decorateAll._

W obu przypadkach istnieje również możliwość zaimportowania samych konwersji / konwerterów odpowiednio do Javy lub Scali, np .:

import scala.collection.convert.wrapAsScala._

Aktualizacja: powyższe stwierdzenie, że JavaConversions i JavaConverters zostały wycofane, wydaje się być błędne. W Scali 2.10 istniały przestarzałe właściwości, co spowodowało ostrzeżenia o wycofaniu podczas ich importowania. Więc alternatywne importy tutaj wydają się być tylko aliasami. Chociaż nadal je wolę, ponieważ IMHO nazwy są bardziej odpowiednie.

stempler
źródło
Dlaczego twierdzisz, że JavaConversions i JavaConverters są przestarzałe? W aktualnej dokumentacji 2.11.8 oba nie są oznaczone jako przestarzałe, a także nie mają odniesienia do „decorateAll” lub „wrapAll” stwierdzającego, że jest to nowe i preferowane użycie.
Joost den Boer
@JoostdenBoer Wygląda na to, że w Scali 2.10 było kilka przestarzałych dekoratorów , chociaż wydaje się, że zostały one ponownie usunięte w Scali 2.11.
stempler
14

Możesz również chcieć zbadać tę doskonałą bibliotekę: kolekcję scalaj, która ma dwukierunkową konwersję między kolekcjami Java i Scala. W twoim przypadku, aby przekonwertować java.util.List na Scala List, możesz to zrobić:

val list = new java.util.ArrayList[java.lang.String]
list.add("A")
list.add("B")
list.asScala
Surya Suravarapu
źródło
1
Ta biblioteka to najwspanialsza rzecz w historii. Naprawdę działa dobrze.
Michael Neale
7
Wracając do tego po kilku latach, JavaConverters firmy Scala jest drogą do zrobienia.
Surya Suravarapu
5

Uruchamianie Scala 2.13, pakiet scala.jdk.CollectionConverterszastępuje pakiety scala.collection.JavaConverters/JavaConversions._:

import scala.jdk.CollectionConverters._

// val javaList: java.util.List[String] = java.util.Arrays.asList("one","two","three")
javaList.asScala
// collection.mutable.Buffer[String] = Buffer("one", "two", "three")
javaList.asScala.toSet
// collection.immutable.Set[String] = Set("one", "two", "three")
Xavier Guihot
źródło
3
val array = java.util.Arrays.asList("one","two","three").toArray

val list = array.toList.map(_.asInstanceOf[String])
jamesqiu
źródło
to świetna odpowiedź i rozwiązała mój problem. Większość metod wymienionych w Internecie po prostu konwertuje (np.) Java.util.List [java.lang.Long] na scala.collection.immutable.List [java.lang.Long]. Więc ta metoda zadziałała, aby przekonwertować ją na scala.collection.immutable.List [scala.Long]
ajkl
2

Możesz dodać informacje o typie w wywołaniu toArray, aby ustawić parametry zestawu:

 val s = Set(javaApi.query(....).toArray(new Array[String](0)) : _*)

Może to być korzystne, ponieważ pakiet zbiory przeżywa poważnych przeróbek do Scala 2.8 i pakiet scala.collection.jcl jest odchodzi

Aaron
źródło
1

Możesz przekonwertować kolekcję Java na tablicę, a następnie utworzyć listę Scala z tego:

val array = java.util.Arrays.asList("one","two","three").toArray
val list = List.fromArray(array)
Fabian Steeg
źródło
2
To nie jest świetne, ponieważ moja java.util.List wraca z interfejsu API Java jako sparametryzowana lista (więc moje wywołanie interfejsu API daje java.util.List <String>) - próbuję to zmienić into a scala immutable HashSet
oxbow_lakes
1

Inny prosty sposób rozwiązania tego problemu:

import collection.convert.wrapAll._
aleksandr_hramcov
źródło