Я не могу удалить ошибку NullPointerException - PullRequest
0 голосов
/ 10 марта 2019

Приведенный ниже код

fun main(args: Array<String>) {
    println("Enter your value : ")
    try{
        val(a, b, c) = readLine()!!.split(' ')
        println("Values are $a $b and $c")
    }catch(ex : IndexOutOfBoundsException){
        println("Invalid. Missing values")
    }
}

приводит к следующей ошибке в Kotlin Playground:

Enter your value:
Exception in thread "main" kotlin.KotlinNullPointerException at FileKt.main(File.kt:4)

Я видел другие вопросы с NullPointerException, но я не могу их решить.Я мог бы пропустить некоторые, так что было бы очень полезно, если бы вы могли поделиться полезными ссылками.Так как я новичок в Kotlin, было бы замечательно, если бы вы исправили мою программу.

Примечание: у меня также нет никакого фона по java, и большинство вопросов NullPointerException основаны на java

Edit 1 : Я попробовал решение Gidds, и оно, кажется, работает, за исключением одной незначительной ошибки.ReadLine () по какой-то причине не работает.

Приведенный ниже код

fun main(args : Array <String>){
 val line = readLine()
 try{

    println("Output : $line")

    if (line != null) {
        val(a, b, c) = line.split(' ')
        println("Values are $a $b and $c")
    } else {
             println("No values given...")
    }
  }
catch(ex : IndexOutOfBoundsException){
    println("Invalid. Missing Values...")
}
}

приводит к следующей ошибке в Kotlin Playground:

Output : null
No values given...

Я думаю, что я получал предыдущие ошибки по той же причине, т.е. readLine () не работал должным образом, и пользователь не получает возможность вводить данные.

Ответы [ 2 ]

1 голос
/ 10 марта 2019

С readLine()!! вы говорите компилятору, что если он вернет null, то произойдет сбой с NullPointerException.По-другому, вы должны быть уверены, что возвращаемое значение readLine() не равно нулю.Подробнее о !! operator здесь .

Оператор утверждения, не равный NULL (!!), преобразует любое значение в ненулевой тип и выдает исключение, еслизначение равно нулю.

Вы можете проверить ноль с помощью оператора elvis , как показано ниже:

try{
    val(a, b, c) = readLine()?.split(' ')
    println("Values are $a $b and $c")
}catch(ex : IndexOutOfBoundsException){
    println("Invalid. Missing values")
}
0 голосов
/ 11 марта 2019

Чтобы расширить предыдущий ответ, речь идет о том, как обрабатывать null с.

Проблема в том, что readLine() может вернуть null.(Это происходит, если достигнут конец файла; например, если вы перенаправляете ввод из файла и достигаете конца файла; или если он принимает ввод с клавиатуры и нажимаете Ctrl + D.)

Компилятор Kotlin это знает.(Обнуляемость встроена в систему типов Kotlin. readLine() возвращает String? - знак вопроса указывает, что значение может быть null.)

Kotlin очень осторожен в отношении нулевой безопасности и выиграл 'Позволяет вам делать что-либо со значением, которое не сработает, если оно null.Таким образом, в вашем коде, если вы пропустите !!, вы получите ошибку в следующем ..(«Только ненулевые (?.) Или ненулевые утвержденные (!!.) Вызовы разрешены для ненулевого приемника типа String?»)

Так что вам нужно как-то обработать null.

Добавление ненулевого утверждения !! эффективно обещает компилятору, что вы знаете лучше, и что он никогда не может быть нулевым.Обычно это плохая идея (именно поэтому этот оператор был разработан, чтобы выглядеть ужасно);на практике вы, как правило, не знаете лучше, чем компилятор, и он вас запутает - как вы обнаружили!В вашем случае readLine() сделал вернул null, и поэтому оператор !! бросил KotlinNullPointerException.

Итак, вам нужен лучший способ справиться с этим.

Традиционный способ - это явная проверка, например:

val line = readLine()
if (line != null) {
    // Within this block, the compiler knows that line
    // cannot be null.
} else {
    println("No values given.")
}

Это хороший, ясный, общий подход.И это может быть лучшим подходом в вашем случае.(Тем не менее, вам все равно нужно поймать IndexOutOfBoundsException.)

Поскольку этот подход может быть немного затянутым, у Kotlin есть некоторые другие инструменты, которые могут быть лучше в определенных ситуациях.Я не думаю, что что-то здесь уместно, но я упомяну некоторые для полноты:

Одним из них является оператор безопасного вызова ?., указанный в сообщении об ошибке ипредыдущий ответ.Это делает вызов, только если значение не null;в противном случае он возвращает null напрямую.Это может быть очень полезно, но это не простой ответ в этом случае, как показывает ваш комментарий: хотя он избегает попыток split() null, вам не удастся деконструировать его в три значения a, b и c.(В конце концов, null не является массивом.)

Если вы хотите заменить значения по умолчанию на a, b и c, если не было ввода, вы можете использовать безопасныйоператор вызова вместе с оператором элвиса ?:.Это возвращает левую сторону, если это не null, иначе правая сторона.Таким образом, вы можете сделать, например:

val (a, b, c) = readLine()?.split(' ')
              ?: arrayOf("defA", "defB", "defC")
println("Values are $a, $b, and $c.")

В этом случае, если readLine() вернет строку, split() будет вызвано для нее;или, если нет, вместо него будет использоваться жестко заданный массив.

Обратите внимание, что это по-прежнему неполное решение, поскольку оно не справится, если вы введете строку, содержащую менее двух пробелов.(Таким образом, вам все равно нужно перехватить IndexOutOfBoundsException или явно проверить этот случай.)

(Возможно, самое короткое из возможных решений - оставить !! без изменений и изменить catchблок, чтобы поймать Exception, поэтому он поймал бы KotlinNullPointerException вместе с IndexOutOfBoundsException. Я не рекомендую этого, потому что это уродливо: никому не понятно, кто читает код, что может произойти и какие исключения вынамереваясь поймать - и это может скрыть другие проблемы в коде, если они также приводят к исключениям.)

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...