Number Types
The built-in number types are as follows
Type | Bytes |
---|---|
Long | 64 bytes |
Double | 64 bytes |
Int | 32 bytes |
Float | 32 bytes |
Short | 16 bytes |
Byte | 8 bytes |
The conversion methods are toByte()
toShort()
toInt()
toLong()
toFloat()
toDouble()
toChar()
// how to convert between types
fun main(args: Array<String>) {
val minutesInYear: Double = (60*24*365).toDouble()
val input = Scanner(System.`in`)
print("Input the number of minutes: ")
val min = input.nextDouble().toInt()
val years = (min / minutesInYear.toLong())
val days = (min / 60.0 / 24.0).toInt() % 365
println("$min mins is approx $years years and $days days")
}
Strings and String Templates
Strings are immutable in Kotlin. There’re two types of String literals
Escaped String
Created using double ""
quotes. Special chars such as new line must be escaped.
val string = "string with \n new line"
Raw String
Created by a triple quote """
. Contains no escaping and can contain newlines and any other characters.
val test = """
for (c in "foo")
print(c) """
String templates
They’re for embedding values, variables or expressions inside a string, without string concatenation.
val name = "Sam"
val str = "hello $name"
Methods can be embedded by prefixing with a dollar $
and wrapping in braces {}
val name = "Sam"
val str = "hello $name. Your name has ${name.length} characters"
You can also use string templates in multiline Strings.
Any
Any
is the supertype of all non-nullable types. It cannot contain a null value. It’s similar to java.lang.Object
.
// this performs automatic boxing
val answer: Any = 42
If you need a variable that can hold any possible value, including null, you must use Any?
Unit Type (Java’s void)
It can be used as a return type of a function that has nothing to return. It does not have to be explicitly declared.
Unlike in Java, where void just indicates that the method doesn’t return anything at all, in Kotlin Unit actually returns something, and this something is nothing. You’re literally returning nothing. Also, unlike void, it can be used as a type argument.
Unit is also useful when you override a function that returns a generic parameter and you want to make it return nothing.
// this requires to return a generic 'T'
interface Processor {
fun process(): T
}
// as Unit is a type and it returns something
// we may use it to implement the previous
// method and don't return anything.
class NoResultProcessor : Processor {
override fun process() {
// do stuff
}
}
The Nothing Type (never returns)
Nothing
has no type. You can use it to mark a function that never returns successfully. It helps optimize the compiler.
For example, if you have a function like an eternal for loop or a function that always throws an Exception. It’s never going to return data. There’s no reason to have that function identified as returning something. Even the Unit type.
There’re no instances of nothing. It’s defined as a type but can never be instantiated.
fun fail(message: String): Nothing {
throw IllegalArgumentException(message)
}
Functions returning Nothing
can be used on the right side of the Elvis operator to perform precondition checking (you don’t have to check for null).
val s = person.name ?: fail("Name required")
println(s) // 's' is known to be initialized at this point.
Explicit Casts and Smart Casts
You can check whether a variable is of a certain type by using an is
check. This is the same as an instanceof
in Java.
// casting in java
if(a instanceof ObjectB) {
ObjectB myObject = (ObjectB) a;
}
In Kotlin you don’t need to do this. The compiler does it for you.
Smart Cast
If you check the variable for a certain type, you don’t need to cast it afterwards. You can use it as having the type you checked for previously
fun printStringLength(any: Any) {
if (any is String) {
// we can access methods from String class
// without a manual cast.
println(any.length)
}
}
Smart casts can only be used on objects or variables that the compiler can guarantee has not changed between the time when the variable is checked and the time when it’s used.
var fields and local vars that have been closed over and mutated cannot be used in smart casts.
Explicit Casting
To cast a reference explicitly we use the as
operator. This operation will throw a ClassCastException if the cast cannot be performed legally.
fun length(any: Any): Int {
val string = any as String
return string.length
}
The null value cannot be cast to a type that’s not defined as nullable.
To cast to a value that can be null, declare the required type as nullable
val string: String? = any as String