Что делает?: делать в Котлине? (Элвис Оператор)

Я не могу понять, что делает ?:, например, в этом случае

val list = mutableList ?: mutableListOf() 

и почему он может быть изменен на этот

val list = if (mutableList != null) mutableList else mutableListOf()

Ответ 1

TL; DR: если результирующая ссылка на объект [первый операнд] не равна null, она возвращается. В противном случае возвращается значение второго операнда (который может быть null)


Оператор Элвиса является частью многих языков программирования, например, Kotlin, а также Groovy или С#. Я нахожу определение Википедии довольно точным:

В определенных языках компьютерного программирования оператор Элвиса ?: Это бинарный оператор, который возвращает свой первый операнд, если этот операнд равен true, и в противном случае вычисляет и возвращает свой второй операнд. Это вариант троичного условного оператора ? : ? :, встречается в этих языках (и во многих других): оператор Элвиса - это троичный оператор, второй операнд которого опущен.

Следующее особенно верно для Kotlin:

Некоторые языки программирования имеют различную семантику для этого оператора. Вместо того, чтобы первый операнд приводил к логическому значению, он должен приводить к ссылке на объект. Если результирующая ссылка на объект не равна null, она возвращается. В противном случае возвращается значение второго операнда (который может быть null).

Пример:

x ?: y // yields 'x' if 'x' is not null, 'y' otherwise.

Ответ 2

Оператор Элвиса представлен знаком вопроса, за которым следует двоеточие: ?: И его можно использовать с этим синтаксисом:

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 происходит от известного американского певца Элвиса Пресли. Его прическа напоминает знак вопроса

Elvis QuestionMark

Источник: Войда, И. Москала, М. Разработка Android с Kotlin. 2017. Packt Publishing

Ответ 3

Это называется 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

Ответ 4

Давайте посмотрим на определение:

Когда у нас есть нулевая ссылка 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, было бы намного больше кода, который труднее читать.

Ответ 5

Просто мы можем сказать, что у вас две руки. Вы хотите знать, работает ли ваша левая рука прямо сейчас? Если левая рука не работает, 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"

Ответ 6

В принципе, если левая сторона Элвиса по какой-либо причине возвращает ноль, вместо этого возвращается правая.

т.е.

val number: Int? = null
println(number ?: "Number is null")

Таким образом, если число НЕ равно нулю, будет напечатано число, в противном случае будет напечатано "Число равно нулю".