I am a beginner in kotlin and this is the code I tried to execute, but runtime error is being displayed. Please help me resolve this.
import java.util.*
fun main(args: Array<String>)
{
var inp = Scanner(System.`in`);
var t:Int = inp.nextInt();
repeat(t)
{
var n:Int = inp.nextInt();
var s:String = readLine()!!
for (i in s)
{
println(i);
}
println()
}
}
Exception in thread "main" kotlin.KotlinNullPointerException at ProgKt.main(prog.kt:10) This is the error that is displayed.
CodePudding user response:
Well, NPE is the most probably thrown from
var s:String = readLine()!!
where those !! are part of kotlin null-safety feature. And from java doc of readLine() we can find out when is null returned.
/**
* Reads a line of input from the standard input stream.
*
* @return the line read or `null` if the input stream is redirected to a file and the end of file has been reached.
*/
fun readLine(): String? = LineReader.readLine(System.`in`, Charset.defaultCharset())
CodePudding user response:
Smeki's answer is right, but I just need to point something out since you're a beginner and it might get confusing.
Normally you'd do something like this:
val s = readLine()
Notice you're not specifying the type of s
- it's being inferred by whatever you're assigning to it. Because readLine
returns a nullable String?
, which is a String
that could be null (which is what the ?
on the end means), then the compiler knows that s
is a String?
. It's the equivalent of doing this:
val s: String? = readLine()
And you can do that explicitly if you want! You usually don't need to though. And now you have your nullable s
, you can do some null-checking to use it safely:
if (s != null) {
// we know it's not null, so now you can do stuff with it
} else {
// if you like, you can handle the null case separately, like breaking out of
// the loop (since null from readLine() means you've reached the end)
}
There's other ways to handle nulls and do null-checking - here's the documentation about it and I'd strongly recommend reading it and getting your head around it - it's a key part of the language! And it makes your life easier and code safer in the long run (avoids problems like this! !!
gets around null-safety and it's usually a bad sign)
But remember when I said you can explicitly declare the type for s
? Here's what I said it would be, and what you've written:
// correct
val s: String? = readLine()
// something's different!
val s: String = readLine()
See how you're missing the ?
that says its a nullable type? Even if you're planning to null-check s
after this, it's going to crash at this line because s
is declared as a non-null type, and readLine()
is gonna to be null at some point. When you assign null to a non-null variable, it'll crash with an error - because as far as the compiler's concerned, something's gone wrong.
(You should also get some warnings in your IDE if you're using one, trying to null-check a variable that you've declared as non-null will give you some "why are you trying to do this? It can't be null, right?" messages that hint that something's wrong somewhere. Also if you didn't add the !!
after readLine()
, you'd get a warning about that - probably why you added the !!
in the first place! It doesn't make the problem go away, just stops the IDE from warning you about it)
Also you might have noticed, I made s
a val
instead of a var
because it's a fixed value you're not going to change - always prefer val
s unless you definitely need to change that variable, it's not such a big deal here but it makes some other things easier (you'll get warnings about that too)