scala hashmap get string value returns some() - scala

val vJsonLoc = new HashMap[String, String]();
def getPrevJson(s:String) = vJsonLoc.get(s)
val previousFile = getPrevJson(s"/${site.toLowerCase}/$languagePath/$channel/v$v/$segment")
this returns
Some(/Users/abc/git/abc-c2c/)
on trying to append string previousFile + "/" + index + ".json"
the result is Some(/Users/abc/git/abc-c2c/)/0.json when the desired result is /Users/abc/git/abc-c2c/0.json
Guess this is some concept of Option that have not understood. New to scala.

As you pointed out, you're getting back an Option type, and not a direct reference to the String contained in your data structure. This is a very standard Scala practice, allowing you to better handle cases where an expected value might not be present in your data structure.
For example, in Java, this type of method typically returns the value if it exists and null if it doesn't. This means, however, subsequent code could be operating on the null value and thus you'd need further protection against exceptions.
In Scala, you're getting a reference to an object which may, or may not, have the value you expect. This is the Option type, and can be either Some (in which case the reference is accessible) or None (in which case you have several options for handling it).
Consider your code:
val vJsonLoc = new HashMap[String, String]();
def getPrevJson(s:String) = vJsonLoc.get(s)
val previousFile = getPrevJson(s"/${site.toLowerCase}/$languagePath/$channel/v$v/$segment")
If the HashMap returned String, your previousFile reference could point to either a null value or to a String value. You'd need to protect against a potential exception (regular practice in Java).
But in Scala, get is returning an Option type, which can be handled in a number of ways:
val previousFile = getPrevJson("your_string").getOrElse("")
//or
val previousFile = getPrevJson("your_string") match {
case Some(ref) => ref
case None => ""
}
The resulting reference previousFile will point to a String value: either the expected value ("get") or the empty string ("OrElse").

Scala Map on get returns Option. Use vJsonLoc(s) instead of vJsonLoc.get(s)

Related

How to avoid NullPointerException in Scala while storing query result in variable

Here is a code that requires a change:
val activityDate = validation.select("activity_date").first.get(0).toString
When we run a job, 'activityDate' might return null as a result of query since there might not be any data in db. In this case we get NullPointerException. I need to update this code to avoid NPE.
I tried to do it in different ways but there is always smth missing. I should probably use Match Expression here but have face some errors while initializing it.
The usual way to model some kind of data that might or might not be there in Scala is the Option type. The Option type has two concrete implementations, Some for a value which is there and the None singleton to represent any absent value. Option conveniently has a constructor that wraps a nullable value and turns it into either a Some(value) for non-null values and None for nulls. You can use it as follows:
Option(validation.select("activity_date").first.get(0))
You can apply transformations to it using various combinators. If you want to transform the piece of data itself into something more meaningful for your application, map is usually a good call. The following applies the logic you had before:
val activityDate: Option[String] =
Option(validation.select("activity_date").first.get(0)).
map { activityDate => activityDate.toString }
Note that now activityDate is an Option itself, which means that you have to explicitly handle the case in which the data is not there. You can do so with a match on the concrete type of the option as follows:
activityDate match {
case Some(date) => // `date` is there for sure!
case None => // handle the `select` returned nothing
}
Altenrnatively if you want to apply a default value you can use the getOrElse method on the Option:
val activityDate: String =
Option(validation.select("activity_date").first.get(0)).
map { activityDate => activityDate.toString }.
getOrElse("No Data")
Another possibility to apply a default value on a None and a function to the value in a Some is using fold:
val activityDate: String =
Option(validation.select("activity_date").first.get(0)).
fold("No Data")(activityDate => activityDate.toString)
As a final note, you can shorten anonymous functions in these cases as follows:
val activityDate: String =
Option(validation.select("activity_date").first.get(0)).
fold("No Data")(_.toString)
Where _ is used to refer to the only parameter.

why use a method with no parameter lists over a val

I came across this function in Scala def nullable: Boolean = true. I understand what does this function do, but I want to know is there specific name for this kind of function, and what's the motivation not using var
Firstly, I would be very precise in scala: use the word Function to only ever mean an instance of FunctionN and use the word Method when talking about a def (which may have zero or more parameter lists). Secondly, this most definitely does have a body (albeit not enclosed in braces). Its body is the expression true (i.e. a boolean literal).
I assume that you really mean to ask: "why use a method with no parameter lists over a val?"
When deciding whether to represent some property of your class, you can choose between a method and a value (advice: avoid using var). Often, if the property involves no side effects, we can use a def with no parameter lists (the scala idiom is that a def with a single, empty parameter list implies side-effects).
Hence we may choose any of the following, all of which are semantically equivalent at the use-site (except for performance characteristics):
case class Foo(s: String) {
//Eager - we calculate and store the value regardless of whether
// it is ever used
val isEmpty = s.isEmpty
}
case class Foo(s: String) {
//Lazy - we calculate and store the value when it
// it is first used
lazy val isEmpty = s.isEmpty
}
case class Foo(s: String) {
//Non-strict - we calculate the value each time
// it is used
def isEmpty = s.isEmpty
}
Hence we might take the following advice
If the value is computationally expensive to calculate and we are sure we will use it multiple times, use val
If the value is computationally expensive and we may use it zero or many times, use lazy val
If the value is space-expensive and we think it will be generally used a most once, use def
However, there is an additional consideration; using a val (or lazy val) is likely to be of benefit to debugging using an IDE which generally can show you in an inspection window the value of any in-scope vals
The primary difference of the use of def or var/val is the when the value will be executed.
the def defines a name for a value, the value on the right will be executed when it is called (called by name), meaning it is lazy
and var defines a name for a value, and it is execute it's evaluated, eagerly upon definition

