try-with-resources / use / multiple resources - kotlin

I'm using a Java-API which heavily uses the Autoclosable-Interface and thus in Java try-with-resources. However in Java you can specify
try (res1, res2, res3...) {
...
}
Do we have a way to use more than one resource? It looks like the well known callback-hell:
val database = Databases.openDatabase(dbFile)
database.use {
database.createResource(ResourceConfiguration.Builder(resPathName, config).build())
val resMgr = database.getResourceManager(ResourceManagerConfiguration.Builder(resPathName).build())
resMgr.use {
val wtx = resMgr.beginNodeWriteTrx()
wtx.use {
wtx.insertSubtreeAsFirstChild(XMLShredder.createStringReader(resFileToStore))
}
}
}

There is no standard solution for this. If you had all of the Closable instances ready at the start, you could use your own self-defined methods to handle them, like this blog post or this repository shows (and here is the discussion on the official forums that led to the latter).
In your case however, where subsequent objects rely on the previous ones, none of these apply like a regular try-with-resources would.
The only thing I can suggest is trying to define helper functions for yourself that hide the nested use calls, and immediately place you in the second/third/nth layer of these resourcs acquisitions, if that's at all possible.

For simplicity I will use A,B and C for the chained autocloseables.
import java.io.Closeable
open class MockCloseable: Closeable {
override fun close() = TODO("Just for compilation")
}
class A: MockCloseable(){
fun makeB(): B = TODO()
}
class B: MockCloseable(){
fun makeC(): C = TODO()
}
class C: MockCloseable()
Using uses
This would look like this:
A().use {a ->
a.makeB().use {b ->
b.makeC().use {c ->
println(c)
}
}
}
Making a chain use function with a wrapper
Definition
class ChainedCloseable<T: Closeable>(val payload: T, val parents: List<Closeable>) {
fun <U> use(block: (T)->U): U {
try {
return block(payload)
} finally {
payload.close()
parents.asReversed().forEach { it.close() }
}
}
fun <U: Closeable> convert(block: (T)->U): ChainedCloseable<U> {
val newPayload = block(payload)
return ChainedCloseable(newPayload, parents + payload)
}
}
fun <T: Closeable, U: Closeable> T.convert(block:(T)->U): ChainedCloseable<U> {
val new = block(this)
}
Usage
A()
.convert(A::makeB)
.convert(B::makeC)
.use { c ->
println(c)
}
This allows you to avoid having to nest deeply, at the cost of creating wrapper objects.

Method 1: For two resources and using native java resource manager:
Define jUsing() in Kotlin:
// crossinline version:
inline fun <R, A : Closeable?, B : Closeable?>
jUsing(a: A, b: B, crossinline block: (A, B) -> R): R =
J.jUsing(a, b) { c, d -> block(c, d) }
And also Util.jUsing() in Util.java:
Note: Below code is compatible with Java 9+. You can implement it with try-catch-finally to make it compatible with previous versions. See here for an example.
public static <R, A extends AutoCloseable, B extends AutoCloseable> R
jUsing(A a, B b, Function2<A, B, R> block) throws Exception {
try (a; b) {
return block.invoke(a, b);
}
}
(Function2 is kotlin.jvm.functions.Function2.)
Then use like below:
// Download url to destFile and close streams correctly:
jUsing(URL(url).openStream(), FileOutputStream(destFile), InputStream::transferTo)
Note: Above code used Java 9+ InputStream.transferTo() method. See here for a transferTo() Kotlin alternative that is compatible with previous versions.
Note: You can write Kotlin jUsing() method more simple using noinline keyword instead of crossinline. But I think crossinline version has more performance:
// noinline version:
inline fun <R, A : Closeable?, B : Closeable?>
jUsing(a: A, b: B, noinline block: (A, B) -> R): R =
Util.jUsing(a, b, block)
Method 2: For two resources (and with similar usage to method 1):
Thank #zsmb13's answer for the link
/**
* Based on https://github.com/FelixEngl/KotlinUsings/blob/master/Usings.kt
* and with some changes
*/
inline fun <R, A : Closeable, B : Closeable> using(a: A, b: B, block: (A, B) -> R): R {
var exception: Throwable? = null
try {
return block(a, b)
} catch (e: Throwable) {
exception = e
throw e
} finally {
if (exception == null) {
a.close()
b.close()
} else {
try {
a.close()
} catch (closeException: Throwable) {
exception.addSuppressed(closeException)
}
try {
b.close()
} catch (closeException: Throwable) {
exception.addSuppressed(closeException)
}
}
}
}
Method 3: For any number of resources (arrayOf(stream1, stream2, ...).use {...}):
/**
* Based on https://medium.com/#appmattus/effective-kotlin-item-9-prefer-try-with-resources-to-try-finally-aec8c202c30a
* and with a few changes
*/
inline fun <T : Closeable?, R> Array<T>.use(block: (Array<T>) -> R): R {
var exception: Throwable? = null
try {
return block(this)
} catch (e: Throwable) {
exception = e
throw e
} finally {
when (exception) {
null -> forEach { it?.close() }
else -> forEach {
try {
it?.close()
} catch (closeException: Throwable) {
exception.addSuppressed(closeException)
}
}
}
}
}
See referenced link for more details.

