Подтвердить что ты не робот

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, но (возможно, наивно) подумал, что будет неявное преобразование.

4b9b3361

Ответ 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>