avoid type conversion in Scala

I have this weird requirement where data comes in as name ->value pair from a service and all the name-> value type is string only (which really they are not but that's how data is stored)
This is a simplified illustration.
case class EntityObject(type:String,value:String)
EntityObject("boolean","true")
now when getting that EntityObject if type is "boolean" then I have to make sure value is not anything else but boolean so first get type out and check value and cast value to that type. e.g in this case check value is boolean so have to cast string value to boolean to validate. If it was anything else besides boolean then it should fail.
e.g. if data came in as below, casting will fail and it should report back to the caller about this error.
EntityObject("boolean","1")
Due to this weird requirement it forces type conversion in validation code which doesn't look elegant and against type safe programming. Any elegant way to handle this in scala (may be in a more type safe manner)?
Here is where I'm going to channel an idea taken from a tweet by Miles Sabin in regards to hereogenous mappings (see this gist on github.) If you know the type of object mapping names a head of time you can use a nifty little trick which involves dependent types. Hold on, 'cause it's a wild ride:
trait AssocConv[K] { type V ; def convert: String => V }
def makeConv[V0](name: String, con: String => V0) = new AssocConv[name.type]{
V = V0
val convert = con
}
implicit val boolConv = makeConv("boolean", yourMappingFunc)
def convEntity(name: String, value: String)(implicit conv: AssocConv[name.type]): Try[conv.V] = Try{ conv.convert(value) }
I haven't tested this but it "should" work. I've also enclosed it in a Scala Try so that it catches exceptions thrown by your conversion function (in case you're doing things like _.toInt as the converter.)
You're really talking about conversion, not casting. Casting would be if the value really were an instance of Boolean at runtime, whereas what you have is a String representation of a Boolean.
If you're already working with a case class, I think a pattern matching expression would work pretty well here.
For example,
def convert(entity : EntityObject) : Any = entity match {
case EntityObject("boolean", "true") => true
case EntityObject("boolean", "false") => false
case EntityObject("string", s) => s
// TODO: add Regex-based matchers for numeric types
}
Anything that doesn't match one of the specified patterns would cause a MatchError, or you could put a catchall expression at the end to throw your own exception.
In this particular example, since the function returns Any, the calling coffee would need to do an actual type cast to get the specific type, but at least by that point all validation/conversion would have already been performed. Alternatively, you could just put the code that uses the values directly into the above function and avoid casting. I don't know what your specific needs are, so I can't offer anything more detailed.

How to get object from Play cache (scala)

How to get object from Play cache (scala)
Code to set:
play.api.cache.Cache.set("mykey98", new Product(98), 0)
Code to get:
val product1: Option[Any] = play.api.cache.Cache.get("mykey98")
I get Option object. How to get actual Product object I stored in first step.
First and foremost, I would suggest using Cache.getAs, which takes a type parameter. That way you won't be stuck with Option[Any]. There are a few ways you can do this. In my example, I'll use String, but it will work the same with any other class. My preferred way is by pattern matching:
import play.api.cache.Cache
Cache.set("mykey", "cached string", 0)
val myString:String = Cache.getAs[String]("mykey") match {
case Some(string) => string
case None => SomeOtherClass.getNewString() // or other code to handle an expired key
}
This example is a bit over-simplified for pattern matching, but I think its a nicer method when needing to branch code based on the existence of a key. You could also use Cache.getOrElse:
val myString:String = Cache.getOrElse[String]("mykey") {
SomeOtherClass.getNewString()
}
In your specific case, replace String with Product, then change the code to handle what will happen if the key does not exist (such as setting a default key).

Scala match/compare enumerations

I have an enumeration that I want to use in pattern matches in an actor. I'm not getting what i'd expect and, now, I'm suspecting I'm missing something simple.
My enumeration,
object Ops extends Enumeration {
val Create = Value("create")
val Delete = Value("delete")
}
Then, I create an Ops from a String:
val op = Ops.valueOf("create")
Inside my match, I have:
case (Ops.Create, ...)
But Ops.Create doesn't seem to equal ops.valueOf("create")
The former is just an atom 'create' and the later is Some(create)
Hopefully, this is enough info for someone to tell me what I'm missing...
Thanks
If you are just trying to get a copy of Create, then you should refer to it directly in your code:
val op = Ops.Create
But if you are parsing it from a string, the string might contain junk, so valueOf returns an Option:
val op1 = Ops.valueOf("create") // Some(Ops.Create)
val op2 = Ops.valueOf("delete") // Some(Ops.Delete)
val op3 = Ops.valueOf("aljeaw") // None
Now, in your match you can just carry along the Option[Ops.Value] and look for:
case(Some(Ops.Create),...)
and you have built-in robustness to junk as input.
Enumeration.valueOf returns None or Some, because you may be asking to create a value that doesn't exist. In your case, for example, Ops.valueOf("blah") would return None, since you don't have an appropriate enumeration value.
To be honest, in this case, I'd use a case class or a case object instead of an Enumeration (they provide better type safety).
It looks like I needed to use the 'get' method of the returned Some to actually get what I wanted. E.g.
ops.valueOf("create").get == Ops.Create
Seems neither intuitive nor friendly but it works.