Convertendo uma coleção Java em uma coleção Scala

87

Relacionado à questão do Stack Overflow Scala equivalente a new HashSet (Collection) , como faço para converter uma coleção Java ( java.util.Listdigamos) em uma coleção Scala List?

Na verdade, estou tentando converter uma chamada de API Java para Spring SimpleJdbcTemplate , que retorna um java.util.List<T>, em um Scala imutável HashSet. Então, por exemplo:

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

Isso parece funcionar. A crítica é bem-vinda!

import scala.collection.immutable.Set
import scala.collection.jcl.Buffer 
val s: scala.collection.Set[String] =
                      Set(Buffer(javaApi.query( ... ) ) : _ *)
oxbow_lakes
fonte

Respostas:

17

Sua última sugestão funciona, mas você também pode evitar o uso de jcl.Buffer:

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

Observe que scala.collection.immutable.Setestá disponível por padrão graças a Predef.scala.

Jorge Ortiz
fonte
9
Esta sugestão não funciona onde desejo manter as informações de tipo
oxbow_lakes
126

Para referência futura: Com Scala 2.8, isso poderia ser feito assim:

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

seté um scala.collection.immutable.Set[String]depois disso.

Veja também a resposta de Ben James para uma forma mais explícita (usando JavaConverters), que parece ser recomendada agora.

robinst
fonte
Parece que agora JavaConversionstem alguns implícitos que tornam a toSetchamada desnecessária.
Rajish
@Rajish Eu acho que é melhor se a conversão for explícita (veja stackoverflow.com/questions/8301947/… )
krookedking
você está certo, é melhor usar import scala.collection.JavaConverters._
Abhishek Sengupta
62

Se quiser ser mais explícito do que JavaConversions demonstrado na resposta de robinst , você pode usar JavaConverters:

import scala.collection.JavaConverters._
val l = new java.util.ArrayList[java.lang.String]
val s = l.asScala.toSet
Ben James
fonte
25

JavaConversions ( resposta de robinst ) e JavaConverters ( resposta de Ben James ) foram descontinuados com Scala 2.10 .

Em vez de JavaConversions, use:

import scala.collection.convert.wrapAll._

como sugerido por aleksandr_hramcov .

Ao invés de JavaConverters, use:

import scala.collection.convert.decorateAll._

Para ambos também existe a possibilidade de importar apenas as conversões / conversores para Java ou Scala respectivamente, por exemplo:

import scala.collection.convert.wrapAsScala._

Atualização: a declaração acima de que JavaConversions e JavaConverters foram descontinuados parece estar errada. Havia algumas propriedades reprovadas no Scala 2.10, o que resultou em avisos de descontinuação ao importá-las. Portanto, as importações alternativas aqui parecem ser apenas aliases. Embora eu ainda prefira eles, como IMHO os nomes são mais apropriados.

trêmulo
fonte
Por que você diz que JavaConversions e JavaConverters estão obsoletos? Na documentação atual 2.11.8, ambos não estão marcados como obsoletos e também não têm uma referência a 'decorateAll' ou 'wrapAll' afirmando que esse é o uso novo e preferido.
Joost den Boer
@JoostdenBoer Parece houve alguns decoradores obsoletos em Scala 2.10, embora eles parecem ter sido removidos novamente com Scala 2.11.
stempler
14

Você também pode querer explorar esta excelente biblioteca: scalaj-collection que possui conversão bidirecional entre coleções Java e Scala. No seu caso, para converter um java.util.List em Scala List, você pode fazer o seguinte:

val list = new java.util.ArrayList[java.lang.String]
list.add("A")
list.add("B")
list.asScala
Surya Suravarapu
fonte
1
Essa biblioteca é a melhor coisa de todos os tempos. Realmente funciona bem.
Michael Neale,
6
Revisitando isso depois de alguns anos, os JavaConverters da Scala são o caminho a percorrer.
Surya Suravarapu
4

Iniciando Scala 2.13, pacote scala.jdk.CollectionConverterssubstitui pacotes 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
fonte
3
val array = java.util.Arrays.asList("one","two","three").toArray

val list = array.toList.map(_.asInstanceOf[String])
Jamesqiu
fonte
esta é uma ótima resposta e resolveu meu problema. A maioria dos métodos mencionados na Internet apenas converte (por exemplo) java.util.List [java.lang.Long] em scala.collection.immutable.List [java.lang.Long]. Portanto, este método funcionou para mim convertê-lo em scala.collection.immutable.List [scala.Long]
ajkl
2

Você pode adicionar as informações de tipo na chamada toArray para fazer o conjunto ser parametrizado:

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

Isso pode ser preferível, pois o pacote de coleções está passando por um grande retrabalho para Scala 2.8 e o pacote scala.collection.jcl está indo embora

Aaron
fonte
1

Você pode converter a coleção Java em uma matriz e, em seguida, criar uma lista Scala a partir disso:

val array = java.util.Arrays.asList("one","two","three").toArray
val list = List.fromArray(array)
Fabian Steeg
fonte
2
Isso não é ótimo porque meu java.util.List está voltando de uma API Java como uma lista parametrizada (portanto, minha chamada para a API produz um java.util.List <String>) - Estou tentando transformar isso em uma escala HashSet imutável
oxbow_lakes
1

Outra maneira simples de resolver esse problema:

import collection.convert.wrapAll._
aleksandr_hramcov
fonte