Я не могу понять, что делает ?:, например, в этом случае
val list = mutableList ?: mutableListOf()
и почему он может быть изменен на этот
val list = if (mutableList != null) mutableList else mutableListOf()
Я не могу понять, что делает ?:, например, в этом случае
val list = mutableList ?: mutableListOf()
и почему он может быть изменен на этот
val list = if (mutableList != null) mutableList else mutableListOf()
TL; DR: если результирующая ссылка на объект [первый операнд] не равна null, она возвращается. В противном случае возвращается значение второго операнда (который может быть null)
Оператор Элвиса является частью многих языков программирования, например, Kotlin, а также Groovy или С#. Я нахожу определение Википедии довольно точным:
В определенных языках компьютерного программирования оператор Элвиса
?:Это бинарный оператор, который возвращает свой первый операнд, если этот операнд равенtrue, и в противном случае вычисляет и возвращает свой второй операнд. Это вариант троичного условного оператора? :? :, встречается в этих языках (и во многих других): оператор Элвиса - это троичный оператор, второй операнд которого опущен.
Следующее особенно верно для Kotlin:
Некоторые языки программирования имеют различную семантику для этого оператора. Вместо того, чтобы первый операнд приводил к логическому значению, он должен приводить к ссылке на объект. Если результирующая ссылка на объект не равна
null, она возвращается. В противном случае возвращается значение второго операнда (который может бытьnull).
Пример:
x ?: y // yields 'x' if 'x' is not null, 'y' otherwise.
Оператор Элвиса представлен знаком вопроса, за которым следует двоеточие: ?: И его можно использовать с этим синтаксисом:
first operand ?: second operand
Это позволяет вам писать кодекс и работает так:
Если first operand не нулевой, он будет возвращен. Если это нуль, тогда будет возвращен second operand. Это можно использовать для гарантии того, что выражение не будет возвращать нулевое значение, поскольку вы предоставите ненулевое значение, если предоставленное значение равно нулю.
Например (в Котлине):
fun retrieveString(): String { //Notice that this type isn't nullable
var nullableVariable: String? = getPotentialNull() //This variable may be null
return nullableVariable ?: "Secondary Not-Null String"
}
В этом случае, если вычисленное значение getPotentialNull не равно нулю, оно будет возвращено retrieveString; Если оно равно нулю, будет возвращено второе выражение "Secondary Not-Null String".
Также обратите внимание, что выражение в правой части вычисляется только в том случае, если значение в левой части равно нулю.
В Kotlin вы можете использовать любое выражение в качестве second operand, например, выражение throw Exception
return nullVariable ?: throw IllegalResponseException("My inner function returned null! Oh no!")
Название Elvis Operator происходит от известного американского певца Элвиса Пресли. Его прическа напоминает знак вопроса
Источник: Войда, И. Москала, М. Разработка Android с Kotlin. 2017. Packt Publishing
Это называется Elvis operator, и это точно... То, что вы описали в своем вопросе. Если его левая сторона представляет собой значение null, вместо этого она возвращает правую сторону, как резервную. В противном случае он просто возвращает значение в левой части.
a ?: b является просто сокращением для if (a != null) a else b.
Еще несколько примеров с типами:
val x: String? = "foo"
val y: String = x ?: "bar" // "foo", because x was non-null
val a: String? = null
val b: String = a ?: "bar" // "bar", because a was null
Давайте посмотрим на определение:
Когда у нас есть нулевая ссылка r, мы можем сказать "если r не нуль, используйте его, в противном случае используйте ненулевое значение x":
Оператор ?: (Elvis) избегает многословия и делает ваш код действительно лаконичным.
Например, многие функции расширения коллекции возвращают null как запасной вариант.
listOf(1, 2, 3).firstOrNull { it == 4 } ?: throw IllegalStateException("Ups")
?: дает вам возможность эффективно обрабатывать запасной вариант, даже если у вас есть несколько слоев запасного варианта. Если это так, вы можете просто создать цепочку умножения операторов Элвиса, как здесь:
val l = listOf(1, 2, 3)
val x = l.firstOrNull { it == 4 } ?: l.firstOrNull { it == 5 } ?: throw IllegalStateException("Ups")
Если бы вы выразили то же самое с помощью if else, было бы намного больше кода, который труднее читать.
Просто мы можем сказать, что у вас две руки. Вы хотите знать, работает ли ваша левая рука прямо сейчас? Если левая рука не работает, return empty busy
Пример для Java:
private int a;
if(a != null){
println("a is not null, Value is: "+a)
}
else{
println("a is null")
}
Пример для Котлина:
val a : Int = 5
val l : Int = if (a != null) a.length else "a is null"
В принципе, если левая сторона Элвиса по какой-либо причине возвращает ноль, вместо этого возвращается правая.
т.е.
val number: Int? = null
println(number ?: "Number is null")
Таким образом, если число НЕ равно нулю, будет напечатано число, в противном случае будет напечатано "Число равно нулю".