Find-first-and-transform for Sequence in Kotlin - kotlin

I often stumble upon this problem but don't see a common implementation: how do I idiomatically (functionally) find an element, stop search after the match, and also return a different type (i.e. map whatever matched to another type)?
I've been able to do a workaround with
fun <F,T> Sequence<F>.mapFirst(block: (F) -> T?): T? =
fold(AtomicReference<T>()) { ref, from ->
if (ref.get() != null) return#fold ref
ref.set(block(from))
ref
}.get()
fun main() {
Files.list(someDir).asSequence().map { it.toFile() }.mapFirst { file ->
file.useLines { lines ->
lines.mapFirst { line ->
if (line == "123") line.toInt() else null
}
}
}?.let { num ->
println("num is $num") // will print 123 as an Int
} ?: println("not a single file had a line eq to '123'")
}
But that doesn't stop on the match (when block() returns non-null) and goes to consume all files and all their lines.

A simple for loop is enough to implement mapFirst:
fun <F,T> Sequence<F>.mapFirst(block: (F) -> T?): T? {
for (e in this) {
block(e)?.let { return it }
}
return null
}
If you need a solution without introducing your own extensions (though there's nothing wrong with it), you can use mapNotNull + firstOrNull combination:
files.asSequence()
.mapNotNull { /* read the first line and return not null if it's ok */ }
.firstOrNull()

I would not map the values you discard then, instead do it like this:
sequenceOf(1, 2, 3)
.firstOrNull() { it == 2 }
?.let { it * 2 } ?: 6
First you find the value that matches your condition, then you transform it too whatever you want. In case you don't find a matching element, you assign a default value (in this case 6).

Related

In Kotlin, how can I test and use a value without computing it twice?

Every so often, I find myself wanting to compute a value for some sort of filter operation, but then wanting to use that value when it's already disappeared into the condition-checking thing.
For instance:
val found = list.firstOrNull { slowConversion(it).isWanted() }
if (found != null) {
something(found, slowConversion(found))
}
or
when {
other_conditions -> other_actions
list.any { it.contains(regex1) } -> something(list.firstOrNull { it.contains(regex1) } ?: "!!??")
}
For the slowConversion() I can work with a sequence mapped to pairs, although the terms first and second kinda confuse things a bit...
val pair = list.asSequence().map { it to slowConversion(it) }.firstOrNull { it.second.isWanted() }
if ( pair != null ) {
something(pair.first, pair.second)
}
or if I only want the conversion,
val converted = list.firstNotNullOfOrNull { slowConversion(it).takeIf { it.isWanted() } }
but the best I can come up with to avoid the when duplication involves moving the action part into the condition part!
fun case(s: List<String>, r: Regex) {
val match = s.firstOrNull { it.contains(r) }?.also { something(it) }
return match != null
}
when {
other_conditions -> other_actions
case(list, regex1) -> true
}
At this point, it seems I should just have a stack of function calls linked together with ||
other_things || case(list, regex1) || case(list, regex2) || catchAll(list)
Is there something better or more concise for either of these?
You can write your first example like this:
for(element in list) {
val result = slowConversion(element)
if(result.isWanted()) {
something(element, result)
break
}
}
This might not look very Kotlin-ish, but I think it's pretty straightforward & easy to understand.
For your second example, you can use the find function:
when {
other_conditions -> other_actions
else -> list.find { it.contains(regex1) }?.let(::something)
}
If you have multiple regexes, just iterate over them,
val regexes = listOf(regex1, regex2, ...)
for(regex in regexes) {
val element = list.find { it.contains(regex1) } ?: continue
something(element)
break
}

Kotlin ? vs ?.let {}

Consider this nice utility extension function i wanted to use :
inline infix fun <T> T?.otherwise(other: () -> Unit): T? {
if (this != null) return this
other()
return null
}
It could be very useful for logging stuff when expressions evaluated to null for example:
val x: Any? = null
x?.let { doSomeStuff() } otherwise {Log.d(TAG,"Otherwise happened")}
but I see that it wont work for :
val x: Any? = null
x?.otherwise {Log.d(TAG,"Otherwise happened")}
see here for running example
Well when thinking about it i guess that makes sense that if x is null the ? makes the postfix not be executed, but i dont understand why the let in the first example is any different?
Is it possible to fix the utility to be more robust and work without having to have let in the chain?
First, you can simplify the implementation:
inline infix fun <T> T?.otherwise(other: () -> Unit): T? {
if (this == null) { other() }
return this
}
Or
inline infix fun <T> T?.otherwise(other: () -> Unit): T? =
also { if (it == null) other() }
When you do this:
null?.otherwise { println("Otherwise happened") }
?. means "execute if not null", so otherwise is not executed.
What you need to write is:
null otherwise { println("Otherwise happened") }
Note this is very similar to the ?: operator (as Vadik pointed out in the comments):
null ?: println("Otherwise happened")
The difference is that otherwise always returns the value on the left (the same as also), but ?: returns the value on the right when the value on the left is null.
In my opinion, otherwise is confusing, especially as it always returns the left value despite the name. You would be better to use the ?: operator. Or perhaps rename it to something like alsoIfNull.
The let example executes because, when you don't utilize the infix feature, it looks like this:
x?.let {}.otherwise {println("1")}
Notice that it's not ?.otherwise; therefore, it always executes.
So to use otherwise without let, you can omit the ?.
x.otherwise { ... }
x?.let { doSomeStuff() }.otherwise {Log.d(TAG,"Otherwise happened")}
// ⬇️
val value = if (x != null) {
doSomeStuff()
} else {
null
}
value.otherwise {Log.d(TAG,"Otherwise happened")}
x?.otherwise { Log.d(TAG,"Otherwise happened") }
// ⬇️
if (x != null) {
otherwise { Log.d(TAG,"Otherwise happened") }
} else {
null
}
?. means if the value is not null then execute the method and return the result otherwise return null

How to implement switch-case statement in Kotlin

How to implement equivalent of following Java switch statement code in Kotlin?
switch (5) {
case 1:
// Do code
break;
case 2:
// Do code
break;
case 3:
// Do code
break;
}
You could do like this:
when (x) {
1 -> print("x == 1")
2 -> print("x == 2")
else -> { // Note the block
print("x is neither 1 nor 2")
}
}
extracted from official help
switch in Java is effectively when in Kotlin. The syntax, however, is different.
when(field){
condition -> println("Single call");
conditionalCall(field) -> {
print("Blocks");
println(" take multiple lines");
}
else -> {
println("default");
}
}
Here's an example of different uses:
// This is used in the example; this could obviously be any enum.
enum class SomeEnum{
A, B, C
}
fun something(x: String, y: Int, z: SomeEnum) : Int{
when(x){
"something" -> {
println("You get the idea")
}
else -> {
println("`else` in Kotlin`when` blocks are `default` in Java `switch` blocks")
}
}
when(y){
1 -> println("This works with pretty much anything too")
2 -> println("When blocks don't technically need the variable either.")
}
when {
x.equals("something", true) -> println("These can also be used as shorter if-statements")
x.equals("else", true) -> println("These call `equals` by default")
}
println("And, like with other blocks, you can add `return` in front to make it return values when conditions are met. ")
return when(z){
SomeEnum.A -> 0
SomeEnum.B -> 1
SomeEnum.C -> 2
}
}
Most of these compile to switch, except when { ... }, which compiles to a series of if-statements.
But for most uses, if you use when(field), it compiles to a switch(field).
However, I do want to point out that switch(5) with a bunch of branches is just a waste of time. 5 is always 5. If you use switch, or if-statements, or any other logical operator for that matter, you should use a variable. I'm not sure if the code is just a random example or if that's actual code. I'm pointing this out in case it's the latter.
The switch case is very flexible in kotlin
when(x){
2 -> println("This is 2")
3,4,5,6,7,8 -> println("When x is any number from 3,4,5,6,7,8")
in 9..15 -> println("When x is something from 9 to 15")
//if you want to perform some action
in 20..25 -> {
val action = "Perform some action"
println(action)
}
else -> println("When x does not belong to any of the above case")
}
When Expression
when replaces the switch operator of C-like languages. In the simplest form it looks like this
when (x) {
1 -> print("x == 1")
2 -> print("x == 2")
else -> { // Note the block
print("x is neither 1 nor 2")
}
}
when matches its argument against all branches sequentially until some branch condition is satisfied. when can be used either as an expression or as a statement. If it is used as an expression, the value of the satisfied branch becomes the value of the overall expression. If it is used as a statement, the values of individual branches are ignored. (Just like with if, each branch can be a block, and its value is the value of the last expression in the block.)
From https://kotlinlang.org/docs/reference/control-flow.html#when-expression
when defines a conditional expression with multiple branches. It is similar to the switch statement in C-like languages. Its simple form looks like this.
when (x) {
1 -> print("x == 1")
2 -> print("x == 2")
else -> { // Note the block
print("x is neither 1 nor 2")
}
}
when matches its argument against all branches sequentially until some branch condition is satisfied.
when can be used either as an expression or as a statement. If it is used as an expression, the value of the first matching branch becomes the value of the overall expression. If it is used as a statement, the values of individual branches are ignored. Just like with if, each branch can be a block, and its value is the value of the last expression in the block.
import java.util.*
fun main(args: Array<String>){
println("Hello World");
println("Calculator App");
val scan=Scanner(System.`in`);
println("""
please choose Your Selection to perform
press 1 for addition
press 2 for substraction
press 3 for multipication
press 4 for divider
press 5 for divisible
""");
val opt:Int=scan.nextInt();
println("Enter first Value");
val v1=scan.nextInt();
println("Enter Second Value");
val v2=scan.nextInt();
when(opt){
1->{
println(sum(v1,v2));
}
2->{
println(sub(v1,v2));
}
3->{
println(mul(v1,v2));
}
4->{
println(quotient(v1,v2));
}
5->{
println(reminder(v1,v2));
}
else->{
println("Wrong Input");
}
}
}
fun sum(n1:Int,n2:Int):Int{
return n1+n2;
}
fun sub(n1:Int, n2:Int):Int{
return n1-n2;
}
fun mul(n1:Int ,n2:Int):Int{
return n1*n2;
}
fun quotient(n1:Int, n2:Int):Int{
return n1/n2;
}
fun reminder(n1:Int, n2:Int):Int{
return n1%n2;
}
Just use the when keyword. If you want to make a loop, you can do like this:
var option = ""
var num = ""
while(option != "3") {
println("Choose one of the options below:\n" +
"1 - Hello World\n" +
"2 - Your number\n" +
"3 - Exit")
option = readLine().toString()
// equivalent to switch case in Java //
when (option) {
"1" -> {
println("Hello World!\n")
}
"2" -> {
println("Enter a number: ")
num = readLine().toString()
println("Your number is: " + num + "\n")
}
"3" -> {
println("\nClosing program...")
}
else -> {
println("\nInvalid option!\n")
}
}
}
val operator = '+'
val a = 6
val b = 8
val res = when (operator) {
'+' -> a + b
'-' -> a - b
'*' -> a * b
'/' -> a / b
else -> 0
}
println(res);
We use the following code for common conditions
val operator = '+'
val a = 6
val b = 8
val res = when (operator) {
'+',
'-' -> a - b
'*',
'/' -> a / b
else -> 0
}
println(res);
In kotlin, their is no switch-case statement. But we have when expression similar to switch. Just like if-else or switch, first all conditions are checked, if none matches then else code evaluated.
when (n) {
1 -> {
print("First")
// run your code
}
2 -> print("Second")
3, 4 -> print("Third or Forth") // check multiple conditions for same code
in 1..100 -> print("Number is in the range")
else -> {
print("Undefined")
}
}
There is no need of any break as of switch case.
Here is an example to know Using “when” with arbitrary objects,
VehicleParts is a enum class with four types.
mix is a method which accepts two types of VehicleParts class.
setOf(p1, p2) - Expression can yield any object
setOf is a kotlin standard library function that creates Set containing the objects.
A set is a collection for which the order of items does not matter.
Kotlin is allowed to combine different types to get mutiple values.
When I pass VehicleParts.TWO and VehicleParts.WHEEL, I get "Bicycle".
When I pass VehicleParts.FOUR and VehicleParts.WHEEL, I get "Car".
Sample Code,
enum class VehicleParts {
TWO, WHEEL, FOUR, MULTI
}
fun mix(p1: VehicleParts, p2: VehicleParts) =
when (setOf(p1, p2)) {
setOf(VehicleParts.TWO, VehicleParts.WHEEL) -> "Bicycle"
setOf(VehicleParts.FOUR, VehicleParts.WHEEL) -> "Car"
setOf(VehicleParts.MULTI, VehicleParts.WHEEL) -> "Train"
else -> throw Exception("Dirty Parts")
}
println(mix(VehicleParts.TWO,VehicleParts.WHEEL))
If You want to print or open multiple Activities using switch case (When) in Kotlin then use this code.. Thank you..
var dataMap: Map<String?, String?> = HashMap()
var noteType: String? = ""
when (noteType) {
"BIGTEXT" -> NEW_PAGE(dataMap)
"NORMAL" -> NORMAL_PAGE(dataMap)
"ABOUT"->ABOUT_PAGE((dataMap))
}

Swift 'if let' statement equivalent in Kotlin

In Kotlin is there an equivalent to the Swift code below?
if let a = b.val {
} else {
}
You can use the let-function like this:
val a = b?.let {
// If b is not null.
} ?: run {
// If b is null.
}
Note that you need to call the run function only if you need a block of code. You can remove the run-block if you only have a oneliner after the elvis-operator (?:).
Be aware that the run block will be evaluated either if b is null, or if the let-block evaluates to null.
Because of this, you usually want just an if expression.
val a = if (b == null) {
// ...
} else {
// ...
}
In this case, the else-block will only be evaluated if b is not null.
Let's first ensure we understand the semantics of the provided Swift idiom:
if let a = <expr> {
// then-block
}
else {
// else-block
}
It means this: "if the <expr> results in a non-nil optional, enter the then-block with the symbol a bound to the unwrapped value. Otherwise enter the else block.
Especially note that a is bound only within the then-block. In Kotlin you can easily get this by calling
<expr>?.also { a ->
// then-block
}
and you can add an else-block like this:
<expr>?.also { a ->
// then-block
} ?: run {
// else-block
}
This results in the same semantics as the Swift idiom.
My answer is totally a copy cat from the others. However, I cannot understand their expression easily. So I guess it would be nice to provide an more understandable answer.
In swift:
if let a = b.val {
//use "a" as unwrapped
}
else {
}
In Kotlin:
b.val?.let{a ->
//use "a" as unwrapped
} ?: run{
//else case
}
if let statement
Swift if let Optional Binding (so called if-let statement) is used to extract a non-optional value if one exists, or to do nothing if a value is nil.
Swift's if-let statement:
let b: Int? = 50
if let a: Int = b {
print("Good news!")
} else {
print("Equal to 'nil' or not set")
}
/* RESULT: Good news! */
In Kotlin, like in Swift, to avoid crashes caused by trying to access a null value when it’s not expected, a specific syntax (like b.let { } in second example) is provided for properly unwrapping nullable types:
Kotlin's equivalent1 of Swift's if-let statement:
val b: Int? = null
val a = b
if (a != null) {
println("Good news!")
} else {
println("Equal to 'null' or not set")
}
/* RESULT: Equal to 'null' or not set */
Kotlin’s let method, when used in combination with the safe-call operator ?:, provides a concise way to handle nullable expressions.
Kotlin's inline let function and Elvis Operator of Swift's nil coalescing operator:
val b: Int? = null
val a = b.let { nonNullable -> nonNullable } ?: "Equal to 'null' or not set"
println(a)
/* RESULT: Equal to 'null' or not set */
guard let statement
guard-let statement in Swift is simple and powerful. It checks for some condition and if it evaluates to be false, then the else statement executes which normally will exit a method.
Let's explore a Swift's guard-let statement:
let b: Int? = nil
func method() {
guard let a: Int = b else {
print("Equal to 'nil' or not set")
return
}
print("Good news!")
}
method()
/* RESULT: Equal to 'nil' or not set */
Kotlin's similar effect of Swift's guard-let statement:
Unlike Swift, in Kotlin, there is no guard statement at all. However, you can use the Elvis Operator – ?: for getting a similar effect.
val b: Int? = 50
fun method() {
val a = b ?: return println("Equal to 'null' or not set")
return println("Good news!")
}
method()
/* RESULT: Good news! */
there are two answers above, both got a lot acceptances:
str?.let{ } ?: run { }
str?.also{ } ?: run { }
Both seem to work in most of the usages, but #1 would fail in the following test:
#2 seems better.
Unlike Swift, Its not necessary to unwrap the optional before using it in Kotlin. We could just check if the value is non null and the compiler tracks the information about the check you performed and allows to use it as unwrapped.
In Swift:
if let a = b.val {
//use "a" as unwrapped
} else {
}
In Kotlin:
if b.val != null {
//use "b.val" as unwrapped
} else {
}
Refer Documentation: (null-safety) for more such use cases
Here's how to only execute code when name is not null:
var name: String? = null
name?.let { nameUnwrapp ->
println(nameUnwrapp) // not printed because name was null
}
name = "Alex"
name?.let { nameUnwrapp ->
println(nameUnwrapp) // printed "Alex"
}
Here's my variant, limited to the very common "if not null" case.
First of all, define this somewhere:
inline fun <T> ifNotNull(obj: T?, block: (T) -> Unit) {
if (obj != null) {
block(obj)
}
}
It should probably be internal, to avoid conflicts.
Now, convert this Swift code:
if let item = obj.item {
doSomething(item)
}
To this Kotlin code:
ifNotNull(obj.item) { item ->
doSomething(item)
}
Note that as always with blocks in Kotlin, you can drop the argument and use it:
ifNotNull(obj.item) {
doSomething(it)
}
But if the block is more than 1-2 lines, it's probably best to be explicit.
This is as similar to Swift as I could find.
There is a similar way in kotlin to achieve Swift's style if-let
if (val a = b) {
a.doFirst()
a.doSecond()
}
You can also assigned multiple nullable values
if (val name = nullableName, val age = nullableAge) {
doSomething(name, age)
}
This kind of approach will be more suitable if the nullable values is used for more than 1 times. In my opinion, it helps from the performance aspect because the nullable value will be checked only once.
source: Kotlin Discussion
I'm adding this answer to clarify the accepted answer because it's too big for a comment.
The general pattern here is that you can use any combination of the Scope Functions available in Kotlin separated by the Elvis Operator like this:
<nullable>?.<scope function> {
// code if not null
} :? <scope function> {
// code if null
}
For example:
val gradedStudent = student?.apply {
grade = newGrade
} :? with(newGrade) {
Student().apply { grade = newGrade }
}
The cleanest option in my opinion is this
Swift:
if let a = b.val {
} else {
}
Kotlin
b.val.also { a ->
} ?: run {
}
Swift if let statement in Kotlin
The short answer is use simple IF-ELSE as by the time of this comment there is no equivalent in Kotlin LET,
if(A.isNull()){
// A is null
}else{
// A is not null
}
we can get the same Unwraping syntax like Swift if let using inline fun
inline fun <T:Any?> T?.unwrap(callback: (T)-> Unit) : Boolean {
return if (this != null) {
this?.let(callback)
true
}else {
false
}
}
Uses: :
val name : String? = null
val rollNo : String? = ""
var namesList: ArrayList<String>? = null
if (name.unwrap { name ->
Log.i("Dhiru", "Name have value on it $name")
})else if ( rollNo.unwrap {
Log.i("Dhiru","Roll have value on it")
}) else if (namesList.unwrap { namesList ->
Log.i("Dhiru","This is Called when names list have value ")
}) {
Log.i("Dhiru","No Field have value on it ")
}
The problem with the Any?.let {} ?: run {} constructions is that:
It only allows for one non-null check per statement
If the let block returns null the run block is evaluated anyway
It's not possible to perform multiple checks in a switch/when style
A solution which tackles most of these problems is to define functions like the following:
private inline fun <A> ifNotNull(p1: A?, block: (A) -> Unit): Unit? {
if (p1 != null) {
return block.invoke(p1)
}
return null
}
private inline fun <A, B> ifNotNull(p1: A?, p2: B?, block: (A, B) -> Unit): Unit? {
if (p1 != null && p2 != null) {
return block.invoke(p1, p2)
}
return null
}
private inline fun <A, B, C> ifNotNull(p1: A?, p2: B?, p3: C?, block: (A, B, C) -> Unit): Unit? {
if (p1 != null && p2 != null && p3 != null) {
return block.invoke(p1, p2, p3)
}
return null
}
This would allow for a statement like:
ifNotNull(a, b) { a, b ->
// code when a, b are not null
} ?:
ifNotNull(c) { c ->
// code when a, b are null and c not null
} ?:
ifNotNull(d, e, f) { d, e, f ->
// code when a, b, c are null and d, e, f not null
} ?: run {
// code which should be performed if a, b, c, d, e and f are null
}
The only caveat is that continue and break statements are not supported if executed within a loop compared to Swift's if let equivalent.
Probably I am very late however the easiest way to unwrap and option is
yourOptionalString ?: return
this was all the following lines will have unwrapped string
If b is a member variable then this approach seems most readable to me:
val b = this.b
if (b == null) {
return
}
println("non nullable : ${b}")
This is also consistent with how it works in swift, where a new local variable shadows the member variable.

Best way to null check in Kotlin?

Should I use double =, or triple =?
if(a === null) {
//do something
}
or
if(a == null) {
//do something
}
Similarly for 'not equals':
if(a !== null) {
//do something
}
or
if(a != null) {
//do something
}
A structural equality a == b is translated to
a?.equals(b) ?: (b === null)
Therefore when comparing to null, the structural equality a == null is translated to a referential equality a === null.
According to the docs, there is no point in optimizing your code, so you can use a == null and a != null
Note that if the variable is a mutable property, you won't be able to smart cast it to its non-nullable type inside the if statement (because the value might have been modified by another thread) and you'd have to use the safe call operator with let instead.
Safe call operator ?.
a?.let {
// not null do something
println(it)
println("not null")
}
You can use it in combination with the Elvis operator.
Elvis operator ?: (I'm guessing because the interrogation mark looks like Elvis' hair)
a ?: println("null")
And if you want to run a block of code
a ?: run {
println("null")
println("The King has left the building")
}
Combining the two
a?.let {
println("not null")
println("Wop-bop-a-loom-a-boom-bam-boom")
} ?: run {
println("null")
println("When things go null, don't go with them")
}
Kotlin ways of handling null
Secure Access Operation
val dialog : Dialog? = Dialog()
dialog?.dismiss() // if the dialog will be null,the dismiss call will be omitted
Let function
user?.let {
//Work with non-null user
handleNonNullUser(user)
}
Early exit
fun handleUser(user : User?) {
user ?: return //exit the function if user is null
//Now the compiler knows user is non-null
}
Immutable shadows
var user : User? = null
fun handleUser() {
val user = user ?: return //Return if null, otherwise create immutable shadow
//Work with a local, non-null variable named user
}
Default value
fun getUserName(): String {
//If our nullable reference is not null, use it, otherwise use non-null value
return userName ?: "Anonymous"
}
Use val instead of var
val is read-only, var is mutable. It’s recommended to use as many read-only properties as you can, they are thread-safe.
Use lateinit
Sometimes you can’t use immutable properties. For example, it happens on Android when some property is initialized in onCreate() call. For these situations, Kotlin has a language feature called lateinit.
private lateinit var mAdapter: RecyclerAdapter<Transaction>
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
mAdapter = RecyclerAdapter(R.layout.item_transaction)
}
fun updateTransactions() {
mAdapter.notifyDataSetChanged()
}
Both approaches generate the same bytecode so you can choose whatever you prefer.
Addition to #Benito Bertoli,
the combination is actually unlike if-else
"test" ?. let {
println ( "1. it=$it" )
} ?: let {
println ( "2. it is null!" )
}
The result is:
1. it=test
But if:
"test" ?. let {
println ( "1. it=$it" )
null // finally returns null
} ?: let {
println ( "2. it is null!" )
}
The result is:
1. it=test
2. it is null!
Also, if use elvis first:
null ?: let {
println ( "1. it is null!" )
} ?. let {
println ( "2. it=$it" )
}
The result is:
1. it is null!
2. it=kotlin.Unit
Check useful methods out, it could be useful:
/**
* Performs [R] when [T] is not null. Block [R] will have context of [T]
*/
inline fun <T : Any, R> ifNotNull(input: T?, callback: (T) -> R): R? {
return input?.let(callback)
}
/**
* Checking if [T] is not `null` and if its function completes or satisfies to some condition.
*/
inline fun <T: Any> T?.isNotNullAndSatisfies(check: T.() -> Boolean?): Boolean{
return ifNotNull(this) { it.run(check) } ?: false
}
Below is possible example how to use those functions:
var s: String? = null
// ...
if (s.isNotNullAndSatisfies{ isEmpty() }{
// do something
}
I want to respond to answers of #Benito Bertoli and #BingLi224 and provide imho correct solution.
Problem is with using let, because result of let is it's last expression. You just want to pass the same thing as is passed into it, so also is a better solution. At the same time, after using elvis operator, let is impossible to use, because there is no object to call extension function to so I am using run (functional version). More on that in the scope functions official documentation
Another downside of this compared to using if/when is not being able to use this as an expression so I wouldn't recommend using it :-)
Final code:
"test"?.also {
println("1. it=$it")
} ?: run {
println("2. it is null!")
}
"test"?.also {
println("1. it=$it")
null
} ?: run {
println("2. it is null!")
}
null?.also {
println("1. it is null!")
} ?: run {
println("2. it is null")
}
null?.also {
println("1. it is null!")
null
} ?: run {
println("2. it is null")
}
And output:
1. it=test
1. it=test
2. it is null
2. it is null