Yet another approach for this:
val CloseableContext = ThreadLocal<MutableList<AutoCloseable>>()
inline fun scopeDef(inScope: () -> Unit) {
val oldContext = CloseableContext.get()
val currentContext = mutableListOf<AutoCloseable>()
CloseableContext.set(currentContext)
try {
inScope()
}
finally {
for(i in (currentContext.size - 1) downTo 0) {
try {
currentContext[i].close()
}
catch(e: Exception) {
// TODO: Record as suppressed exception
}
}
CloseableContext.set(oldContext)
}
}
fun <T: AutoCloseable> autoClose(resource: T): T {
CloseableContext.get()?.add(resource) ?: throw IllegalStateException(
"Calling autoClose outside of scopeDef is forbidden")
return resource
}
Usage:
class Close1(val name: String): AutoCloseable {
override fun close() {
println("close $name")
}
}
fun main(args : Array<String>) {
scopeDef {
val c1 = autoClose(Close1("1"))
scopeDef {
val c3 = autoClose(Close1("3"))
}
val c2 = autoClose(Close1(c1.name + "+1"))
}
}
Output:
close 3
close 1+1
close 1

Related

Kotlin: inline function and shared type

I want to call multiple API calls at once using coroutines. So far I used coroutines only to call single API call which returned result in form off success or error. Its using inline function. But I need to understand how to use this inline function parameter for data class.
Class JsonResponse is open class which is result for every single API call. But if I use T inside my data class, its red. If I use there type JsonResponse, it is returning JsonResponse type, but not that exact type what apiBlock suppose to return.
Example: apiBlock can contain task, which will return LoginResponse. LoginResponse is extending JsonResponse. But if I use JsonResponse instead T inside my data class, I will have generic JsonResponse inside my onSuccess callback.
My goal here is to initialize multiple tasks, run them inside coroutine as async, then wait for all tasks to finish and if some of them will fail, return failed ones as array so they can be called again.
Here is code what I want to achieve:
data class ApiTask(
val apiBlock: suspend CoroutineScope.() -> T,
val onSuccess: suspend (T)->Unit)
protected fun<T: JsonResponse> apiCallChained(
apiBlocks: List<ApiTask>,
onError: ((List<ApiTask>)->Unit),
onSuccess: ()->Unit){
val failedTasks = mutableListOf<ApiTask>()
apiBlocks.forEach { apiBlock->
launch(Dispatchers.Main){
val (r, err) = withContext(Dispatchers.IO){
try {
apiBlock.apiBlock(this) to null
} catch (e: ApiCallError) {
null to e
}
}
when {
r != null -> {
apiBlock.onSuccess(r)
}
err != null -> failedTasks.add(apiBlock)
}
}
}
if (failedTasks.isEmpty()) onSuccess.invoke() else onError.invoke(failedTasks)
}
Here is my working example for single API call:
protected fun<T: JsonResponse> apiCall(apiBlock: suspend CoroutineScope.() -> T,
onError: ((ApiCallError)->Unit)? = null,
onDone: (()->Unit)? = null,
onSuccess: suspend (T)->Unit): Job {
return launch(Dispatchers.Main){
val (r, err) = withContext(Dispatchers.IO){
try {
apiBlock() to null
} catch (e: ApiCallError) {
null to e
}
}
onDone?.invoke()
when {
r != null -> onSuccess(r)
err != null -> {
onError?.invoke(err)
}
}
}
}
Example of ApiBlock parameter value:
class ApiLogin(js: JSONObject): JsonResponse(js) {
companion object {
#Throws(ApiCallError::class)
operator fun invoke(api: AppApi, email: String, pass: String): ApiLogin{
return ApiLogin(api.apiLoginUser(email, pass))
}
}
class LoginServerResponse(js: JSONObject): JsonResponse(js){
val httpCode by JsInt("httpCode")
val session by JsString("session")
}
val r = LoginServerResponse(js)
}
This class is then used as
apiBlock = { ApiLogin(app.api, email, pass) }
UPDATE:
Fixed it like this, its working.
data class ApiTask<out T: JsonResponse>(
val apiBlock: suspend CoroutineScope.() -> T,
val onSuccess: suspend (#UnsafeVariance T)->Unit)
Your ApiTask also needs a generic parameter:
data class ApiTask<T : JsonResponse>(
val apiBlock: suspend CoroutineScope.() -> T,
val onSuccess: suspend (T) -> Unit
)
Then you have to add this generic parameter in the apiCallChained function too:
protected fun <T : JsonResponse> apiCallChained(
apiBlocks: List<ApiTask<T>>,
onError: ((List<ApiTask<T>>) -> Unit),
onSuccess: () -> Unit
) {
val failedTasks = mutableListOf<ApiTask<T>>()
apiBlocks.forEach { apiBlock ->
launch(Dispatchers.Main) {
val (r, err) = withContext(Dispatchers.IO) {
try {
apiBlock.apiBlock(this) to null
} catch (e: ApiCallError) {
null to e
}
}
when {
r != null -> {
apiBlock.onSuccess(r)
}
err != null -> failedTasks.add(apiBlock)
}
}
}
if (failedTasks.isEmpty()) onSuccess.invoke() else onError.invoke(failedTasks)
}

Infix Not enough information to infer type variable T

what a difference does make the "." for an infix function in Kotlin?
Here is my example of java "try catch" DSL usage:
this compiles OK
try_(openFile("1"), openFile("2")) { (streamIn, streamOut) ->
doMyStuffIfYouKnowWhatImTalkingAbout(streamIn, streamOut)
} catch { error: NullPointerException ->
print("Kotlin has a null pointer exception ;)")
} catch { error: RuntimeException ->
print("Bad things happen, take care")
} finally {
print("It's time to go home")
}
this compiles OK
try_(openFile("1"), openFile("2")) { (streamIn, streamOut) ->
doMyStuffIfYouKnowWhatImTalkingAbout(streamIn, streamOut)
}.catch<NullPointerException> {
// this compiles OK
}.catch<RuntimeException> {
// this compiles OK
} finally {
// this compiles OK
}
this DOESN'T compile
try_(openFile("1"), openFile("2")) { (streamIn, streamOut) ->
doMyStuffIfYouKnowWhatImTalkingAbout(streamIn, streamOut)
} catch<NullPointerException> {
// this DOESN'T compile due to Not enough information to infer type variable T
} catch<RuntimeException> {
// this DOESN'T compile due to Not enough information to infer type variable T
} finally {
// this compiles
}
Here is an implementation of it where the infix function catch is defined:
inline fun <T : AutoCloseable> try_(vararg resources: T, block: (Array<out T>) -> Unit): Throwable? = try {
block(resources)
null
} catch (error: Throwable) {
error
} finally {
resources.forEach {
try {
it.close()
} catch (ignore: Throwable) {
}
}
}
inline infix fun <reified T : Throwable> Throwable?.catch(block: (T) -> Unit) =
if (this is T) {
block(this)
null
} else this
inline infix fun Throwable?.finally(block: () -> Unit) = block()
So why does }.catch<RuntimeException> { works but this } catch<RuntimeException> { doesn't?

How to check Kotlin BufferedReader use { return something } has called method close()?

My sample Kotlin about BufferedReader().use {}
I wonder if the close() is called when I return early in the use block
fun main() {
sendGet()
}
fun sendGet() {
val queryUrl = "http://www.google.com/search?q=kotlin&ie=utf-8&oe=utf-8"
val url = URL(queryUrl)
val conn = url.openConnection() as HttpURLConnection
conn.requestMethod = "GET"
conn.setRequestProperty("User-Agent", "Mozilla/5.0")
val responseCode = conn.responseCode
println("Response code: ${responseCode}")
when (responseCode) {
200 -> {
println("response: ${conn.getResponseText()}")
}
else -> println("Bad response code: ${responseCode}")
}
}
private fun HttpURLConnection.getResponseText(): String {
BufferedReader(InputStreamReader(inputStream)).use {
return it.readText()
}
}
You can see the source code for use in stdlib by navigating using "Go to implementation" (Cmd + B on a Mac):
public inline fun <T : Closeable?, R> T.use(block: (T) -> R): R {
var exception: Throwable? = null
try {
return block(this)
} catch (e: Throwable) {
exception = e
throw e
} finally {
when {
apiVersionIsAtLeast(1, 1, 0) -> this.closeFinally(exception)
this == null -> {}
exception == null -> close()
else ->
try {
close()
} catch (closeException: Throwable) {
// cause.addSuppressed(closeException) // ignored here
}
}
}
}
Because the call to close is inside the finally block, it will execute even on an early return.

My own solution for Kotlin's try-with-resources absence

Kotlin provides the use function for Closeable objects, but it seems they forgot to consider AutoCloseable (e.g. DB prepared statements) for the try-with-resources full Java equivalent.
I've implemented the next "home-made" solution:
inline fun <T:AutoCloseable,R> trywr(closeable: T, block: (T) -> R): R {
try {
return block(closeable);
} finally {
closeable.close()
}
}
Then you can use it the next way:
fun countEvents(sc: EventSearchCriteria?): Long {
return trywr(connection.prepareStatement("SELECT COUNT(*) FROM event")) {
var rs = it.executeQuery()
rs.next()
rs.getLong(1)
}
}
I'm new to Kotlin and I would like to know if I'm missing something important in my own solution that could give me problems/leakages in a production environment.
Your implementation will work fine but it's different from a standard try-with-resources implementation. If you want it to work like in Java you should do something like that:
inline fun <T : AutoCloseable, R> trywr(closeable: T, block: (T) -> R): R {
var currentThrowable: java.lang.Throwable? = null
try {
return block(closeable)
} catch (throwable: Throwable) {
currentThrowable = throwable as java.lang.Throwable
throw throwable
} finally {
if (currentThrowable != null) {
try {
closeable.close()
} catch (throwable: Throwable) {
currentThrowable.addSuppressed(throwable)
}
} else {
closeable.close()
}
}
}
UPDATE:
As mfulton26 pointed out in his comment kotlin.Throwable doesn't contain addSuppressed(Throwable) method so we have to cast kotlin.Throwable to java.lang.Throwable to make the code work.
Since Kotlin 1.1, .use has an AutoCloseable implementation.
#SinceKotlin("1.1")
#Suppress("INVISIBLE_REFERENCE", "INVISIBLE_MEMBER")
#kotlin.internal.InlineOnly
public inline fun <T : AutoCloseable?, R> T.use(block: (T) -> R): R {
var exception: Throwable? = null
try {
return block(this)
} catch (e: Throwable) {
exception = e
throw e
} finally {
this.closeFinally(exception)
}
}
Copied from source
I think what you want is use() as defined on Closable.

Idiomatic way of handling nullable or empty List in Kotlin

Say I have a variable activities of type List<Any>?. If the list is not null and not empty, I want to do something, otherwise I want to do something else. I came up with following solution:
when {
activities != null && !activities.empty -> doSomething
else -> doSomethingElse
}
Is there a more idiomatic way to do this in Kotlin?
For some simple actions you can use the safe call operator, assuming the action also respects not operating on an empty list (to handle your case of both null and empty:
myList?.forEach { ...only iterates if not null and not empty }
For other actions. you can write an extension function -- two variations depending on if you want to receive the list as this or as a parameter:
inline fun <E: Any, T: Collection<E>> T?.withNotNullNorEmpty(func: T.() -> Unit): Unit {
if (this != null && this.isNotEmpty()) {
with (this) { func() }
}
}
inline fun <E: Any, T: Collection<E>> T?.whenNotNullNorEmpty(func: (T) -> Unit): Unit {
if (this != null && this.isNotEmpty()) {
func(this)
}
}
Which you can use as:
fun foo() {
val something: List<String>? = makeListOrNot()
something.withNotNullNorEmpty {
// do anything I want, list is `this`
}
something.whenNotNullNorEmpty { myList ->
// do anything I want, list is `myList`
}
}
You can also do inverse function:
inline fun <E: Any, T: Collection<E>> T?.withNullOrEmpty(func: () -> Unit): Unit {
if (this == null || this.isEmpty()) {
func()
}
}
I would avoid chaining these because then you are replacing an if or when statement with something more wordy. And you are getting more into the realm that the alternatives I mention below provide, which is full branching for success/failure situations.
Note: these extensions were generalized to all descendants of Collections holding non null values. And work for more than just Lists.
Alternatives:
The Result library for Kotlin gives a nice way to handle your case of "do this, or that" based on response values. For Promises, you can find the same thing in the Kovenant library.
Both of these libraries give you manner for returning alternative results from a single function, and also for branching the code based on the results. They do require that you are controlling the provider of the "answer" that is acted upon.
These are good Kotlin alternatives to Optional and Maybe.
Exploring the extension Functions Further (and maybe too much)
This section is just to show that when you hit an issue like the question raised here, you can easily find many answers in Kotlin to make coding the way you want it to be. If the world isn't likeable, change the world. It isn't intended as a good or bad answer, but rather additional information.
If you like the extension functions and want to consider chaining them in an expression, I would probably change them as follows...
The withXyz flavours to return this and the whenXyz should return a new type allowing the whole collection to become some new one (maybe even unrelated to the original). Resulting in code like the following:
val BAD_PREFIX = "abc"
fun example(someList: List<String>?) {
someList?.filterNot { it.startsWith(BAD_PREFIX) }
?.sorted()
.withNotNullNorEmpty {
// do something with `this` list and return itself automatically
}
.whenNotNullNorEmpty { list ->
// do something to replace `list` with something new
listOf("x","y","z")
}
.whenNullOrEmpty {
// other code returning something new to replace the null or empty list
setOf("was","null","but","not","now")
}
}
Note: full code for this version is at the end of the post (1)
But you could also go a completely new direction with a custom "this otherwise that" mechanism:
fun foo(someList: List<String>?) {
someList.whenNullOrEmpty {
// other code
}
.otherwise { list ->
// do something with `list`
}
}
There are no limits, be creative and learn the power of extensions, try new ideas, and as you can see there are many variations to how people want to code these type of situations. The stdlib cannot support 8 variations of these type of methods without being confusing. But each development group can have extensions that match their coding style.
Note: full code for this version is at the end of the post (2)
Sample code 1: Here is the full code for the "chained" version:
inline fun <E: Any, T: Collection<E>> T?.withNotNullNorEmpty(func: T.() -> Unit): T? {
if (this != null && this.isNotEmpty()) {
with (this) { func() }
}
return this
}
inline fun <E: Any, T: Collection<E>, R: Any> T?.whenNotNullNorEmpty(func: (T) -> R?): R? {
if (this != null && this.isNotEmpty()) {
return func(this)
}
return null
}
inline fun <E: Any, T: Collection<E>> T?.withNullOrEmpty(func: () -> Unit): T? {
if (this == null || this.isEmpty()) {
func()
}
return this
}
inline fun <E: Any, T: Collection<E>, R: Any> T?.whenNullOrEmpty(func: () -> R?): R? {
if (this == null || this.isEmpty()) {
return func()
}
return null
}
Sample Code 2: Here is the full code for a "this otherwise that" library (with unit test):
inline fun <E : Any, T : Collection<E>> T?.withNotNullNorEmpty(func: T.() -> Unit): Otherwise {
return if (this != null && this.isNotEmpty()) {
with (this) { func() }
OtherwiseIgnore
} else {
OtherwiseInvoke
}
}
inline fun <E : Any, T : Collection<E>> T?.whenNotNullNorEmpty(func: (T) -> Unit): Otherwise {
return if (this != null && this.isNotEmpty()) {
func(this)
OtherwiseIgnore
} else {
OtherwiseInvoke
}
}
inline fun <E : Any, T : Collection<E>> T?.withNullOrEmpty(func: () -> Unit): OtherwiseWithValue<T> {
return if (this == null || this.isEmpty()) {
func()
OtherwiseWithValueIgnore<T>()
} else {
OtherwiseWithValueInvoke(this)
}
}
inline fun <E : Any, T : Collection<E>> T?.whenNullOrEmpty(func: () -> Unit): OtherwiseWhenValue<T> {
return if (this == null || this.isEmpty()) {
func()
OtherwiseWhenValueIgnore<T>()
} else {
OtherwiseWhenValueInvoke(this)
}
}
interface Otherwise {
fun otherwise(func: () -> Unit): Unit
}
object OtherwiseInvoke : Otherwise {
override fun otherwise(func: () -> Unit): Unit {
func()
}
}
object OtherwiseIgnore : Otherwise {
override fun otherwise(func: () -> Unit): Unit {
}
}
interface OtherwiseWithValue<T> {
fun otherwise(func: T.() -> Unit): Unit
}
class OtherwiseWithValueInvoke<T>(val value: T) : OtherwiseWithValue<T> {
override fun otherwise(func: T.() -> Unit): Unit {
with (value) { func() }
}
}
class OtherwiseWithValueIgnore<T> : OtherwiseWithValue<T> {
override fun otherwise(func: T.() -> Unit): Unit {
}
}
interface OtherwiseWhenValue<T> {
fun otherwise(func: (T) -> Unit): Unit
}
class OtherwiseWhenValueInvoke<T>(val value: T) : OtherwiseWhenValue<T> {
override fun otherwise(func: (T) -> Unit): Unit {
func(value)
}
}
class OtherwiseWhenValueIgnore<T> : OtherwiseWhenValue<T> {
override fun otherwise(func: (T) -> Unit): Unit {
}
}
class TestBrancher {
#Test fun testOne() {
// when NOT null or empty
emptyList<String>().whenNotNullNorEmpty { list ->
fail("should not branch here")
}.otherwise {
// sucess
}
nullList<String>().whenNotNullNorEmpty { list ->
fail("should not branch here")
}.otherwise {
// sucess
}
listOf("a", "b").whenNotNullNorEmpty { list ->
assertEquals(listOf("a", "b"), list)
}.otherwise {
fail("should not branch here")
}
// when YES null or empty
emptyList<String>().whenNullOrEmpty {
// sucess
}.otherwise { list ->
fail("should not branch here")
}
nullList<String>().whenNullOrEmpty {
// success
}.otherwise {
fail("should not branch here")
}
listOf("a", "b").whenNullOrEmpty {
fail("should not branch here")
}.otherwise { list ->
assertEquals(listOf("a", "b"), list)
}
// with NOT null or empty
emptyList<String>().withNotNullNorEmpty {
fail("should not branch here")
}.otherwise {
// sucess
}
nullList<String>().withNotNullNorEmpty {
fail("should not branch here")
}.otherwise {
// sucess
}
listOf("a", "b").withNotNullNorEmpty {
assertEquals(listOf("a", "b"), this)
}.otherwise {
fail("should not branch here")
}
// with YES null or empty
emptyList<String>().withNullOrEmpty {
// sucess
}.otherwise {
fail("should not branch here")
}
nullList<String>().withNullOrEmpty {
// success
}.otherwise {
fail("should not branch here")
}
listOf("a", "b").withNullOrEmpty {
fail("should not branch here")
}.otherwise {
assertEquals(listOf("a", "b"), this)
}
}
fun <T : Any> nullList(): List<T>? = null
}
UPDATE:
kotlin 1.3 provide isNullOrEmpty now!
https://twitter.com/kotlin/status/1050426794682306562
try this! very clear.
var array: List<String>? = null
if (array.orEmpty().isEmpty()) {
// empty
} else {
// not empty
}
More simplest way would be,
if(activities?.isNotEmpty() == true) doSomething() else doSomethingElse()
Because of the safe call on activities?, the return value is Boolean? which can either be true, false or null. In order to use this expression in an if, we need to explicitly check if it's true
In addition to the other answers, you can also use the safe-call operator in combination with the extension method isNotEmpty(). Because of the safe call, the return value is actually Boolean? which can either be true, false or null. To use the expression in an if or when clause, you'll need to explictly check if it's true:
when {
activities?.isNotEmpty() == true -> doSomething
else -> doSomethingElse
}
Alternative syntax using the elvis operator:
when {
activities?.isNotEmpty() ?: false -> doSomething
else -> doSomethingElse
}
Consider using ?.forEach if appropriate
activities?.forEach {
doSmth(it)
}
If you want exactly the behavior you described I think your variant reads better then anything else more concise I can think of. (Yet simple if should suffice)
The actual method to use in Kotlin 1.3 is isNullOrEmpty like what was mentioned in this answer: https://stackoverflow.com/a/48056456/2735286
Here is an example of its usage:
fun main(args: Array<String>) {
var array: MutableList<String>? = null
println(array.isNullOrEmpty()) // true
array = mutableListOf()
println(array.isNullOrEmpty()) // true
array = mutableListOf("a")
println(array.isNullOrEmpty()) // false
}
This example prints out:
true
true
false
Kotlin 1.3 has extension isNullOrEmpty. The brief answer is:
if (activities.isNullOrEmpty) doSomething
else doSomethingElse
Extension is defined as:
fun <T> Collection<T>?.isNullOrEmpty(): Boolean
Similar extension exists for String and Array.
In my case prices is a optional.I handle the case in the following way with orEmpty() which returns the given array or an empty array if the given array is null.
val safeArray = poi.prices.orEmpty()
if (!safeArray.isEmpty()) {
...
}
Firstly I wanted to advise to make extension function in addition to #mlatu's answer, which handles else condition
public inline fun Map.forEachElse(operation: (Map.Entry) -> Unit, elseBlock: () -> Unit): Unit {
if (!empty)
for (element in this) operation(element)
else
elseBlock()
}
But the usage is no so beautiful.
Actually you are looking for a Maybe monad