Scala Map和ConcurrentHashMap抛出java.lang.UnsupportedOperationException

Phi*_*dos 7 java containers multithreading scala java.util.concurrent

有了这个简单的代码

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

Scala抛出java.lang.UnsupportedOperationException.

为什么?

Sas*_*erg 7

那么这就是发生的事情(我认为):

  1. 您使用创建并发Java哈希映射 new java.util.concurrent.ConcurrentHashMap[String,String]()
  2. 然后将其转换为不可变的scala Map toMap
  3. 由于toMap没有定义,因此应用java.util.concurrent.ConcurrentHashMap了对可变 scala映射的隐式转换.并且toMap进而使得这种的可变 Map不可变的 Map.
  4. 然后你调用未定义的'put(...)' scala.collection.immutable.Map.
  5. 然而,scala编译器可以方便scala.collection.immutable.Mapjava.util.Map在导入import scala.collection.JavaConversions._中找到具有put(...)定义方法的转换.但是,转换返回一个包装器扩展AbstractMap.
  6. 但是put(...)在该包装器中没有实现任何方法.因此,调用最终在默认实现java.util.AbstractMap中没有真正实现put(...),而是抛出一个UnsupportedOperationException

我想由此引起的混乱,是一个原因,大多数开发商阶喜欢import scala.collection.JavaConverters._import scala.collection.JavaConversions._时下.

所以,我想,这可能是你想要做的:

import scala.collection.JavaConverters._
new java.util.concurrent.ConcurrentHashMap[String,String]().asScala.put("abc","def")    
Run Code Online (Sandbox Code Playgroud)


whe*_*ies 4

与 Java 不同,Scala 中的默认集合是不可变的。如果您查看 api(可在此处Map找到),您会发现缺少一个方法。所以例外是非常正确地告诉你,它不能做你想做的事。如果你想用值填充:MapputMapMap

Map("abc" -> "def")
Run Code Online (Sandbox Code Playgroud)

顺便说一句,不可变集合已经是线程安全的。无需使用ConcurrentHashMap.

  • 此外,scala 不可变映射的性能还得到了优化:[基准](https://gist.github.com/rklaehn/26c277b2b5666ec4b372) 和 [src](https://github.com/scala/scala/blob/2.12)。 x/src/library/scala/collection/immutable/HashMap.scala#L166)。不过还是要看实际需求 (2认同)