Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to use ConcurrentHashMap computeIfAbsent() in Scala

I'm using a ConcurrentHashMap in Scala and I would like to use the computeIfAbsent() method but can't figure out the syntax for the second argument. Can someone show me what would be the proper syntax?

When running the following code

val data = new ConcurrentHashMap[String, LongAdder]

data.computeIfAbsent("bob", k: String => new LongAdder()).increment()

I'm getting the following error

Type mismatch, expected: Function[_ >: String, _ <: LongAdder], actual: (String) => Any

Thanking you in advance

Francis

like image 607
Francis Avatar asked Apr 24 '16 18:04

Francis


People also ask

How do I convert a map to ConcurrentHashMap?

To insert mappings into a ConcurrentHashMap, we can use put() or putAll() methods.

How do you get keys in ConcurrentHashMap?

ConcurrentHashMap keys() method in Java with Examples The keys() method of ConcurrentHashMap class in Java is used to get the enumeration of the keys present in the hashmap. Parameters: The method does not take any parameters. Return value: The method returns an enumeration of the keys of the ConcurrentHashMap.

Can ConcurrentHashMap throws ConcurrentModificationException?

ConcurrentHashMap does not throw ConcurrentModificationException if the underlying collection is modified during an iteration is in progress. Iterators may not reflect the exact state of the collection if it is being modified concurrently.

What is ConcurrentHashMap in Java with example?

A hash table supporting full concurrency of retrievals and high expected concurrency for updates. This class obeys the same functional specification as Hashtable and includes versions of methods corresponding to each method of Hashtable.


2 Answers

The problem is that you're using java.util.concurrent.ConcurrentHashMap, which accepts java.util.function.Function as a parameter for computeIfAbsent() instead of scala.Function1 which you pass to it.

Since scala doesn't support lambda conversion for functional interfaces as Java does (at least not without the -Xexperimental flag), you can solve this by implementing a java.util.function.Function explicitly:

val data = new ConcurrentHashMap[String, LongAdder]
val adderSupplier = new java.util.function.Function[String, LongAdder]() {
  override def apply(t: String): LongAdder = new LongAdder()
}
data.computeIfAbsent("bob", adderSupplier).increment()

Alternatively, if you need this more often, you may write a utility conversion function or even an implicit conversion:

object FunctionConverter {
  implicit def scalaFunctionToJava[From, To](function: (From) => To): java.util.function.Function[From, To] = {
    new java.util.function.Function[From, To] {
      override def apply(input: From): To = function(input)
    }
  }
}

import FunctionConverter._
val data = new ConcurrentHashMap[String, LongAdder]()
data.computeIfAbsent("bob", (k: String) => new LongAdder()) // <- implicit conversion applied here
like image 147
Mifeet Avatar answered Nov 01 '22 16:11

Mifeet


If you enable -Xexperimental flag you can use scala anonymous function notation for this:

scala> val data = new java.util.concurrent.ConcurrentHashMap[String, Int]
data: java.util.concurrent.ConcurrentHashMap[String,Int] = {}

scala> data.computeIfAbsent("bob", _.size)
res0: Int = 3

Note that you still can't pass regular scala Function

scala> val f: String => Int = _.size
f: String => Int = <function1>

scala> data.computeIfAbsent("bob", f)
<console>:13: error: type mismatch;
 found   : String => Int
 required: java.util.function.Function[_ >: String, _ <: Int]
       data.computeIfAbsent("bob", f)
                               ^

But eta-expansion will work

scala> def a(s: String): Int = s.size
a: (s: String)Int

scala> data.computeIfAbsent("bob", a)
res3: Int = 3
like image 39
Łukasz Avatar answered Nov 01 '22 14:11

Łukasz