9. Nullable Types¶
9.1. A First Example¶
Kotlin’s readLine()
function can be used to read a line of text from standard input. Let’s investigate what it returns when called.
-
In the Kotlin REPL, invoke
readLine()
and assign the returned value to a variable. Kotlin will wait for input at the point, so type some text and press Enter. Then query the value of the variable by entering its name at the prompt. Your interaction with the REPL should resemble this:>>> val input = readLine() Hello >>> input res1: kotlin.String? = Hello
Note, in particular, the type reported for the variable:
String?
. -
Try querying the length property of the string. For example, if your variable is named
input
, then enterinput.length
at the REPL prompt. What happens? -
The error message seen in the previous step notes that
input
is a ‘nullable receiver’. If an object is of a nullable type, you cannot use the usual.
operator to access a property or call a method; instead you must use the safe call operator,?.
.Try entering
input?.length
at the prompt. What happens now? What type of value is returned? (Look closely!…) -
Why does
readLine()
return a nullable string? Repeat the REPL interaction shown in Step 1 above, but this time instead of entering any text, press Ctrl+D when Kotlin awaits your input. This closes the input stream before any input has been supplied. As a result, you should see thatinput
has a value ofnull
. Kotlin uses thenull
value to signal that there was no input.If you had just pressed the Enter key instead of Ctrl+D, the value of
input
would have been a zero-length string instead.
9.2. Creating Nullable Variables¶
If you wish to create your own nullable variable, append a question mark to the type name when declaring it.
-
Try entering the following lines in the REPL:
var name: String? = "Joe" name = null
name
is a nullable string, which means its value can be either a string ornull
. -
Repeat the above steps, using a type of
String
instead ofString?
. This time, the assignment toname
will fail. You can only assignnull
to variables of a nullable type.
9.3. The Elvis Operator¶
Sometimes, we need to assign the result of computation to a variable and want that variable to be given a default value of some kind when the computation evaluates to null
. The ‘null coalescing operator’ or Elvis operator, ?:
, provides a neat way of achieving this.
-
Enter the following at the REPL prompt:
val input = readLine() ?: "NO INPUT"
Enter some text, as before, then check the value and type of the
input
variable. The value should be the text you entered, and the type should beString
, notString?
. -
Repeat the previous step, but this time press Ctrl+D instead of supplying input. If you check the
input
variable again, this time it should have a value of"NO INPUT"
. Again, the type will beString
, notString?
.The Elvis operator requires an expression that can evaluate to
null
on the left and a default value on the right. If the expression on the left is notnull
, its value is used; otherwise, the value supplied on the right is used. Since this eliminates the possibility of anull
result, the value returned by the Elvis expression is of a non-nullable type. -
The safe call and Elvis operators can be used together. Try this in the REPL:
readLine()?.length ?: 0
This will access the
length
property ifreadLine()
returns a string, otherwise it will return 0. Consequently, you will see 0 displayed if you just press Enter or Ctrl+D, otherwise you’ll see a count of the number of characters you entered.
9.4. The let
Scope Function¶
Kotlin provides several scope functions which allow you to execute a block of code within the context of a particular object. One of these, the let
function, is often combined with the safe call operator to provide a neat way of making code execution conditional on a value being non-null 1.
-
Download
passcheck.kt
. This is a mostly incomplete program that is supposed to check the validity of a password entered by the user. Edit the file and add the following code:print("Enter a password: ") val password = readLine()
Remember that
readLine()
here will return a nullable string. -
Now add the following:
password?.let { when { it in badWords -> println("Password forbidden") it.length < 8 -> println("Password too short") it.length > 24 -> println("Password too long") else -> println("Password OK") } }
The code in the lambda function supplied to
let
will execute only when the value ofpassword
is non-null. Inside this lambda function, thepassword
variable can be referenced asit
. -
Compile and run the program like so:
kotlinc -include-runtime -d passcheck.jar passcheck.kt java -jar passcheck.jar
Footnotes
- 1
-
This could also be achieved by testing explicitly for
null
with anif
statement, but using safe call +let
is a bit more elegant.