Best practice to update ConcurrentHashMap with atomic values - kotlin

I have the ConcurrentHashMap<String, AtomicReference<String>> map and I need to update some value in there.
I wrote the following code:
map.compute(key) { _, value ->
value?.also { reference ->
reference.set(getNewValue())
}
}
It works well, but I'm not sure that it is an optimal solution for this case. Is there any kind of better practice?

Your intent is not clear with your current code:
map.compute(key) { _, value ->
value?.also { reference ->
reference.set(getNewValue())
}
}
I'm not sure if this is indeed your intent, but, with what you wrote, if the key doesn't exist, it will not insert the new value. The lambda will receive null for value, and your lambda definition will return the same null.
To show your intent more clearly, make it more obvious:
map[key]?.also { reference ->
reference.set(getNewValue())
}
But as Holger says in the comment to your question, there's no point using an AtomicReference. Use ConcurrentMap<String, String> instead:
map.computeIfPresent(key) { getNewValue() }
However:
If your intent is actually to update existing or insert new value
then just do this:
map[key] = getNewValue()
If, for some strange reason, you really must use an AtomicReference, then do this:
map.getOrPut(key, AtomicReference<String>()).set(getNewValue())

Related

Why is the value not entering the list?

At 'urichecking2' log, I can see there is value. But in 'uriChecking' the uriList is null.
why the uriList.add not work??
private fun getPhotoList() {
val fileName = intent.getStringExtra("fileName")
Log.d("fileNameChecking", "$fileName")
val listRef = FirebaseStorage.getInstance().reference.child("image").child(fileName!!)
var tmpUrl:Uri = Uri.parse(fileName)
Log.d("firstTmpUri","$tmpUrl")
listRef.listAll()
.addOnSuccessListener { listResult ->
for (item in listResult.items) {
item.downloadUrl.addOnCompleteListener { task ->
if (task.isSuccessful) {
tmpUrl = task.result
Log.d("secondTmpUri","$tmpUrl")
Log.d("urichecking2","$task.result")
uriList.add(task.result)
} else {
}
}.addOnFailureListener {
// Uh-oh, an error occurred!
}
}
}
Log.d("thirdTmpUri","$tmpUrl")
Log.d("urichecking", "$uriList")
}
If I do this, the log is output in the order of first, third, and second, and the desired value is in second, but when third comes out, it returns to the value of first.
The listAll method (like most cloud APIs these days, including downloadUrl which you also use) is asynchronous, since it needs to make a call to the server - which may take time. This means the code executes in a different order than you may expect, which is easiest to see if you add some logging:
Log.d("Firebase","Before starting listAll")
listRef.listAll()
.addOnSuccessListener { listResult ->
Log.d("Firebase","Got listResult")
}
Log.d("Firebase","After starting listAll")
When you run this code it outputs:
Before starting listAll
After starting listAll
Got listResult
This is probably not the order you expected, but it perfectly explains why you can't see the list result. By the time your Log.d("urichecking", "$uriList") runs, none of the uriList.add(task.result) has been called yet.
The solution for this is always the same: any code that needs the list result, has to be inside the addOnCompleteListener callback, be called from there, or be otherwise synchronized.
So in its simplest way:
listRef.listAll()
.addOnSuccessListener { listResult ->
for (item in listResult.items) {
item.downloadUrl.addOnCompleteListener { task ->
if (task.isSuccessful) {
uriList.add(task.result)
Log.d("urichecking", "$uriList")
}
}
}
}
This is an incredibly common mistake to make if you're new to programming with asynchronous APIs, so I recommend checking out
Asynchronous programming techniques in the Kotlin language guide
How to get URL from Firebase Storage getDownloadURL
Can someone help me with logic of the firebase on success listener
Why does my function that calls an API or launches a coroutine return an empty or null value?

Is it considered bad convention when in iterating through two maps, I don't check if key exists in one of them?

