Котлин дважды проверяет наличие null, если еще

У меня есть элемент с переменной datePurchased, которая может быть нулевой. По дате покупки создаю этикетку. Когда я проверяю, имеет ли datePurchased значение null, в ветке else мне все равно нужно проверять значение null. Он говорит, что умное приведение невозможно, потому что это изменяемое свойство.

Вот что я пробовал до сих пор:

if (datePurchased == null) {
    ""
} else {
    if (datePurchased.isToday()) {//error here
    }
}

    when {
        datePurchased == null    -> {

        }
        datePurchased.isToday() -> {//smart cast bla bla mutable bla bla
        datePurchased?.isToday() -> {//expected Boolean, got Boolean?
        datePurchased?.isToday()?:false -> {//all good, but does not look nice, since datePurchased can't be null here
        }
        else                     -> {

        }
    }

person Marius Kaunietis    schedule 17.11.2016    source источник
comment
@miensol итак, вы предлагаете обернуть мою ветку else в ?.let?   -  person Marius Kaunietis    schedule 17.11.2016
comment
да. Вы можете сделать это: datePurchased?.let { if(it.isToday()) // Do something } ?: ""   -  person marstran    schedule 17.11.2016
comment
@marstran спасибо. Я не понимал, что ?.let поддерживает ?:   -  person Marius Kaunietis    schedule 17.11.2016


Ответы (3)


Благодаря марстрану у меня получилось такое решение:

        return datePurchased?.let {
            when {
                it.isToday()     -> {
                    "Today"
                }
                it.isYesterday() -> {
                    "Yesterday"
                }
                else             -> {
                    dateFormat.format(it)
                }

            }
        } ?: ""
person Marius Kaunietis    schedule 18.11.2016

Если вы уверены, что у вас нет гонки за данные, в которой datePurchased становится null, добавьте ненулевое утверждение в ветку else:

if (datePurchased == null) {
    ""
} else {
    datePurchased!!.isToday()
}

Или короче и надежнее:

datePurchased?.isToday() ?: ""
person voddan    schedule 17.11.2016

  1. datePurchased является изменяемым, что означает, что его можно изменить.

  2. Ваш код не работает внутри какой-либо синхронной блокировки, что означает, что другой поток потенциально может работать и изменять его одновременно.

Имея это в виду, возможно следующее:

if (datePurchased == null) {
    ...
} else {

    // another thread comes in here and changes datePurchased=null

    if (datePurchased.isToday()) { // Null Pointer Exception!
        ...
    }
}

Возможно, у вас нет потока, выполняющего это, но компилятор не знает. Он играет осторожно и говорит, что вы не можете этого сделать. Вероятно, в 98% случаев это неправильно, но эти 2% заставляют вас задуматься о том, как ваш код ведет себя в параллельной среде.

Одно из решений - просто использовать локальный val, который нельзя изменить в новом потоке:

val datePurchased = datePurchased

if (datePurchased == null) {
    ...
} else {

    // datePurchased val cannot have been changed, compiler can guarantee safety

    if (datePurchased.isToday()) { 
        ...
    }
}

Но главное, теперь вам нужно подумать о том, что на самом деле означает неизменяемый в контексте вашего приложения, и действительно ли вам нужно иметь изменяемые переменные.

person Tom    schedule 09.05.2017