173

If I have a nullable Boolean b, I can do the following comparison in Java:

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

In Kotlin, I can achieve the same by using the !! operator:

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

However, the use of !! feels a bit sketchy to me, circumventing the null safety system.

Is there a more elegant approach for this?


Edit It seems I oversimplicated a bit. For local variables, as Banthar shows, it does work. However, my Boolean b is actually a "property with a backing field" (I'm not really up to speed yet what this imposes). This is the result:

enter image description here

Vadim Kotov
  • 8,084
  • 8
  • 48
  • 62
nhaarman
  • 98,571
  • 55
  • 246
  • 278
  • Why you need `!!b` and not simply `b`? (I'm not that familiar with kotlin, just curios) – Maroun Sep 28 '15 at 20:10
  • 1
    @MarounMaroun Since `b` may be `null` and one of Kotlin's features is [Null Safety](http://kotlinlang.org/docs/reference/null-safety.html#the--operator), which gives compilation errors when trying to evaluate nullable references. Thus, using plain `b` gives a compilation error :) – nhaarman Sep 28 '15 at 20:12
  • But won't `b != nil` catch that before checking the right side? – Maroun Sep 28 '15 at 20:14
  • You would say indeed, but my IDE says otherwise. I do remember that something like that should work, I'll see if I can find something. – nhaarman Sep 28 '15 at 20:16
  • I think `val r = b?doSomething() ?: doSomethingElse()` should work. – Maroun Sep 28 '15 at 20:22
  • I would have hoped that as well indeed, since the docs provide `val l = s?.length() ?: -1`, where `s` is a `String`. However, the `Boolean` 'equivalent'(?) `val r = b? "Yes" ?: "No"` doesn't parse. – nhaarman Sep 28 '15 at 20:27
  • Now I've come to think of it.. It might actually be intentional, due to concurrency issues. The field may be updated between the left and right hand side of the &&. – nhaarman Sep 28 '15 at 20:34
  • Related post covering null operators including "Safe Casts" which are where you ran into trouble. The special cases sometimes defeat the safe cast. http://stackoverflow.com/questions/34498562/in-kotlin-what-is-the-idiomatic-way-to-deal-with-nullable-values-referencing-o/34498563#34498563 – Jayson Minard Jan 06 '16 at 21:20

13 Answers13

254

You can compare nullable boolean with true, false or null using equality operator:

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 
}
Chitrang
  • 5,097
  • 1
  • 35
  • 58
Ilya
  • 21,871
  • 8
  • 73
  • 92
  • 5
    note: does not seem to work with the inverse operator `!` – Richard Dec 22 '17 at 09:22
  • 9
    @Richard it helps to think b as a having 3 possible values: `true`, `false` or `null`. Then when doing `if (b != true)` you only know that b is not true, but you know nothing about `false` or `null` – jivimberg Jun 09 '18 at 14:50
  • 8
    eg2.`if (b != true) // b is null or false` eg3. `if (b == false) // b is false` – hmac Jun 11 '18 at 11:07
  • 3
    This is the correct answer and makes sense in Kotlin, but coming from a Java background it may feel strange to explicitly compare to true or false or null within an if-statement, which may explain why this is such a popular question and answer. – Michael Peterson Nov 09 '19 at 02:34
55

If you want to cleanly check whether a Boolean? is true or false you can do:

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

If you want to check if it's null you can add null (or else) as a value in the when:

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

when(b) {
    true -> {}
    false -> {}
    else -> {}
}
Ola Ström
  • 4,136
  • 5
  • 22
  • 41
Eliezer
  • 7,209
  • 12
  • 56
  • 103
27

Kotlin will statically analyze your null checks. This is fine:

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

Even though this fails with type error:

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

For more see: http://kotlinlang.org/docs/reference/null-safety.html

You can also use "null coalescing operator" (which will work for mutable variables):

val b: Boolean? = null
if (b ?: false) {
    println(b)
}
Mark Gilchrist
  • 1,972
  • 3
  • 24
  • 44
Piotr Praszmo
  • 17,928
  • 1
  • 57
  • 65
  • The analysis works only for immutable values. If you need to do this to a mutable field, store it to temporary local variable. – Piotr Praszmo Sep 28 '15 at 20:50
  • 1
    That makes sense, indeed. The null coalescing operator is probably what I was looking for. Thanks! – nhaarman Sep 28 '15 at 20:58
  • @Banthar that is not completely correct (your second example would be `var`?) ... if it is a local `var` then the compiler can still allow the safe cast. For more special cases, read http://stackoverflow.com/questions/34498562/in-kotlin-what-is-the-idiomatic-way-to-deal-with-nullable-values-referencing-o/34498563#34498563 – Jayson Minard Jan 06 '16 at 21:21
  • null coalescing elvis can be moved to assignment `val booleanVal = nullableProducer?.produceVal() ?: false; if (booleanVal) {}` – MainActivity Sep 03 '18 at 11:29
8

From what I've seen the Boolean? is a result of a method that returns Boolean on an object that is nullable

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

The solution I've been using is to use the let function to remove the possible returned null value like so

person?.let {
  if(it.isHome()) {
    //Do something
  }
}
DroidT
  • 3,168
  • 3
  • 31
  • 29
4

In Kotlin, you can do like this:

val b: Boolean? = true
if (b == true) { // if b is null, this should be null == true
    /* Do something */
} else {
    /* Do something else */
}
ininmm
  • 502
  • 4
  • 12
3

first, add the custom inline function below:

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
}

then you can write code like this:

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

//or

b.ifFalse {
   /* Do something else in false case */
}
zyc zyc
  • 3,805
  • 1
  • 14
  • 14
3

For Kotlin what i normally use is

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

this would only work when the property is true and the object is not null. For the reverse:

if (!object?booleanProperty !=true)
   { 
     //do Stuff
   }
Horrorgoogle
  • 7,858
  • 11
  • 48
  • 81
John
  • 410
  • 1
  • 4
  • 19
1
myBoolean?.let {
    if(it) -> doSomething()
}

myBoolean?.let {
    if(it) -> {
        doSomething()
    } else {
        doSomethingElse()
    }
}

You can also choose to do something in the event myBoolean is null like this:

myBoolean?.let {
    if(it) -> doSomething()
} ?: doSomethingInCaseOfNull()
Z3r0CooL
  • 131
  • 1
  • 7
0

Let's use an if-else statement with an 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!")
}

// Result: "One of them isn't nullable..."

a = null
b = null

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

// Result: "Both are nullables!"

Andy Jazz
  • 49,178
  • 17
  • 136
  • 220
0

It's pretty easy to add an extension function if that helps you.

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

var x: Boolean? = null

if(x.orDefault()) {
..
}
Nic Bell
  • 513
  • 2
  • 7
0

In case if you want to perform operations alike contain on a String you could use equality check like below -

if (url?.contains("xxx") == true){
  return false;
}
Anoop M Maddasseri
  • 10,213
  • 3
  • 52
  • 73
-1

You can cast Boolean? to Boolean by using operator ?: and returning false. if Boolean? is null it will return false value instead null

val b: Boolean? = null

if(b ?: false == true ) {
  //some action
}
andermirik
  • 40
  • 4
-2

You can do with safe Operator "let"

val b: Boolean? = null
b?.let { flag ->
    if(flag){
        // true Block
    } else {
        // false Block
    }
}
finalpets
  • 281
  • 4
  • 6