Kotlin Tips & Tricks (1): there’s no need for ternary operator.
Reason
:-
Kotlin said I don’t have ternary operator, it’s bad for readabilit
- the idea is that the former expression is more readable since everybody knows what
if else
does, ? :
The Elvis operator is part of many programming languages, e.g. Kotlin but also Groovy or C#. may be unclear if you're not familiar with the syntax already.
Alternative
(1) if statament or when statment
if
or when in Kotlin is not a statement but an expression (i.e. it evaluates to a value),
if (condition) exp1 else exp2
if (a) b else c
in the case where you have multiple statements inside the body of an if
branch (or the body of else
or else if
), the last line of the block is the value of that branch
when(a) {
true -> b
false -> c
}
(2) Elvis Presley
the Elvis operator
?:
is a binary operator that returns its first operand if that operand istrue
, and otherwise evaluates and returns its second operand.
x ?: y // return x if x is not null, y otherwise. //Make sure that y is not null or return will be null if both x and y are null
- the Elvis operator is the ternary operator with its second operand omitted.
- This can be used to guarantee that an expression won’t return a null value, as you’ll provide a non-nullable value if the provided value is null.
- The name Elvis Operator comes from the famous American singer Elvis Presley. His hairstyle resembles a Question Mark
- Instead of the first operand having to result in a boolean, it must result in an object reference. If the resulting object reference is not
null
, it is returned. Otherwise the value of the second operand (which may benull
) is returned.
fun getData(): String { //return type isn't nullable
val nullableString: String? = getPotentialNull() //This
variable may be null
return nullableString?: "Default Not-Null String"
}
In Kotlin, you could use any expression as second operand
, such as a throw Exception
expression
return nullStr ?: throw IllegalResponseException("fun return null")
?:
gives you a way to handle the fallback case elgantely even if you have multiple layers of fallback. If so, you can simply chain multiply Elvis operators, like here:
val l = listOf(1, 2, 3)val x = l.firstOrNull { it == 4 } ?: l.firstOrNull { it == 5 } ?: throw IllegalStateException("Ups")
(3) Extension function
use Extension function with Elvis Presley Link and Link
fun T?.or<T>(default: T): T = if (this == null) default else this
fun T?.or<T>(compute: () -> T): T = if (this == null) compute() else this
First one will return provided default value in case object equals null. Second will evaluate expression provided in lambda in the same case.
Usage:
1) e?.getMessage().or("unknown")
2) obj?.lastMessage?.timestamp.or { Date() }
- code above more readable than
if
construction inlining
Infix notation
Functions marked with the infix keyword can also be called using the infix notation (omitting the dot and the parentheses for the call). Infix functions must satisfy the following requirements:
- They must be member functions or extension functions;
- They must have a single parameter;
- The parameter must not accept variable number of arguments and must have no default value.
Boolean
extension function that returnsnull
when theBoolean
isfalse
infix fun <T> Boolean.then(param: T): T? = if (this) param else null
Used
println(condition then "yes" ?: "no")
This would make an a ? b : c
expression translate to a then b ?: c
infix fun <T> Boolean.then(param: () -> T): T? = if (this) param() else null
used
println(condition then { “yes” } ?: “no”)
more enhancement in code (Link)
data class Ternary<T>(val target: T, val result: Boolean)
create a class to hold your target and result:
data class Ternary<T>(val target: T, val result: Boolean)
create some infix functions to simulate a ternary operation
infix fun <T> Boolean.then(target: T): Ternary<T> {
return Ternary(target, this)
}infix fun <T> Ternary<T>.or(target: T): T {
return if (this.result) this.target else target
}
Then you will be able to use it like this:
val collection: List<Int> = mutableListOf(1, 2, 3, 4)var exampleOne = collection.isEmpty() then "yes" or "no"
var exampleTwo = (collection.isNotEmpty() && collection.contains(2)) then "yes" or "no"
var exampleThree = collection.contains(1) then "yes" or "no"