I have two maps, let's call them oneMap and twoMap.
I am iterating through all the keys in oneMap, and if the key exists in twoMap I do something
like
fun exampleFunc(oneMap: Map<String, Any>, twoMap: Map<String, Any>) {
for((oneMapKey, oneMapVal) in oneMap) {
if (twoMap.containsKey(oneMapKey)) {
val twoMapVal = twoMap[oneMapKey]
if (twoMapVal == oneMapVal) {
//do more stuff
}
//do more stuff, I have more if statements
}
}
}
To avoid having more nested if statements, I was wondering if instead I could get rid of the
if (twoMap.containsKey(oneMapKey)) check. if twoMap doesn't contain the oneMapKey, we get a null object, and my code still works fine. I was wondering if this is considered bad convention though
fun exampleFunc(oneMap: Map<String, Any>, twoMap: Map<String, Any>) {
for((oneMapKey, oneMapVal) in oneMap) {
val twoMapVal = twoMap[oneMapKey]
if (twoMapVal == oneMapVal) {
//do more stuff
}
//do more stuff, I have more if statements
}
}
It depends. Do you wanna execute the "more stuff" or not?
If you do not wanna execute it you should keep the if condition. Though, if you are concerned about indentation (and deep if hierarchies) you can consider breaking out of the loop:
for((oneMapKey, oneMapVal) in oneMap) {
if (!twoMap.contains(oneMapKey)) continue // continue with next iteration
// do more stuff
}
If your map does not contain null values you can also get the value and check if the result was null (which means the key was not present in the map):
for((oneMapKey, oneMapVal) in oneMap) {
val twoMapVal: Any = twoMap[oneMapKey] ?: continue // continue with next iteration
// do more stuff
}
So its always good practice the remove useless code and (in my opinion) to have less if-hierarchies, as you can easily loose focus when you have lots of nested conditions.
As Tenfour04 says, omitting the containsKey() check is only an option if the map values aren't nullable; if they are, then []/get() gives no way to distinguish between a missing mapping and a mapping to a null value.
But if not (or if you want to ignore null values anyway), then I'd certainly consider omitting the check; the resulting code would be slightly shorter and slightly more efficient, without losing clarity or maintainability.  It could also avoid a potential race condition.  (Though in a multi-threaded situation, I'd be considering more robust protection!)
One variation is to use let() along with the safe-call ?. operator to restrict it to non-null cases:
for ((oneMapKey, oneMapVal) in oneMap) {
twoMap[oneMapKey]?.let { twoMapVal ->
if (twoMapVal == oneMapVal) {
// Do more stuff
}
// Do more stuff
}
}
Using ?.let() this way seems to be a fairly common idiom in Kotlin, so it should be fairly transparent.

Simplify testing of a null variable in an IF statement

In Kotlin I have this (which will not compile):
var list: MutableList<String>? = null
if (list.isNotEmpty()) {
}
This will compile:
var list: MutableList<String>? = null
if (list!!.isNotEmpty()) {
}
However, if list is null, a runtime exception will occur. I could do this:
var list: MutableList<String>? = null
if ((list != null) && list.isNotEmpty()) {
}
But this seems to be repetitive everywhere you need to test if something is null. Is there a more eloquent way of doing this in Kotlin?
In the specific case of checking if the list is not null or empty you can use:
if (!list.isNullOrEmpty())
For a list, it's better to avoid handling null state instead handle only empty and non-empty state. refer http://thefinestartist.com/effective-java/43.
Saying that, we don't need to explicitly check for null check and only empty check alone should do the trick.
var list : MutableList<String> = mutableListOf()
list.add("Test1")
list.takeIf { it.isNotEmpty() }?.forEach { println(it) }
We can use
takeIf
to check whether the list is empty or not.
The first way add this line
list = list?:MutableList<String>()
Second way
val isEmpty = list.isEmpty()?:false
if(isEmpty){}else{}
Third way
if (!list.isNullOrEmpty())
as #AndroidDev suggested
Why are getting an error? Since !! require non-null. if the object is null then it will throw NPE
I think most can be done with the safe operator ?. itself. So if you just want to iterate over the list (or reduce, map, or whatever), you can just simply do so directly:
val sumExpression = list?.joinToString("+") { it.someValue } ?: throw exception? use default value?
list?.forEach { println("an entry in the list: $it") } // if there are entries, just iterate over them... if not, there is nothing to do
list?.also {
consume(it) // consume now is only called if the list is not null
}
Enhancing it then with a condition is also rather easy with takeIf or takeUnless (depending on what you require):
list?.takeIf { it.isNotEmpty() }
Now you still have a nullable list and can again call any of the desired functions as shown before:
list?.takeIf( it.isNotEmpty() }?.also {
consume(it)
}
Also a variant instead of list.isNullOrEmpty() (already shown by gpuntos answer) is to compare the possible null value to the expected outcome, e.g.:
if(list?.isNotEmpty() == true) {
// do something with the non-empty list
}
In case it is null the condition simplifies to basically null == true which is false. However I wouldn't overuse that too much as then you don't see the actual nullable types so easily anymore. Such a usage may make sense, if what you are trying to calculate isn't already supported in its own extension function (as is with isNullOrEmpty()), e.g. for entering the if only if the count is 4 it makes sense to use something like: if (list?.count() == 4)...

