Scala: Updating a field of an object in an Option - scala

What is idiomatic way of updating a field in an object inside a scala option?
flag is a boolean field in item,and I just want to reverse its value:
val newOption = itemOption.map(item => item.copy(flag = !item.flag))
Is this correct way?

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.

How to see if an Array contains a value from another Java List in Scala?

I have 1 Scala Array containing Strings and 1 Java Util List containing Strings. I want to check if value of one Array is in the other List, and set a flag accordingly.
def getFlag(JavaList, scalaArray): Boolean = {
val res = JavaList.toArray.filter(x => scalaArray.contains(x))
if (res.isEmpty)
false
else
true
}
the contains doesn't seem to be working. It always shows the size as 0 even when there should be a matching string and I'm not sure why.
How would I fix this or are there any other better methods of doing this? I am trying to get more familiar with Scala any help is appreciated thank you
I would use exists and I would transform the Array into a Set to speed up the check.
// This one for 2.13+
import scala.jdk.CollectionConverters._
// This one for 2.12-
import scala.collection.JavaConverters._
def getFlag(javaList: java.util.List[String], scalaArray: Array[String]): Boolean = {
val values = scalaArray.toSet
javaList.asScala.exists(values.contains)
}
If you get a false, then there are some errors in the strings, maybe try converting them to lower case or checking if there are invisible characters in there.
I am trying to get more familiar with Scala any help is appreciated thank you
My best advice would be try to stay away from Java collections and from plain Arrays. Instead, use collections from the Scala library like: List, Vector, ArraySeq, Set, Map, etc.

scala hashmap get string value returns some()

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)

How to transfer String type to Object type in Scala

I am writing scala application, and want to utilize my java library. I have java API function that takes inputs as Object; however, the scala application that calling such function has input type as string. my code is as following:
val data = Array("foo", "bar")
val dataSource = new MyJavaAPIDataProvider(data)
Because I am using MyJavaAPIDataProvider(Object[] data), the scala code keeps telling me type mismatch. How do I change my scala code data array from a string array to Object array? Thanks
You have to cast the array to Array[Object]
val objs = data.asInstanceOf[Array[Object]]
val dataSource = new MyJavaAPIDataProvider(objs)
Edit:
to complete this answer with Seth Tisue's comment, you also can use:
val data = Array[AnyRef]("foo", "bar")
To avoid having to cast. AnyRef is equivalent to Java's Object.
Based on that, another possibility that comes to my mind is to create an array of AnyRef with the elements of your string array, like this:
Array[AnyRef](data: _*)

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).