While trying to make a map in Scala, I receive the following error message: object Map is not a value
The code I'm using is the following:
val myStringMap = Map[String, String]("first" -> "A", "second" -> "B", "third" -> "C")
I am quite puzzled as to why I cannot create this map because after looking at Scala documentation, it seems to me that the syntax of my code is proper.
When you see the error "object is not a value" this typically means that the in-scope type is a Java type - you probably are importing java.util.Map in scope
scala> Map(1 -> "one")
res0: scala.collection.immutable.Map[Int,java.lang.String] = Map(1 -> one)
But
scala> import java.util.Map
import java.util.Map
scala> Map(1 -> "one")
<console>:9: error: object Map is not a value
Map(1 -> "one")
^
Remember, in scala each class comes with a (optional) companion object which is a value. This is not true of Java classes.
Because in scala each native scala class comes with an (optional) companion object (allowing for assignment from the companion object as in your example code) when incorporating a java class into scala code always remember to instantiate the class by invoking the constructor, ie. use keyword "new", thus creating a value.
Just found this so maybe it will be useful to share my solution.
If you have imported java.util.Map and need to use scala.collection.immutable.Map then use it with the full name so instead of
Map(1 -> "one")
do
scala.collection.immutable.Map(1 -> "one")
This way it will know what you mean
I got similar error on Lists. try this in scala console:
import java.util.List object test { def a():List[String] = { val list = List[String](); null }}
you'll get the err "Object List is not a value."
You get it because you're hiding the built-in List type, that is because List is different from java.util.List
What if someone wants to use util.List?
you can use a qualified name or a rename import
! import java.util.{List => JList}
import java.util.{List=>JList}
Related
I am trying to print the value of 1, 2 or 3
using this code
but it just says
defined object Demo
import scala.collection.immutable._
object Demo {
val mymap : Map[String, String] =
Map("1" -> "ME", "2" -> "SUPERMAN", "3" -> "ZOD")
def main(args: Array[String]) {
println(mymap("1"));
}
}
Judging from the tags you used (databricks), it looks like you are using either a REPL or some other online worksheet. As such, you don't have to create an object with a main method, but just write in your code, as follows:
import scala.collection.immutable._
val mymap: Map[String, String] =
Map("1" -> "ME", "2" -> "SUPERMAN", "3" -> "ZOD")
println(mymap("1"))
You can play around with this code with another Scala online worksheet, called Scastie (here).
Alternatively, you can also call Demo.main directly from outside of the object definition, passing Array.empty as its only argument.
A few of further notes:
I'm not 100% whether this is true for your environment, but in general importing scala.collection.immutable._ is not strictly necessary
in Scala you can make use of type inference and skip the Map[String, String] type annotation: the compiler will infer it for you
semi-colons are optional in Scala
I have 2 maps, map1 and map2, both of type Map[String, MyType].
What I wanted to do was, searching for a key in the first map, if not found, search in the second one, and if still not found, use a default value:
map1.getOrElse(name, map2.getOrElse(name, defVal))
However, what I accidently wrote was:
map1.getOrElse(name, map2.get(name, defVal)).
Surprisingly, this didn't cause a compile-time error (and returned null), although i called get with 2 parameters.
As I can see in the IDE (Eclipse), it calls get(x$1 : Any) : MyType of java.util.Map, instead of get(key : String) : Option[MyType] of scala.collection.MapLike
Why doesn't it report an error, when I call map2.get with a second parameter? As far as I can see in the documentation, map.get only takes one parameter? Does it interpret the two parameters as a tuple or something similar (and use this tuple as Any-parameter)?
If relevant, MyType is a class from a referenced Java-project.
I am quiet new in Scala, so if this is trivial or a basic concept that I missed (and everyone programming scala should already know), please tell me what to search for.
EDIT:
As I saw in the comments, that the problem is not reproduceable, I saw, that I hava import scala.collection.javaConversions._, because I get the collections from a Java-Project that I reference. Now it is also reproducable with a short code like this:
import scala.collection.JavaConversions._
object Main {
def main (args : Array[String]) : Unit = {
val map1 = Map("1" -> 2)
val map2 = Map("2" -> 1)
map1.getOrElse("1", map2.get("2", 0))
}
}
Might be argument adaptation from map2.get(name, defVal) to map2.get((name, defVal)).
Edit: Use JavaConverters. JavaConversions is deprecated.
Well... I am not sure how you made this work, it should not be possible.
It is still not doable ( at least with Scala 2.12.1)
scala> val map1 = Map("1" -> "!", "2" -> "#")
map1: scala.collection.immutable.Map[String,String] = Map(1 -> !, 2 -> #)
scala> val map2 = Map("3" -> "#", "4" -> "$")
map2: scala.collection.immutable.Map[String,String] = Map(3 -> #, 4 -> $)
scala> val s = map1.getOrElse("3", map2.get("3", "%"))
<console>:13: error: too many arguments (2) for method get: (key: String)Option[String]
val s = map1.getOrElse("3", map2.get("3", "%"))
^
I have the following data structure:
java.util.Map[List[String],List[String]] = {[10, 20]=[1500], [5, 7]=[1400]}
I am trying to extract the numbers 10 20 5 and 7 using Scala. The way I was looking to achieve this is:
map.head._1 -> to extract 10 (map.head returns a tuple)
map.head._2 -> to extract 20 (map.head returns a tuple)
However, I am getting the following exception:
java.lang.ClassCastException: java.util.ArrayList cannot be cast to scala.collection.immutable.List
I have read about importing import scala.collection.JavaConversions._ however, this did not fix anything.
Thanks, any help is highly appreciated!
The piece of code that tries to achieve this is:
def getTokenRangeForKeys(params: String): java.util.Map[List[String], List[String]] = {
invokeOperation[java.util.Map[List[String], List[String]]]("XXX", "YYY", Array(params))
}
The above method returns my map, which looks like this:
map = java.util.Map[List[String],List[String]] = {[10, 20]=[1500], [5, 7]=[1400]}
What I have tried so far:
map.head._1 -> java.lang.ClassCastException: java.util.ArrayList cannot be cast to scala.collection.immutable.List
scalaMap = map.asScala
m.headOption match {
case Some((h1, h2)) => println((h1, h2)) -> java.util.ArrayList cannot be cast to scala.collection.immutable.List
case None => ...
}
I think your declaration of what comes from Java world should be:
java.util.Map[java.util.List[String], java.util.List[String]]
In the current form of java.util.Map[List[String], List[String]] you declare a java Map of Scala Lists, which is probably not what you want. JVM is not complaining when you pass your Java types because only top level type is checked as a part of function signature check - this is called type erasure.
On this you should use JavaConverters asScala to convert to corresponding Scala types as written in the Reactormonk answer:
import scala.collection.JavaConverters._
val m = map.asScala.map{case (h, k) => (h.asScala, k.asScala)}
Don't use JavaConversions.
import scala.collection.JavaConverters._
val m = map.asScala.map({case (h, k) => (h.asScala, k.asScala)})
m.headOption match {
case Some((h1, h2)) => ...
case None => ...
}
I am thoroughly confused by this behavior in the Scala REPL:
scala> import java.util.Map
import java.util.Map
scala> import java.util.HashMap
import java.util.HashMap
scala> val jMap:java.util.Map[String,Int]=new HashMap[String,Int]("first"->1,"second" -> 2)
<console>:12: error: type mismatch;
found : (String, Int)
required: Float
val jMap =new HashMap[String,Int]("first"->1,"second" -> 2)
^
<console>:12: error: type mismatch;
found : (String, Int)
required: Float
val jMap=new HashMap[String,Int]("first"->1,"second" -> 2)
^
Can someone help explain what's going on here ?
java.util.HashMap does not provide capability to construct the map by passing a vararg of (K, V), but there is a two-arg constructor accepting initialCapacity: Int and loadFactor: Float, that's why you're getting the compile error about a Float being required.
(updated for scala 2.13+) The idiomatic approach in Scala would be to just use Scala immutable maps (no imports required):
val map = Map("first" -> 1, "second" -> 2).asJava
If your Scala code works with a Java library that returns a java.util.Map, you can convert it into a Scala map explicitly by using scala.jdk.CollectionConverters like so:
import scala.jdk.CollectionConverters._
val javaMap: java.util.Map[String, String] = // ...
val map = javaMap.asScala
// or vice versa if you need to pass it into the Java API
val javaMap = Map("first" -> 1, "second" -> 2).asJava
Note that asScala is just a wrapper to the underlying Java map (so if that one is mutable, the wrapped map will also be mutable) and is an instance of scala.collection.Map. In order to be fully idiomatic and benefit from Scala's immutability guarantees, you might need to add another .toMap at the end that will convert it to scala.collection.immutable.Map (which is the default Map).
If you use scala 2.12 or older, instead of scala.jdk.CollectionConverters._ import scala.collection.JavaConverters._.
What is the best way to resolve the compilation error in the example below? Assume that 'm' must be of type GenMap and I do not have control over the arguments of myFun.
import scala.collection.GenMap
object Test {
def myFun(m: Map[Int, String]) = m
val m: GenMap[Int, String] = Map(1 -> "One", 2 -> "two")
//Build error here on m.seq
// Found scala.collection.Map[Int, String]
// Required scala.collection.immutable.Map[Int, String]
val result = myFun(m.seq)
}
EDIT:
I should have been clearer. In my actual use-case I don't have control over myFun, so I have to pass it a Map. The 'm' also arises from another scala component as a GenMap. I need to convert one to another, but there appears to be a conflict between collection.Map and collection.immutable.Map
m.seq.toMap will solve your problem.
According to the signature presented in the API toMap returns a scala.collection.immutable.Map which is said to be required in your error message. scala.collection.Map returned by the seq method is a more general trait which besides being a parent to immutable map is also a parent to the mutable and concurrent map.