I have a List<T?> containing null values (which, I suppose, is not forbidden). If one element of this list is null, I want the entire list to be null (what Haskell people call sequence). The following pseudocode demonstrates what I want to do:
fun <T> sequence(a : List<T?>) : List<T>? {
return
a.fold(
listOf(),
{
prevArray, element ->
if(element == null) null else prevArray + element
})
}
This is pseudocode because the compiler complains that Null can not be a value of a non-null type kotlin.collections.List<T>.
What's the idiomatic way to express what I want to in Kotlin? Using Java's Optional type, this is at least compilable:
fun <T> sequence(a : List<T?>) : Optional<List<T>> {
return
a.fold(
Optional.of(listOf()),
{
prevArray, element ->
if(element == null) Optional.empty<List<T>>() else Optional.of(prevArray + element)
})
}
But Kotlin has many operators and functionalities regarding null handling, so I thought using null directly would be more idiomatic.
You can use a non-local return to return from the sequence function:
fun <T> sequence(a: List<T?>): List<T>? {
return a.fold(listOf()) {
prevArray, element ->
if (element == null) return null else prevArray + element
}
}
However, I would solve the problem you described with a simple if-expression, to prevent lots of list allocations which happen because the list addition creates a new list backed by array for each element. The unchecked cast warning is suppressed below because the compiler cannot figure out that the list does not contain nulls at that point, although we can clearly see that is the case:
fun <T> sequence(a: List<T?>): List<T>? {
#Suppress("UNCHECKED_CAST")
return if (a.any { it == null }) null else a as List<T>
}
Using Konad library you can now do the following:
fun <T> sequence(a : List<T?>) : List<T>? = a.flatten()?.toList()
Related
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
If I have the following array:
[1,1,1,2,2,1,1,1,1,2,2,3]
Is there any built in method in Kotlin which will filter out adjacent elements of the same value, resulting in:
[1,2,1,2,3]
It's important that the order is preserved.
P.S. My actual use case isn't integers, it's an object which implements equals.
I don't think there is a standard function to do this.
But it is easy to build one with mapOrNull:
fun <T : Any> Iterable<T>.removeAdjacent(): List<T> {
var last: T? = null
return mapNotNull {
if (it == last) {
null
} else {
last = it
it
}
}
}
There's a one-line solution, using zipWithNext():
list.zipWithNext().filter{ it.first != it.second }.map{ it.first } + list.last()
That creates a list of pairs of adjacent elements; we then filter out the identical pairs, and take the first of each remaining pair. That will have omitted the last one, so we have to add that in separately.
That works with any element type, using the object's own notion of equality (via its equals() method); this includes nullable types (unlike another answer). And it's stateless so ‘pure’ functional (which you may or may not consider a good thing!).
It handles one-element lists, but not empty lists; for completeness, you'd have to handle those separately. And it would fit very neatly into an extension function:
fun <T> List<T>.compress() = when (isEmpty()) {
true -> listOf()
else -> zipWithNext().filter{ it.first != it.second }.map{ it.first } + last()
}
Functional solution using fold:
val result = listOf(1,1,1,2,2,1,1,1,1,2,2,3)
.fold(mutableListOf<Int>()) { currentList, currentItem ->
if (currentList.isEmpty()) { // Applies only to the very first item
mutableListOf(currentItem)
} else {
if (currentItem != currentList.last()) {
currentList.apply { add(currentItem) }
} else {
currentList
}
}
}
I have an extension function something like this:
inline fun <A, B, C> Pair<A, B>.notNull(code: (A, B) -> C) {
if (this.first != null && this.second != null) {
code(this.first, this.second)
}
}
with that, I can do something like this:
Pair(username, password).notNull { user, pass ->
// code to execute when username and password is not null
}
The problem is, user and password type is still in nullable form, so I still need to use ?. to call user and pass, even though user and pass is not null
How to cast it to their respective not nullable type?
Maybe something like this, but for generic:
inline fun <C> Pair<Editable?, Editable?>.notNull(code: (Editable, Editable) -> C) {
if (this.first != null && this.second != null) {
code(this.first!!, this.second!!)
}
}
General Answer :
if you declare a generic class or function they can include nullable while substituting their type params :
Example :
class Help<T>{
fun printHelp(message :T){
message?.render();
}
}
so in this case message is nullable despite T isn't marked with T?
So to avoid passing a nullable parameter type and guarantee that a non-null type will always be substituted you can change it to :
class Help<T : Any>{
fun printHelp(message :T){
message.render();
}
}
In this case the smart cast does not work because you're accessing properties of a class declared in another module. It will work if you store the property values in local variables:
inline fun <A : Any, B : Any, C> Pair<A?, B?>.notNull(code: (A, B) -> C) {
val first = this.first
val second = this.second
if (first != null && second != null) {
code(first, second)
}
}
I think this will work.
inline fun <A: Any, B: Any, C> Pair<A?, B?>.notNull(code: (A, B) -> C) {
if (this.first != null && this.second != null) {
code(this.first!!, this.second!!)
}
}
Here, the types A and B are not defined to be subtypes of Any?. They are restricted to subtypes of Any, so they are not null. (Of course, every subtype of Any is a subtype of Any?.)
However, the type of this will be Pair<A?, B?>, so it will be a pair of nullables. All not-null types are subtypes of their corresponding nullable types, so any Pair can call this extension function.
EDIT: For an archive, yole's answer seems more preferred (not using !!): https://stackoverflow.com/a/48960855/869330
I need to map a list and retrieve the first non null element, and I need the map operation to be short circuited like it should be in Java 8 streams API. Is there a ready way to do this in Kotlin, without Java 8 streams?
I created my own extension method to do this:
fun <T, R> Iterable<T>.firstNonNullMapping(transform: (T) -> R?): R? {
for (element in this) {
val result = transform(element)
if (result != null) {
return result
}
}
return null
}
A test proves that this works
val firstNonNullMapping = listOf(null, 'a', 'b')
.firstNonNullMapping {
assertNotEquals(it, 'b') // Mapping should be stopped before reaching 'b'
it
}
assertEquals(firstNonNullMapping, 'a')
IntelliJ, however, suggest that I replace my for loop with the much neater
return this
.map { transform(it) }
.firstOrNull { it != null }
Problem is that this will map all elements of the iterable, and it is essential to my use case that is stops at the first non null element.
Kotlin has lazily evaluated sequences that correspond to Java 8 streams, instead of invoking stream() on a collection, you invoke asSequence():
return this
.asSequence()
.mapNotNull { transform(it) }
.firstOrNull()
Kotlin 1.5 provides a shortcut replacement for the combination of
.asSequence(), .mapNotNull { ... } and .first/firstOrNull(): the functions firstNotNullOf and firstNotNullOfOrNull respectively.
They execute the transform function once for each element and stop as soon as they encounter the first non-null result of that function, so they are short-circuiting.
I wonder what is faster, the #ingoKegel's solution, or this:
return this.firstOrNull { transform(it) != null }?.let { transform(it) }
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