2016-07-25 18 views
7

Mit diesem einfachen CodeScala Karte und ConcurrentHashMap eine java.lang.UnsupportedOperationException

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

Scala werfen einen java.lang.UnsupportedOperationException werfen.

Warum?

+0

Was bedeutet 'toMap' tun? ConcurrentHashMap ist bereits eine Karte. Ich denke, 'neue java.util.concurrent.ConcurrentHashMap [String, String]() .put (" abc "," def ")' sollte gut funktionieren. –

Antwort

4

Im Gegensatz zu Java sind die Standardkollektionen in Scala unveränderbar. Wenn Sie einen Blick auf die API für Map (gefunden here) werfen, werden Sie sehen, dass Map eine Methode put fehlt. Also die Ausnahme sagt Ihnen zu Recht, dass Map nicht tun kann, was Sie wollen. Wenn Sie die Map mit Werten füllen wollen:

Map("abc" -> "def") 

By the way, eine unveränderliche Kollektion ist bereits Thread-sicher. Keine Notwendigkeit, eine ConcurrentHashMap zu verwenden.

+0

Re, "Übrigens, keine ConcurrentHashMap benötigt." Siehe http://stackoverflow.com/questions/6692008/java-concurrenthashmap-is-better-than-hashmap-performance-wise –

+0

@jameslarge ihre Leistung ist ziemlich viel gleich beginnend mit Java7, die direkt in der Antwort auf die erklärt wird Frage, auf die du zeigst. Oder meintest du etwas anderes? – dk14

+2

Darüber hinaus wird die Performance der unveränderlichen Karte von scala zusätzlich optimiert: [benchmark] (https://gist.github.com/rklaehn/26c277b2b5666ec4b372) und [src] (https://github.com/scala/scala/blob/2.12 .x/src/Bibliothek/Scala/Sammlung/unveränderlich/HashMap.scala # L166). Es hängt jedoch von den tatsächlichen Anforderungen ab. – dk14

7

Nun ist es das, was passiert (glaube ich):

  1. Sie eine Java-Hash-Karte mit new java.util.concurrent.ConcurrentHashMap[String,String]()
  2. gleichzeitige Erstellen Sie dann Sie es zu einem unveränderlichen scala Map umwandeln mit toMap
  3. Als toMap nicht ist definiert auf java.util.concurrent.ConcurrentHashMap eine implizite Umwandlung in eine veränderbare Scala Map wird angewendet. Und toMap macht dann veränderbarMap ein unveränderlichMap.
  4. Dann rufen Sie 'Put (...)', die nicht auf scala.collection.immutable.Map definiert ist.
  5. Der Scala-Compiler findet jedoch bequem eine Konvertierung von scala.collection.immutable.Map zu java.util.Map in Ihrem Import import scala.collection.JavaConversions._, der eine put(...) Methode definiert hat. Die Konvertierung gibt jedoch einen Wrapper zurück, der AbstractMap erweitert.
  6. Aber es gibt keine put(...) Methode in diesem Wrapper implementiert. Daher endet der Aufruf in der Standardimplementierung von java.util.AbstractMap auf die nicht wirklich put(...) implementieren, sondern wirft ein UnsupportedOperationException

ich die Verwirrung erraten, die dadurch verursacht, ist ein Grund, die meisten scala Entwickler import scala.collection.JavaConverters._ über import scala.collection.JavaConversions._ heutzutage bevorzugen.

Also, ich glaube, das könnte das sein, was Sie tun möchten:

import scala.collection.JavaConverters._ 
new java.util.concurrent.ConcurrentHashMap[String,String]().asScala.put("abc","def")  
+0

Nur eine sehr kleine Änderung: Die letzte Konvertierung ist von "scala.collection.Map" nach "java.util.Map". Aber es gibt tatsächlich einen Wrapper zurück, der 'AbstractMap' erweitert, der Methoden wie' get' an die entsprechenden 'scala.collection.Map' Methoden delegiert. Und es gibt keine Methode, die "Put" entspricht, also wird sie nicht überschrieben und die Implementierung von "AbstractMap" wird vererbt. –

+0

@AlexeyRomanov Danke, war ein bisschen faul dort. Ich habe meine Antwort bearbeitet und hoffe, dass sie jetzt genauer ist. –