7

With this simple code

import scala.collection.JavaConversions._
new java.util.concurrent.ConcurrentHashMap[String,String]  ().toMap.put("abc","def")

Scala throw a java.lang.UnsupportedOperationException.

Why ?

1
  • What does toMap do? ConcurrentHashMap is already a map. I guess, new java.util.concurrent.ConcurrentHashMap[String,String] ().put("abc","def") should work fine.
    – Tamas Rev
    Commented Jul 25, 2016 at 13:08

2 Answers 2

7

Well this is what happens (I think):

  1. You create a concurrent java hash map with new java.util.concurrent.ConcurrentHashMap[String,String]()
  2. Then you convert it to an immutable scala Map with toMap
  3. As toMapis not defined on java.util.concurrent.ConcurrentHashMap an implicit conversion to a mutable scala map is applied. And toMap then makes of this mutable Map an immutable Map.
  4. Then you call 'put(...)' which is not defined on scala.collection.immutable.Map.
  5. The scala compiler however, conveniently, finds a conversion from scala.collection.immutable.Map to java.util.Map in your import import scala.collection.JavaConversions._ which has a put(...) method defined. However, the conversion returns a wrapper extending AbstractMap.
  6. But there is no put(...) method implemented in that wrapper. Therefore, the call ends up in the default implementation of java.util.AbstractMap which does not really implement put(...) but instead throws an UnsupportedOperationException

I guess the confusion caused by this, is one reason most scala developers prefer import scala.collection.JavaConverters._ over import scala.collection.JavaConversions._ nowadays.

So, I think, this might be what you want to do:

import scala.collection.JavaConverters._
new java.util.concurrent.ConcurrentHashMap[String,String]().asScala.put("abc","def")    
2
  • Just a very slight change: the last conversion is from scala.collection.Map to java.util.Map. But it actually returns a wrapper extending AbstractMap which delegates methods like get to corresponding scala.collection.Map methods. And there is no method corresponding to put, so it isn't overridden and AbstractMap's implementation is inherited. Commented Jul 25, 2016 at 13:58
  • @AlexeyRomanov Thanks , was a bit lazy there. I edited my answer, hope it's more accurate now. Commented Jul 25, 2016 at 14:05
4

Unlike Java, the default collections in Scala are immutable. If you take a look at the api for Map (found here) you'll see that Map lacks a method put. So the exception is telling you, quite rightly, that Map can't do what you want it to do. If you want to fill the Map with values:

Map("abc" -> "def")

By the way, an immutable collection is already thread-safe. No need to use a ConcurrentHashMap.

3
  • Re, "By the way... no need to use a ConcurrentHashMap." See stackoverflow.com/questions/6692008/… Commented Jul 25, 2016 at 14:06
  • @jameslarge their performance is pretty much equals starting from Java7, which is directly explained in the answer to the question you're pointing to. Or did you mean something else?
    – dk14
    Commented Jul 25, 2016 at 14:09
  • 2
    moreover the performance of scala's immutable map is additionally optimized: benchmark and src. It depends on actual requirements though
    – dk14
    Commented Jul 25, 2016 at 14:17

Not the answer you're looking for? Browse other questions tagged or ask your own question.