Today we will look into Kotlin type checking and smart type casting. We will use Kotlin Online playground for code snippets.
Kotlin Type Checking
Type Checking is the way to check the type of a data at runtime. In Java, we have the instanceof
keyword to check the type. Kotlin uses is
and !is
keywords to check whether a property is and is not of a certain type respectively.
Let’s look at an example code for the same.
var myProperty = "xyz"
var otherProperty = 1
if(myProperty is String)
{
println("type is String")
}
else{
println("unknown type")
}
if(otherProperty !is Double)
{
println("not a string")
}
else{
println("unknown type")
}
The first if-else expression would print type is String. The second would give a compilation error since Kotlin is powerful enough to determine the types at compile time itself.
Let’s create a list of Any
objects and check the type of each element.
We’ll use the when
statement to check the type of each element in a for loop.
val anyList: List<Any> = listOf("JournalDev.com", "Java", 101, 12.5f,12.5456789,false)
for(value in anyList) {
when (value) {
is String -> println("String: '$value'. Capitalize :${value.capitalize()}")
is Int -> println("Integer: '$value'")
is Double -> println("Double: '$value'")
is Float -> println("Float: '$value'")
else -> println("Unknown Type")
}
}
Following is the output of the above code.
Kotlin Smart Type Casting
Smart type casting is one of the most interesting features available in Kotlin. It automatically casts a property to the desired type on the right hand side if the condition meets.
fun getName(obj: Any?) {
if (obj == null || obj !is String) {
return
}
val string = obj
println("Length of the string is ${string.length}")
}
getName(null)
getName("Anupam")
In the above code, we don’t need to unwrap the optional. If the smart cast passes the above null checker, optional is unwrapped automatically.
The output printed from the above piece of code is given below.
The same equivalent code in Java would look like this:
class MyJava
{
public static void main (String[] args) throws java.lang.Exception
{
// your code goes here
MyJava mj = new MyJava();
mj.printStringLength("Anu");
}
public void printStringLength(Object obj) {
if (obj instanceof String) {
String str = (String) obj;
System.out.print("String substring is ");
System.out.print(str.substring(1));
}
}
}
In the above code, we’re first checking the instanceOf
and then explicitly type casting. Kotlin makes it way simpler thanks to Smart Casting.
Smart Casting With Binary Operators
Smart Casting is also possible with binary operators as shown in the below code.
fun newStringOnlyIfLength6(str: Any): Boolean {
return str is String && str.length == 6
}
print(newStringOnlyIfLength6("Kotlin")) //prints true
fun stringOnlyIfLength6(str: Any): Boolean {
return str !is String || str.length == 6
}
print(stringOnlyIfLength6("Kotlin")) //prints true
In the above code, in the first function, if the first condition is true, Kotlin type casts the parameter in the second parameter to the same type.
Smart Casts in Classes
Let’s create classes that implement an interface as shown below:
import java.util.*
fun main(args: Array<String>) {
class Car : Vehicle {
override fun printDetails() {
println("AUDI Rocks")
}
}
class Bike : Vehicle {
override fun printDetails() {
println("Bullet fires")
}
}
val printMe: Vehicle
val random = Random()
fun rand(from: Int, to: Int): Int {
return random.nextInt(to - from) + from
}
printMe = if (rand(0, 10) % 2 == 0) {
Car()
} else {
Bike()
}
if (printMe is Car) {
printMe.printDetails()
}
if (printMe is Bike) {
printMe.printDetails()
}
}
interface Vehicle {
fun printDetails()
}
The Random function gets a random integer between 0 to 10. Based on whether it’s even or odd, the interface creates instantiates from either of the classes.
The is
operator then calls the method in the if expressions by smart casting the type of the class.
Note: The Kotlin compiler does not smart cast when it cannot guarantee that the value hasn’t changed between check and usage. It always smart casts for val
properties and can never do so for var
properties.
Explicit Type Casting
We can explicitly type cast properties in Kotlin using the as
operator.
val object: Any = "Hello World"
val str: String = object as String
println(str.length)
The as operator is unsafe. It can lead to ClassCastException
similar to Java in scenarios shown below.
var y = null
var x = y as String
println(x) // crashes
x is not a nullable type, so it cannot be set to null. For this case, we’ll can do either of the following:
var y = null
var x = y as String?
println(x)
This allows us to set x as a null.
But the above approach would fail when:
var y = 5
var x = y as String?
println(x) //crashes
So we need to use the as?
operator which instead of giving a runtime exception, sets a null value if the cast doesn’t succeed.
var y = 5
var x = y as? String
println(x) //gives a null
That’s all for type checking and smart casting in kotlin programming language.