Created by Erik Nelson
A statically-typed JVM languaged developed by JetBrains
package hello
fun main(args: Array) : Unit {
println("Hello World!")
}
or more simply:
package hello
fun main(args: Array) {
println("Hello World!")
}
class Greeter(val name: String) {
fun greet() {
println("Hello, $name")
}
}
fun main(args: Array) {
Greeter(args[0]).greet()
}
val a: Int = 1
val b = 1 // `Int` type is inferred
val c: Int // Type required when no initializer is provided
c = 1 // definite assignment
var x = 5 // `Int` type is inferred
x += 1
Abbreviated form:
val sum = { x: Int, y: Int -> x + y }
Full syntactic form:
val sum: (Int, Int) -> Int = { x, y -> x + y }
One param lambda:
ints.filter { it > 0 } // this literal is of type '(it: Int) -> Boolean'
fun lock(lock: Lock, body: () -> T): T {
lock.lock()
try {
return body()
}
finally {
lock.unlock()
}
}
Most of these structures should be familiar from Java, with some noted improvements
In Kotlin if is an expression (it returns a value)
// Traditional usage
var max = a
if (a < b)
max = b
// With else
var max: Int
if (a > b)
max = a
else
max = b
// As expression
val max = if (a > b) a else b
if branches can be blocks. In this case the last expression is the value of the block.
val max = if (a > b) {
print("Choose a")
a
}
else {
print("Choose b")
b
}
for (arg in args) {
print(arg)
}
while (i < args.size){
print(args[i++])
}
The when expression replaces the switch operator of C-style languages
fun cases(obj: Any) {
when (obj) {
1 -> print("One")
"Hello" -> print("Greeting")
is Long -> print("Long")
!is String -> print("Not a string")
else -> print("Unknown")
}
}
val i = 10
val s = "i = $i" // evaluates to "i = 10"
expressions are supported via curly braces:
val s = "abc"
val str = "$s.length is ${s.length}" // "abc.length is 3"
Check if a number is in a range:
if (x in 1..y-1)
print("OK")
Or out of range:
if (x !in 1..y-1)
print("OUT")
Iterating over a range:
for (x in 1..5)
print(x)
Iterating over a collection:
for (name in names)
println(name)
Check if a collection contains an object
if (text in names) // names.contains(text) is called
print("Yes")
Filter and map with lambda expressions:
names
.filter { it.startsWith("A") }
.sortedBy { it }
.map { it.toUpperCase() }
.forEach { print(it) }
Generates the following methods for free:
Example:
data class User(val name: String, val age: Int)
Regular variables can not be null:
var a: String = "abc"
a = null // compilation error
To allow nulls, declare the variable as a nullable type:
var b: String? = "abc"
b = null // ok
Property access:
var a: String = "abc"
val l = a.length // ok
Compiler error if you try to access a nullable:
var b: String? = "def"
val l = b.length // error: variable 'b' can be null
val l = if (b != null) b.length else -1
The compiler tracks null checks, which allows for:
if (b != null && b.length > 0)
print("String of length ${b.length}")
else
print("Empty string")
* Only works when b is immutable
Recall this:
var b: String? = "def"
val l = b.length // error: variable 'b' can be null
How do we get around this? The safe operator:
?.
var b: String? = "def"
val l = b?.length
returns b.length if b is not null, otherwise returns null
bob?.department?.head?.name
This call will return null if any of the properties in the chain are null
val l: Int = if (b != null) b.length else -1
The above can be rewritten more simply:
val l = b?.length ?: -1
Advanced example:
fun foo(node: Node): String? {
val parent = node.getParent() ?: return null
val name = node.getName() ?: throw IllegalArgumentException("name expected")
// ...
}
If your life just feels too empty without NPEs...
val l = b!!.length()
This will return the length if b has value, otherwise will throw a NullPointerException
Allow you to extend a class with new functionality without having to inherit from the class or use any type of design pattern such as a Decorator.
Two kinds of extensions:
No more Util classes!
To declare an extension function, its name must be prefixed with a receiver type (the type being extended)
fun MutableList.swap(index1: Int, index2: Int) {
val tmp = this[index1] // 'this' corresponds to the list
this[index1] = this[index2]
this[index2] = tmp
}
This can now be used on any MutableList<Int>:
val l = mutableListOf(1, 2, 3)
l.swap(0, 2) // 'this' inside 'swap()' will hold the value of 'l'
val List.lastIndex: Int
get() = size - 1
Extensions don't insert members into classes, so initializers are not allowed. Getters/setters must be used.