How can I find the first element's method result that is not null?

So I have parsers and want to use the first that does return a non-null value. How would I do that most elegantly?
return parsers.map { it.parse(content) }.firstOrNull { it != null }
would map all (million?) parsers before picking the first.
return parsers.firstOrNull { it.parse(content) != null }?.parse(content)
would run the (expensive?) parse() once again.
I know I can
for (parser in parsers) {
val result = parser.parse(content)
if (result != null) {
return result
}
}
return null
parsers.forEach { it.parse(content)?.run { return this } }
return null
is the shortest I can get but it's not nice to read.
I'm pretty sure there is a shortcut here that I don't see.
Use a sequence. It makes your computation lazy, so that you will only compute parse as many times as you need.
return parsers.asSequence()
.map { it.parse(content) }
.find { it != null }
As an alternative to the overhead of a Sequence, or mapping lots of values unnecessarily, you could use an extension method such as:
inline fun <T, R> List<T>.firstMappedNotNull(transform: (T) -> R): R? {
for (e in this)
return transform(e) ?: continue
return null
}
This uses the minimum of mapping function calls and temporary objects.  It's necessarily written in an imperative way, but it's quite short, and makes your own code short, clear, and functional.
(This version returns null if the list was empty or every mapping returned null.  You could of course change the signature and last line to throw an exception instead.)
It's a shame this function isn't already in the standard library.  But it's easy to add your own!
Also, you can use the following code:
parsers.asSequence()
.mapNotNull { it.parse(content) }
.first()

Kotlin Lambda not calling code inside

I encountered the strangest thing.
Lets say I have a text file called "lines.txt". This file contains lines in key value pairs.
test:100
test1:200
test2:300
test3:400
If I read this file in Kotlin the list is not empty however the loop inside the output stream does not get called.
object App {
#JvmStatic
fun main(args: Array<String>) {
// file containing lines of text
val lines = Files.readAllLines(Paths.get("./hashes.txt"))
// not empty
println(lines.size)
// write back a modified version
PrintWriter(FileWriter(File("./lines2.txt"))).use { out -> {
// this doesn't get called
println(lines.size)
lines.forEach {
out.println(it.split(":")[0])
}
}
}
}
}
I don't understand why this is so if anyone can enlighten me that would be awesome.
The list is not empty. A single println(lines.size) will shown you that, because that println is never called.
You simply have one pair of curly braces too much.
change your code to
...
PrintWriter(FileWriter(File("./lines2.txt"))).use { out ->
// list is empty??
println(lines.size)
lines.forEach {
out.println(it.split(":")[0])
}
}
...
The reason is, that a lambda doesn't need its block in curly braces.
So don't write
out -> { ... }
just write
out -> ...
guenther already told you what is wrong with your code, but I think an explanation of what happened is missing.
Consider the following:
val x = { println("y") }
Will it print out y? No, the lamda is never invoked. You have to call x().
Let's take a look at what you did:
val x = { { println("y") } }
x()
Will it print out y? No, because you don't invoke the lambda that prints y.
To make things more clear, let's specify the types explicitely.
val x:() -> (() -> Unit) = { { println("y") } }
Now we can see that the first lambda invoked by x() returns a lambda as well so you would have to call x()() in order to invoke the returned lambda as well.
So using a second pair a curly braces is not just not optional but gives the code a whole new meaning.
But this means that there would be also another solution to your problem.
PrintWriter(FileWriter(File("./lines2.txt"))).use { out -> {
println(lines.size)
lines.forEach {
out.println(it.split(":")[0])
}
}() // <-- add braces here to invoke the lambda
}
So, you can either remove two brackets are add two more. Choice is yours.
Disclaimer: Removing two braces is the way to go. The other option is just to prove a point.