Использование логического? в выражении if

131

Если у меня есть значение Boolean b, допускающее значение NULL , я могу выполнить следующее сравнение на Java:

Boolean b = ...;
if (b != null && b) {
   /* Do something */
} else {
   /* Do something else */
}

В Kotlin я могу добиться того же, используя !!оператор:

val b: Boolean? = ...
if (b != null && b!!) {
   /* Do something */
} else {
   /* Do something else */
}

Однако использование функции !!кажется мне немного схематичной, поскольку она позволяет обойти нулевую систему безопасности.

Есть ли для этого более элегантный подход?


Edit Кажется, я немного упростил. Для локальных переменных, как показывает Бантар , это работает. Однако мое логическое значение bна самом деле является «свойством с резервным полем» (я еще не совсем понимаю, что это налагает). Вот результат:

введите описание изображения здесь

nhaarman
источник
Зачем тебе нужно !!bи не просто b? (Я не так хорошо знаком с котлином, просто любопытство)
Марун
1
@MarounMaroun Поскольку bможет быть, nullи одной из функций Kotlin является Null Safety , которая дает ошибки компиляции при попытке оценить ссылки, допускающие значение NULL. Таким образом, использование plain bдает ошибку компиляции :)
nhaarman
Но не b != nilпоймете это, пока не проверите правую сторону?
Maroun
Вы бы сказали действительно, но моя IDE говорит иначе. Помню, что что-то подобное должно работать, посмотрю, найду ли что-нибудь.
nhaarman
Думаю val r = b?doSomething() ?: doSomethingElse()должно работать.
Maroun

Ответы:

186

Вы можете сравнить логическое значение, допускающее значение NULL true, falseили nullс помощью оператора равенства:

var b: Boolean? = null
if (b == true) {
    // b was not null and equal true
} 
if (b == false) {
   // b is false 
}
if (b != true) { 
   // b is null or false 
}
Илья
источник
4
примечание: похоже, не работает с обратным оператором!
Ричард
7
@Richard это помогает думать б как имеющие 3 возможных значений: true, falseили null. Тогда, когда if (b != true)вы делаете это, вы знаете только, что b не соответствует действительности, но вы ничего не знаете о falseилиnull
jivimberg
7
ЭГ2. if (b != true) // b is null or falseEG3. if (b == false) // b is false
hmac
Это правильный ответ, который имеет смысл в Kotlin, но, исходя из опыта работы с Java, может показаться странным явное сравнение с истинным, ложным или нулевым в операторе if, что может объяснить, почему это такой популярный вопрос и ответ.
Майкл Петерсон
32

Если вы хотите чисто проверить , является ли Boolean?это trueили falseвы можете сделать:

when(b) {
    true -> {}
    false -> {}
}

Если вы хотите проверить, можете ли nullвы добавить это (или else) как значение в when:

when(b) {
    true -> {}
    false -> {}
    null -> {}
}

when(b) {
    true -> {}
    false -> {}
    else-> {}
}
Элиэзер
источник
22

Kotlin будет статически анализировать ваши нулевые проверки. Это отлично:

val b: Boolean? = null
if (b != null && b) {
    println(b)
}

Даже если это не удается с ошибкой типа:

val b: Boolean? = null
if (b == null && b) {
    println(b)
}

Подробнее см .: http://kotlinlang.org/docs/reference/null-safety.html.

Вы также можете использовать «нулевой оператор объединения» (который будет работать для изменяемых переменных):

val b: Boolean? = null
if (b ?: false) {
    println(b)
}
Петр Прасмо
источник
Анализ работает только для неизменяемых значений. Если вам нужно сделать это с изменяемым полем, сохраните его во временной локальной переменной.
Петр Прасмо
1
Это действительно имеет смысл. Вероятно, я искал нулевой оператор объединения. Спасибо!
nhaarman
@Banthar, что не совсем правильно (ваш второй пример var?) ... если он локальный, varто компилятор все еще может разрешить безопасное приведение. Для других особых случаев прочтите stackoverflow.com/questions/34498562/…
Джейсон Минард,
null coalescing elvis может быть перемещен в назначениеval booleanVal = nullableProducer?.produceVal() ?: false; if (booleanVal) {}
uTha9 03
7

Из того, что я видел логическое значение? является результатом метода, который возвращает логическое значение для объекта, допускающего значение NULL

val person: Person? = null
....
if(person?.isHome()) { //This won't compile because the result is Boolean?
  //Do something
}

Решение, которое я использовал, - использовать letфункцию для удаления возможного возвращаемого нулевого значения, например

person?.let {
  if(it.isHome()) {
    //Do something
  }
}
DroidT
источник
5
Первый компилируется, если вы замените ifблок на person?.isHome() == true.
Hesam
2

В Kotlin это можно сделать так:

val b: Boolean? = true
if (b == true) { // if b is null, this should be null == true
    /* Do something */
} else {
    /* Do something else */
}
ininmm
источник
3
b != null && b == trueтакое же, как b == true.
nhaarman
1

сначала добавьте настраиваемую встроенную функцию ниже:

inline fun Boolean?.ifTrue(block: Boolean.() -> Unit): Boolean? {
    if (this == true) {
        block()
    }
    return this
}

inline fun Boolean?.ifFalse(block: Boolean?.() -> Unit): Boolean? {
    if (null == this || !this) {
        block()
    }

    return this
}

тогда вы можете написать такой код:

val b: Boolean? = ...
b.ifTrue {
   /* Do something in true case */
}

//or

b.ifFalse {
   /* Do something else in false case */
}
zyc zyc
источник
Да, в случае: b.ifTrue {...} или b.ifFalse {...} это может быть полезно
zyc zyc
1

Для Котлина я обычно использую

if (object?.booleanProperty ==true)
   { 
     //do stuff 
   }

это будет работать, только если свойство истинно, а объект не равен нулю. Для обратного:

if (!object?booleanProperty !=true)
   { 
     //do Stuff
   }
Джон
источник
0

Давайте использовать if-elseоператор с Elvis Operator:

val a: Boolean?
val b: Boolean?

a = true
b = null

if (a != null ?: b) { 
    println("One of them isn't nullable...")
} else {
    println("Both are nullables!")
}

// Результат: «Один из них не допускает значения NULL ...»

a = null
b = null

if (a != null ?: b) { 
    println("One of them isn't nullable...")
} else {
    println("Both are nullables!")
}

// Результат: «Оба значения допускают значение NULL!»

Энди Федоров
источник
0

Если это вам поможет, довольно легко добавить функцию расширения.

fun Boolean?.orDefault(default: Boolean = false): Boolean {
    if (this == null)
        return default
    return this
}

var x: Boolean? = null

if(x.orDefault()) {
..
}
Ник Белл
источник
0

В случае, если вы хотите выполнять аналогичные операции containнад a, Stringвы можете использовать проверку равенства, как показано ниже:

if (url?.contains("xxx") == true){
  return false;
}
Ануп М
источник
-1

Можно обойтись безопасным Оператором «пусть»

val b: Boolean? = null
b?.let { flag ->
    if(flag){
        // true Block
    } else {
        // false Block
    }
}
finalpets
источник
Это просто неправда, и она вернется в случае возникновения исключения.
nhaarman
Отредактировал свой ответ на основе предыдущего комментария
finalpets