157

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
  • 7,766
  • 8
  • 46
  • 61
nhaarman
  • 94,943
  • 53
  • 240
  • 273
  • 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

12 Answers12

236

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,055
  • 1
  • 34
  • 54
Ilya
  • 19,764
  • 8
  • 62
  • 84
  • 5
    note: does not seem to work with the inverse operator `!` – Richard Dec 22 '17 at 09:22
  • 7
    @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
  • 7
    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
49

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 that (or else) as a value in the when:

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

when(b) {
    true -> {}
    false -> {}
    else-> {}
}
Eliezer
  • 6,941
  • 11
  • 55
  • 102
25

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,850
  • 3
  • 24
  • 44
Piotr Praszmo
  • 17,463
  • 1
  • 55
  • 62
  • 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,010
  • 3
  • 27
  • 29
3

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
  • 454
  • 3
  • 11
2

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,655
  • 1
  • 11
  • 13
1

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,790
  • 11
  • 46
  • 79
John
  • 370
  • 1
  • 2
  • 18
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
  • 71
  • 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
  • 36,357
  • 13
  • 107
  • 175
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
  • 503
  • 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
  • 9,497
  • 3
  • 49
  • 68
-2

You can do with safe Operator "let"

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