What is the difference between JavaConverters and JavaConversions in Scala?
Asked Answered
C

4

207

In scala.collection, there are two very similar objects JavaConversions and JavaConverters.

  • What is the difference between these two objects?
  • Why do they both exist?
  • When do I want to use one vs. the other?
Campanulate answered 28/11, 2011 at 20:34 Comment(0)
R
265

EDIT: Java Conversions got @deprecated in Scala 2.13.0. Use scala.jdk.CollectionConverters instead.

JavaConversions provide a series of implicit methods that convert between a Java collection and the closest corresponding Scala collection, and vice versa. This is done by creating wrappers that implement either the Scala interface and forward the calls to the underlying Java collection, or the Java interface, forwarding the calls to the underlying Scala collection.

JavaConverters uses the pimp-my-library pattern to “add” the asScala method to the Java collections and the asJava method to the Scala collections, which return the appropriate wrappers discussed above. It is newer (since version 2.8.1) than JavaConversions (since 2.8) and makes the conversion between Scala and Java collection explicit. Contrary to what David writes in his answer, I'd recommend you make it a habit to use JavaConverters as you'll be much less likely to write code that makes a lot of implicit conversions, as you can control the only spot where that will happen: where you write .asScala or .asJava.

Here's the conversion methods that JavaConverters provide:

Pimped Type                            | Conversion Method   | Returned Type
=================================================================================================
scala.collection.Iterator              | asJava              | java.util.Iterator
scala.collection.Iterator              | asJavaEnumeration   | java.util.Enumeration
scala.collection.Iterable              | asJava              | java.lang.Iterable
scala.collection.Iterable              | asJavaCollection    | java.util.Collection
scala.collection.mutable.Buffer        | asJava              | java.util.List
scala.collection.mutable.Seq           | asJava              | java.util.List
scala.collection.Seq                   | asJava              | java.util.List
scala.collection.mutable.Set           | asJava              | java.util.Set
scala.collection.Set                   | asJava              | java.util.Set
scala.collection.mutable.Map           | asJava              | java.util.Map
scala.collection.Map                   | asJava              | java.util.Map
scala.collection.mutable.Map           | asJavaDictionary    | java.util.Dictionary
scala.collection.mutable.ConcurrentMap | asJavaConcurrentMap | java.util.concurrent.ConcurrentMap
—————————————————————————————————————————————————————————————————————————————————————————————————
java.util.Iterator                     | asScala             | scala.collection.Iterator
java.util.Enumeration                  | asScala             | scala.collection.Iterator
java.lang.Iterable                     | asScala             | scala.collection.Iterable
java.util.Collection                   | asScala             | scala.collection.Iterable
java.util.List                         | asScala             | scala.collection.mutable.Buffer
java.util.Set                          | asScala             | scala.collection.mutable.Set
java.util.Map                          | asScala             | scala.collection.mutable.Map
java.util.concurrent.ConcurrentMap     | asScala             | scala.collection.mutable.ConcurrentMap
java.util.Dictionary                   | asScala             | scala.collection.mutable.Map
java.util.Properties                   | asScala             | scala.collection.mutable.Map[String, String]

To use the conversions directly from Java, though, you're better off calling methods from JavaConversions directly; e.g.:

List<String> javaList = new ArrayList<String>(Arrays.asList("a", "b", "c"));
System.out.println(javaList); // [a, b, c]
Buffer<String> scalaBuffer = JavaConversions.asScalaBuffer(javaList);
System.out.println(scalaBuffer); // Buffer(a, b, c)
List<String> javaListAgain = JavaConversions.bufferAsJavaList(scalaBuffer);
System.out.println(javaList == javaListAgain); // true
Rostellum answered 28/11, 2011 at 21:21 Comment(9)
Hi Jean-Philippe. I don't get your point regarding implicits conversion. As you have explained, ScalaConverter make use of implicits to add asJava and asScala. Furthermore, you specify the scala or java type you want to convert to on the new val definition (i.e. val sl = new scala.collection.mutable.ListBuffer[Int]; val jl : java.util.List[Int] = sl). So using ScalaConversions you have an easy way to convert your collection and the ability to fine tune the target type.Hl
Yes, use JavaConverters over JavaConversions,. But also consider using github.com/scalaj/scalaj-collection as it has some benefits as converting java.util.List to Seq. (Is the above list from 2.8.1?)Caryophyllaceous
@Hl While implicit conversions like those provided by JavaConversions are convenient, you may quickly overlook all the places where they can be inserted by the compiler. You control those places with JavaConverters. It's the whole discussion about implicit vs explicit conversion.Rostellum
@Jean-PhilippePellet implicit conversions in Scala are Scope based so if you don't import JavaConversions._, conversions will not occur so you have the control on what is converted. If you place the import the right way (only when needed), you have full control on where the conversion is done.Hl
@Hl … and with JavaConverters you have the additional safety that nothing happens unless you write it explicitly. That's an additional security, and that's most probably why this class was added.Rostellum
You'd think the naming would be better: e.g. something like "JavaConversionsImplicit" and "JavaConversionsExplicit" would have been easier to distinguish.Grandiloquence
Are the JavaConverters usable from within java? (eg, I have a java.util.List and an API that requires a scala Set and I am writing java code)Telemark
@TheTrav I added an example in Java. I think you're better off using JavaConversions, if it's from Java.Rostellum
Unfortunately, I think whoever created those classes was stoned. JavaConversions is very nice but gives you no way to create immutable scala collections and the toMap bits of JavaConverters are a PITA to work with.Defect
M
56

For anyone landing on this question since Scala 2.12.x, JavaConversions is now deprecated and JavaConverters is the preferred method.

Mastersinger answered 18/1, 2017 at 14:11 Comment(1)
Since Scala 2.13, JavaConverters is deprecated, and scala.jdk.CollectionConverters is the preferred method ;)Undersize
C
8

In Scala 2.13, JavaConverters have been deprecated in favour of scala.jdk.CollectionConverters:

...new package scala.jdk with objects CollectionConverters (classic Java collections, similar to collection.JavaConverters in 2.12), StreamConverters, FunctionConverters and OptionConverters...

Cicatrix answered 25/6, 2019 at 20:31 Comment(0)
H
6

As explained in the API, JavaConversions is a set of implicit conversions that transforms java collections into related scala collection.

You can use it with an import collection.JavaConversions._. When necessary, the compiler will automatically transform the java collection into the right scala type.

JavaConverters are a set of decorator that helps transform java or scala collections to scala or java collections using asScala or asJava methods that will be implicitly added to the collection that you want to transform. In order to use these converters, you need to import :

import collection.JavaConverters._

You should prefer JavaConversions as it's generally easier to use (no need to use asScala or asJava).

Hl answered 28/11, 2011 at 21:17 Comment(2)
While using the totally implicit approach of JavaConverters is easier to write, it is harder to read. Current Scala style suggests that it's better to explicitly call methods to perform conversions, which is why JavaConverters are now preferred.Esculent
JavaConversions are deprecated in Scala 2.12Entente

© 2022 - 2024 — McMap. All rights reserved.