Java.util.Iterator в список Scala?
У меня есть следующий код:
private lazy val keys: List[String] = obj.getKeys().asScala.toList
obj.getKeys
возвращает java.util.Iterator<java.lang.String>
Вызов asScala
через JavaConverers
(который импортируется) в соответствии с документами.
java.util.Iterator <==> scala.collection.Iterator
scala.collection.Iterator
определяет
def toList: List[A]
Исходя из этого, я считаю, что это должно сработать, однако вот ошибка компиляции:
[scalac] <file>.scala:11: error: type mismatch;
[scalac] found : List[?0] where type ?0
[scalac] required: List[String]
[scalac] private lazy val keys : List[String] = obj.getKeys().asScala.toList
[scalac] one error found
Я понимаю, что параметр типа или java Iterator является строкой Java, и я пытаюсь создать список строк Scala, но (возможно, наивно) подумал, что будет неявное преобразование.
Ответы
Ответ 1
Это будет работать, если obj.getKeys() был java.util.Iterator<String>
. Я полагаю, что это не так.
Если obj.getKeys()
является просто java.util.Iterator
в необработанном виде, а не java.util.Iterator<String>
, даже не java.util.Iterator<?>
, это что-то scala, как правило, не нравятся, но в любом случае нет способа scala ввести ваш выражение List[String]
, если у него нет гарантии obj.getKeys()
содержит String.
Если вы знаете, что ваш итератор находится в строках, но тип не говорит об этом, вы можете использовать:
obj.getKeys().asInstanceOf[java.util.Iterator[String]]
(тогда продолжайте с .asScala.toList
)
Обратите внимание, что так же, как в java и из-за стирания типа, этот прилив не будет проверен (вы получите предупреждение). Если вы хотите немедленно проверить, что у вас есть строки, вы можете скорее сделать
obj.getKeys().map(_.asInstanceOf[String])
который будет проверять тип каждого элемента во время итерации для создания списка
Ответ 2
Вам не нужно вызывать asScala, это неявное преобразование:
import scala.collection.JavaConversions._
val javaList = new java.util.LinkedList[String]() // as an example
val scalaList = javaList.iterator.toList
Если у вас действительно нет параметра типа итератора, просто введите его в правильный тип:
javaList.iterator.asInstanceOf[java.util.Iterator[String]].toList
EDIT: некоторые люди предпочитают не использовать неявные преобразования в JavaConversions, но использовать декодеры asScala/asJava в JavaConverters, чтобы сделать преобразования более явными.
Ответ 3
Мне не нравятся другие ответы. Черт, мне не нравится то, что предлагает использовать asInstanceOf
, если нет альтернативы. В этом случае есть. Если вы это сделаете:
private lazy val keys : List[String] = obj.getKeys().asScala.collect {
case s: String => s
}.toList
Вы безопасно и эффективно поворачиваете Iterator[_]
в Iterator[String]
.
Ответ 4
Начиная с версии 2.12.8 можно использовать
import scala.collection.JavaConverters._
asScalaIterator(java.util.Iterator variable).toSeq
Ответ 5
Обратите внимание, что начиная с Scala 2.13
, пакет scala.jdk.CollectionConverters
заменяет устаревшие пакеты scala.collection.JavaConverters/JavaConversions
когда речь идет о неявных преобразованиях между коллекциями Java и Scala:
import scala.jdk.CollectionConverters._
// val javaIterator: java.util.Iterator[String] = java.util.Arrays.asList("a", "b").iterator
javaIterator.asScala
// Iterator[String] = <iterator>