Я не могу понять, что делает ?:
, например, в этом случае
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")
Таким образом, если число НЕ равно нулю, будет напечатано число, в противном случае будет напечатано "Число равно нулю".