Create an immutable list from a java.lang.Iterator

21,965

Solution 1

You might want to rethink the need for a List, although it feels very familiar when coming from Java, and List is the default implementation of an immutable Seq, it often isn't the best choice of collection.

The operations that list is optimal for are those already available via an iterator (basically taking consecutive head elements and prepending elements). If an iterator doesn't already give you what you need, then I can pretty much guarantee that a List won't be your best choice - a vector would be more appropriate.


Having got that out the way... The recommended technique to convert between Java and Scala collections (since Scala 2.8.1) is via scala.collection.JavaConverters. This gives you more control than JavaConversions and avoids some possible implicit conflicts.

You won't have a direct implicit conversion this way. Instead, you get asScala and asJava methods pimped onto collections, allowing you to perform the conversions explicitly.

To convert a Java iterator to a Scala iterator:

javaIterator.asScala

To convert a Java iterator to a Scala List (via the scala iterator):

javaIterator.asScala.toList

You may also want to consider converting toSeq instead of toList. In the case of iterators, this'll return a Stream - allowing you to retain the lazy behaviour of iterators within the richer Seq interface.

EDIT: There's no toVector method, but (as Daniel pointed out) there's a toIndexedSeq method that will return a Vector as the default IndexedSeq subclass (just as List is the default Seq).

javaIterator.asScala.toIndexedSeq

Solution 2

EDIT: You should probably look at Kevin Wright's answer, which provides a better solution available since Scala 2.8.1, with less implicit magic.


You can import the implicit conversions from scala.collection.JavaConversions and then create a new Scala collection seamlessly, e.g. like this:

import collection.JavaConversions._
println(List() ++ javaIterator)

Your Java iterator is converted to a Scala iterator by JavaConversions.asScalaIterator. A Scala iterator with elements of type A implements TraversableOnce[A], which is the argument type needed to concatenate collections with ++.

If you need another collection type, just change List() to whatever you need (e.g., IndexedSeq() or collection.mutable.Seq(), etc.).

Share:
21,965

Related videos on Youtube

Romain Rouvoy
Author by

Romain Rouvoy

Updated on May 17, 2020

Comments

  • Romain Rouvoy
    Romain Rouvoy about 4 years

    I'm using a library (JXPath) to query a graph of beans in order to extract matching elements. However, JXPath returns groups of matching elements as an instance of java.lang.Iterator and I'd rather like to convert it into an immutable scala list. Is there any simpler way of doing than iterating over the iterator and creating a new immutable list at each iteration step ?

  • Jean-Philippe Pellet
    Jean-Philippe Pellet about 13 years
    Kevin, as your answer is clearly better, I'll delete mine. And I'll definitely look at all the new API introduced in 2.8.1 and 2.9!
  • Kevin Wright
    Kevin Wright about 13 years
    @Jean-Philippe - Do you know how depressing that is? It shows that I've clearly been burdened with far too much Java interop work in my time... Besides, you raised an important point about TraversableOnce and ++; your answer would help some hypothetical future reader who was interested in concatenating a Java collection.
  • Jean-Philippe Pellet
    Jean-Philippe Pellet about 13 years
    @Kevin OK, I've reopened it, directing readers to your answer in an edit.
  • Daniel C. Sobral
    Daniel C. Sobral about 13 years
    @Kevin Vector is the default implementation of IndexedSeq, and there is a toIndexedSeq.