As mentioned in Kotlin API document, readLine() returns the line read or null if end of file has already been reached but it is the same functionality as readlnOrNull(). So what is the difference here?
I know that readlnOrNull() and readln() have been introduced in Kotlin 1.6 for the purpose of null safety but I can't understand why readlnOrNull() introduced when readLine() exist before.
They added readlnOrNull as an alias of readLine for the sake of preserving the convention that each standard library function that throws a RuntimeException has an “orNull” version that returns null instead of throwing. It was added when readlnwas added. It’s so the matching function with this behavior can be easily found. If readLn had existed from the earliest version of Kotlin, then they might never have created a redundant readLine function that matches the behavior of readlnOrNull. They have not deprecated readLine because there’s nothing wrong with its behavior and it’s concise.
readLine() and readlnOrNull() are both methods used in Kotlin for reading input from the user.
readLine() is used to read a line of text from the standard input and returns a string. If the user does not provide any input or an error occurs, this method throws an IOException.
scss
val input = readLine()
readlnOrNull() is similar to readLine(), but instead of throwing an exception, it returns null if the user does not provide any input or an error occurs.
scss
val input = readLine() ?: "No input provided"
In general, it is recommended to use readlnOrNull() as it provides a more flexible and safer way to handle input reading in Kotlin.
Related
As I learn new components in Kotlin, I came accross requireNotNull and checkNotNull but the only difference I've found is that requireNotNull can throw an IllegalArgumentException while checkNotNull can throw an IllegalStateException. Is this the only reason why there are two methods, or I'm missing some under-the-hood implementation detail?
The exception types are the only practical difference, as far as the compiler is concerned — but there's a big difference in intent, for anyone reading the code:
• require…() functions are for checking parameters, to confirm that a function's input fulfils its contract. So you'd normally call them first thing in a function. (Of course, Kotlin's non-nullable types mean that you wouldn't need to call requireNotNull() for a single parameter; but you might need to check a more complex condition on a combination of parameters or their sub-objects.) That's why they throw IllegalArgumentException: it's checking that the arguments are legal.
• check…() functions are for checking the relevant properties, to confirm that the object or whatever is in a valid state for this function to be called now. (Again, any properties that were never null would be typed accordingly, so checkNotNull() is more appropriate for cases where a property, combination, and/or sub-property can be null, but this function mustn't be called when they are.) So they throw IllegalStateException: they're checking that the object's current state allows the function to be called.
In both cases, you could of course write a standard if check (as you would in Java). Or you could use the Elvis operator ?: to do the check the first time the possibly-null value is used. But these functions give you an alternative that's in a more declarative form: you'd normally put them at the top of the function, where they spell out what the function's contract is, in a way that's obvious to anyone glancing at the code.
As a linked answer points out, there are also assert…() functions, which again have more of a semantic difference than a practical one. Those are for detecting programming errors away from the boundary of a function call: for confirming invariants and other conditions, and for all the checks in unit tests and other automated tests.
(Assertions have another important difference: they can be enabled and disabled from the command-line. Though in my experience, that's not a very good thing. If a check is important, it should always be run: be mandatory; if not, then it should be removed, or at least moved to automated tests, once the code is debugged.)
It is a semantic difference and hence it throws different exceptions. RequireNotNull is used to check input values, typically at the beginning of a method, while checkNotNull is used anywhere to check the current state.
If you're looking for differences in implementation, the best place to go would be the source code. In this case it seems like there are no differences aside from the different exception thrown, the source for both methods is otherwise identical.
checkNotNull
[...]
if (value == null) {
val message = lazyMessage()
throw IllegalStateException(message.toString())
} else {
return value
}
requireNotNull
[...]
if (value == null) {
val message = lazyMessage()
throw IllegalArgumentException(message.toString())
} else {
return value
}
Therefore the difference is purely semantic. The answer from #gidds details some good scenarios for using them both.
I'am new to Kotlin (and Java) so may be a stupid question, but IntelliJ keeps telling me "No cast needed" on the second function call. If i switch the order of the functions the same for the other functions.
I could imagine 2 things:
Kotlin is smart it knows: Hey first cast is fine, so i will cast the second
IntelliJ problem ?
(this as Exec).setVersionToDeploy()
(this as Exec).setEcsTaskMemory()
Both functions are defined as (Gradle-Plugin):
fun Exec.XX()
Your first guess is correct!
This is known as a smart cast: the compiler knows that, if execution reaches your second line, the type of this must be Exec (else the first line would have thrown a ClassCastException and it wouldn't have reached the second line). So it infers the specific type, and a further cast is not needed
In general, the compiler infers types in cases such as this, so you don't need to cast explicitly. (It's not an error to do so, only a warning; but IDEA is very keen on showing ways your code can be improved.)
You see this most commonly with nullability (since that's part of the type system). For example, if you have a nullable field, the compiler won't let you call its methods directly:
val myString: String? = "abc"
println(myString.length) // COMPILE ERROR, as myString could be null
but if you add a manual check, the compiler smart-casts the field to its non-nullable type, so you don't need a cast:
val myString: String? = "abc"
if (myString != null)
println(myString.length) // OK; compiler infers type String
The following code :
fun main(args: Array<String>) {
print("Write anything here: ")
val enteredString = readLine()
println("You have entered this: $enteredString")
}
gives the following error in KotlinPlayground :
Write anything here: You have entered this: null
Here, the user doesn't get an opportunity to enter input. After the initial print statement gets executed, the compiler is not waiting for the user to give input and skips to the next print statement. Why is it happening? I have tried the same in several other online Kotlin compilers but I am getting the same error.
There's no error. readLine just returns null (because Kotlin Playground doesn't have a console to read from), and it's printed as expected.
E.g. on https://ideone.com/ you can say what to use for input and it'll print that line (though its Kotlin version is pretty old).
Because Kotlin playground have no user input console and this is not an error. For user input you can either use https://ideone.com/ or
https://www.jdoodle.com/compile-kotlin-online/
I will recommend you to use the second on which is jdoodle. It is pretty much faster to run and read user input and almost use the latest version of Kotlin and JRE.
And if you like to play (run) with command line argument then it will good for you with jdoodle.
This can be done in Kotlin Playground by using JS as the destination platform - click on the JVM dropdown (top left, to the right of the kotlin version) and change to JS.
Now you can call JavaScript - only using constant strings, e.g.
fun main() {
val name = js("prompt('Please enter your name', 'Bob')")
println("Hello $name")
}
For another example, using a common function, see https://pl.kotl.in/MkhfYNS47
Note: if you try this:
fun promptName(default: String = "") {
return js("prompt('Please enter your name', '$default')")
}
You will get a compilation error - Argument must be string constant.
Note that JS IR as an option ran much slower and had an issue with default type needing to be stated for the linked code
The below code
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")
}
}
produces the following error in Kotlin Playground:
Enter your value:
Exception in thread "main" kotlin.KotlinNullPointerException at FileKt.main(File.kt:4)
I have seen other questions with NullPointerException but I am unable to resolve it. I might would have missed some so it would be really helpful if you can share useful links. Since I am new to Kotlin, it would be awesome if you correct my program.
Remark: I don't have any background on java either and most of the NullPointerException questions are based on java
Edit 1 : I have tried gidds' solution and it seems to be working except one minor fault. The readLine() is for some reason not working.
The below code
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...")
}
}
produces the following error in Kotlin Playground :
Output : null
No values given...
I guess I was getting the previous errors due to the same reason, i.e. readLine() was not working properly and the user is not getting an opportunity to give input(s).
With readLine()!!, you are saying the compiler that if this returns null, that will crash with NullPointerException. In another way, you must be sure to have return value of readLine() to be not null. Read more about !! operator here.
The not-null assertion operator (!!) converts any value to a non-null
type and throws an exception if the value is null.
You can have null check with elvis operator like below:
try{
val(a, b, c) = readLine()?.split(' ')
println("Values are $a $b and $c")
}catch(ex : IndexOutOfBoundsException){
println("Invalid. Missing values")
}
To expand on the earlier answer, this is about how to handle nulls.
The problem is that readLine() can return null. (This happens if end-of-file is reached; for example, if you redirect the input from a file, and reach the end of the file; or if it's taking input from the keyboard and you press Ctrl+D.)
The Kotlin compiler knows this. (Nullability is built into Kotlin's type system. readLine() returns a String? — the question mark indicates that the value could be null.)
Kotlin is very careful about null-safety, and won't let you do anything with the value that would fail if it's null. So in your code, if you omit the !!, you get an error on the following .. (‘Only safe (?.) or non-null asserted (!!.) calls are allowed on a non-nullable receiver of type String?’)
So you have to handle the null somehow.
Appending the not-null assertion !! effectively promises the compiler that you know better, and that it can never be null. This is usually a bad idea (which is why that operator was designed to look ugly); in practice, you generally don't know better than the compiler, and it will trip you up — as you've discovered! In your case readLine() did return null, and so the !! operator threw a KotlinNullPointerException.
So, you need a better way to handle it.
The traditional way is an explicit check, e.g.:
val line = readLine()
if (line != null) {
// Within this block, the compiler knows that line
// cannot be null.
} else {
println("No values given.")
}
This is a good, clear, general approach. And it may be the best approach in your case. (You'd still need to catch the IndexOutOfBoundsException, though.)
Because that approach can be a bit long-winded, Kotlin has some other tools that can be better in particular situations. I don't think any are appropriate here, but I'll mention some for completeness:
One of those is the safe-call operator ?. given in the error message and the earlier answer. This makes the call only if the value is not null; otherwise, it returns the null directly. That can be really useful, but it's not a simple answer in this case, as your comment shows: although it avoids trying to split() the null, you then fail to deconstruct it into the three values a, b, and c. (After all, null is not an array.)
If you wanted to substitute default values for a, b, and c if there was no input, you could use the safe-call operator in conjunction with the elvis operator ?:. That returns the left-hand side if it's not null, else the right-hand side. So you could do e.g.:
val (a, b, c) = readLine()?.split(' ')
?: arrayOf("defA", "defB", "defC")
println("Values are $a, $b, and $c.")
In this case, if readLine() returns a string, split() would be called on it; or if not, it would use the hard-coded array instead.
Note that this still isn't a complete solution, as it won't cope if you enter a line with less than two spaces. (So you'd still need to catch the IndexOutOfBoundsException, or check for that case explicitly.)
(Perhaps the shortest solution overall would be to leave the !! intact, and change the catch block to catch Exception, so it would catch the KotlinNullPointerException along with the IndexOutOfBoundsException. I'm not recommending that, as it's ugly: it's not clear to anyone reading the code what could happen and what exceptions you're intending to catch — and it could hide other problems in the code if they also resulted in exceptions.)
I'm new to Kotlin and there's a common pattern that I'm not sure how to deal with most correctly. Take this code, for example, which doesn't compile:
git_repo?.add().addFilepattern()
add() is a call in the JGit library which is purely Java, so its return type is AddCommand!.
I have two options:
git_repo?.add()!!.addFilepattern("test.txt")
and
git_repo?.add()?.addFilepattern("test.txt")
Both work fine and given that
I don't know the intricacies of the library implementation,
the documentation of the JGit library doesn't specify whether add() can return null, and
within this context I'd typically expect add() to not return a null
Which version is more idiomatically correct to write in Kotlin? It seems that this would be a fairly common issue to deal with since basically every non-Kotlin library would introduce this issue.
I would use the ?. safe operator and then put your own exception at the end after an ?: Elvis operator. This way you get a message that is meaningful. Using just !! isn't a very helpful message to someone down the road who has no idea what the intricacies were either.
val cmd = gitRepo.add()?.addFilepattern("test.txt") ?: throw IllegalStateException("assert: gitRepo.add() returned an unexpected null")
cmd.doSomething() // never is null guaranteed
If the value is every null you will have a custom error.
assert: gitRepo.add() returned an unexpected null
And after this line, you will not have to null check because the result of the expression is guaranteed never to be null.
If you inspect the code of the other library and ensure it would never ever be null no matter what, then a !! is appropriate. But if not sure, do one better with the custom message.
Note I dropped the first ?. from your example because I'm assuming git_repo itself is not nullable. Plus I renamed it not to have an underscore which isn't normal Kotlin naming convention.
If you are sure that git_repo will always return a value!! is fine in that case.
It is ugly but !! will always be there when you use Java libraries, and you can't avoid it.
The only reason i would use git_repo?.add()?.addFilepattern("test.txt"), would be if you are returning a value, and you want the value to be nullable so that your calling method can handle the nullable.
fun nullableMethod(): string? {
return git_repo?.add()?.addFilepattern("test.txt")
}
fun callingMethod() {
if(this.nullableMethod() != null) {
}
//Else
}
If you are guaranteed it is never going to null, use !!