Это очень плохая практика использования! в котлин?

Недавно была дискуссия о том, является ли!! следует использовать в коде kotlin. Одно мнение, что это не следует использовать вообще, потому что это плохая практика с kotlin и увеличивает риск аварии.

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

Кто-нибудь имеет мнение против или против использования!! (не использовать его вслепую)?

два примера ниже, не видите dataCount_2 будет лучше, или?

var data: List<Data>? = null  // it will be set before calling the two dataCount()

fun dataCount_1() : Int {
    return if (data!=null && data!!.isNotEmpty())  data!![0].count else 0
}

fun dataCount_2() : Int {

    data?.let { dataList ->
        if (dataList.isNotEmpty()) {
            return dataList[0].count ?: 0
        }
    }
    return 0
}

3 ответа

Решение

В этом случае есть несколько идиоматических способов выразить идею без использования !!так что определенно предпочтительнее не использовать его. Вот что я хотел бы сделать (используя функцию orEmpty, добавленную в Kotlin 1.3):

fun dataCount() = data.orEmpty().firstOrNull()?.count ?: 0

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

На самом деле в этом случае самый простой и безопасный способ - сделать это так:

var data: List<Data>? = null  // it will be set before calling the two dataCount()

fun dataCount() : Int {
    val data = data
    return when {
        data == null || data.isEmpty() -> 0
        else -> data[0].count
    }
}

хотя лично я бы просто использовал run превратить это в однострочную функцию.

fun dataCount() : Int = run {
    val data = data
    when {
        data == null || data.isEmpty() -> 0
        else -> data[0].count
    }
}

Но это может быть только я.

В любом случае, если вы присваиваете изменяемой переменной val (или держите его в закрытом положении, как вы делаете с ?.let { во втором примере), то вы можете использовать смарт-кастинг, и вам не нужно будет использовать !!,

Я не думаю что-либо !! необходимы в dataCount_1(), как после явной проверки нуля, компилятор знает data не может быть нулевым и умным приведением к необнуляемому типу.

Так что пока есть очень мало случаев, когда !! может быть уместно, я не думаю, что это один из них!

(Кроме того, в этом случае вы можете внести еще два изменения: использовать lateinit Вар, который снова не понадобится !!; и заменить все условие более кратким .isNotNullOrEmpty().)

В целом мой опыт показывает, что большую часть времени вы достигаете !!есть лучший подход. Но я бы не запретил это полностью: если вы тщательно рассмотрели все альтернативы и все еще думаете, что !! самый ясный и безопасный путь, тогда иди вперед.

Я бы предпочел использовать requireNotNull(). БроскиIllegalStateException если аргумент null.

Другие вопросы по тегам