Kotlin Docs
Kotlin Docs
Table of Contents
Getting Started 4
Basic Syntax 4
Idioms 10
Coding Conventions 15
Basics 17
Basic Types 17
Packages 23
Control Flow 24
Interfaces 39
Visibility Modifiers 41
Extensions 43
Data Classes 49
Generics 51
Generic functions 55
Generic constraints 55
Nested Classes 57
Enum Classes 58
Delegation 63
Delegated Properties 64
Functions 67
Inline Functions 78
Other 81
2
Destructuring Declarations 81
Collections 83
Ranges 85
This Expression 90
Equality 91
Operator overloading 92
Null Safety 95
Exceptions 98
Annotations 100
Reflection 104
Reference 113
Interop 116
Tools 131
FAQ 146
FAQ 146
3
Getting Started
Basic Syntax
Defining packages
Package specification should be at the top of the source file:
It is package
not required to match directories and packages: source files can be placed arbitrarily in the file system.
my.demo
See Packages.
import java.util.*
Defining
// ...functions
Function having two Int
parameters with Int return type:
Function
fun returning
sum(a: no meaningful
Int, b: Int) value:
= a + b
Unit
funreturn type can be Int,
printSum(a: omitted:
b: Int):
Unit { print(a + b)
See}Functions.
fun printSum(a: Int, b: Int)
{ print(a + b)
}
4
Defining local variables
Assign-once (read-only) local variable:
Mutable
val variable:
a: Int = 1
val b = 1 // `Int` type is inferred
val
Seevar c:
also x Int
Properties // Type required when no initializer is
= 5 // And Fields
`Int` .
type is
provided c = 1 // definite assignment
inferred x += 1
Comments
Just like Java and JavaScript, Kotlin supports end-of-line and block comments.
Unlike
// Java,
Thisblock
is comments in Kotlin can
an end-of-line be nested.
comment
See Documenting Kotlin Code for information on the documentation comment syntax.
/* This is a block
comment on multiple
Using string
lines.templates
*/
Seefun
String templates. Array<String>) {
main(args:
if (args.size == 0) return
Using conditional expressions
print("First argument: ${args[0]}")
}
Using if max(a:
fun as an expression:
Int, b: Int): Int {
if (a > b)
return a
fun max(a: Int, b: Int) = if (a > b) a else b
else
return b
}
5
See if-expressions.
Usefun
a function returning nullable
parseInt(str: value: Int? {
String):
// ...
or }
fun main(args: Array<String>) {
if (args.size < 2) {
See Null- print("Two integers expected")
//safety
... .
return
if (x == null) {
}
Using type print("Wrong
checks andnumberautomaticformat
castsin '${args[0]}'")
return
The isval x = parseInt(args[0])
} operator checks if an expression is an instance of a type. If an immutable local variable or property is checked for a
val y = parseInt(args[1])
specificiftype,
(y there’s
== null)
no need
{ to cast it explicitly:
print("Wrong number format in '${args[1]}'")
// Using `x * y` yields error because they may hold nulls.
return
if (x != null && y != null) {
}
// x and y are automatically cast to non-nullable after null
check print(x * y)
// x and y are automatically cast to non-nullable after null check
}
print(x * y)
}
6
fun getStringLength(obj: Any): Int? {
if (obj is String) {
// `obj` is automatically cast to `String` in this branch
return obj.length
}
or
or even
fun getStringLength(obj: Any): Int? {
if (obj !is String)
Seefun return
Classes nullcasts.
and Type
getStringLength(obj: Any): Int? {
// `obj` is automatically cast to `String` on the right-hand side of `&&`
// `obj` is automatically cast to `String` in this branch
Usingif (obj loop
a for is String && obj.length >
return obj.length
0)
return obj.length
}
or fun main(args: Array<String>) {
return null
} for (arg in args)
Seefor print(arg)
for loop
(i. in args.indices)
}
print(args[i])
Using a while loop
7
fun main(args: Array<String>) {
var i = 0
while (i < args.size)
print(args[i++])
}
Seefunwhencases(obj:
expression. Any) {
when (obj) {
Using ranges1 -> print("One")
"Hello" ->
Check if aprint("Greeting")
number is within a range isusing
Longin operator:
-
> print("Long")
Check a!is
if if(x
String
number is out->
in 1..y-
print("Not a string")
of range:
else -> print("Unknown")
1)
}
print("OK")
Iterating over a range:
if (x !in 0..array.lastIndex)
print("Out")
SeeforRanges.
(x in 1..5)
print(x)
Using collections
Iterating over a collection:
Checking if a collection
for (name contains an object using in operator:
in names)
println(name)
8
if (text in names) // names.contains(text) is
called print("Yes")
Seenames
Higher-order functions and Lambdas.
.filter { it.startsWith("A") }
.sortedBy { it }
.map { it.toUpperCase() }
.forEach { print(it) }
9
Idioms
A collection of random and frequently used idioms in Kotlin. If you have a favorite idiom, contribute it. Do a pull request.
provides Customer
dataa class class with thename:
Customer(val following functionality:
String, val email: String)
— equals()
— hashCode()
— toString()
— copy()
— component1() , component2() , …, for all properties (see Data classes)
fun foo(a:
Filtering a list Int = 0, b: String = "") { ... }
Or alternatively,
val positives even shorter:
= list.filter { x -> x > 0 }
valInterpolation
String positives = list.filter { it > 0 }
println("Name
Instance Checks $name")
when (x)
Traversing {
a map/list of pairs
is Foo -> ...
is Bar -> ...
for ((k,
else v)-> in...
map)
} { println("$k -> $v")
}
10
k ,v can be called anything.
Using ranges
val list
Read-only map = listOf("a", "b", "c")
val map
Accessing = mapOf("a" to 1, "b" to 2, "c" to 3)
a map
Lazyprintln(map["key"])
property
map["key"] = value
val p:Functions
Extension String by lazy {
// compute the string
}
fun String.spaceToCamelCase()
Creating a singleton { ... }
println(files?.size)
11
val files = File("Test").listFiles()
println(files?.size ?: "empty")
val if
Execute data = ...
not null
val email = data["email"] ?: throw IllegalStateException("Email is missing!")
valon
Return data
when= statement
...
data?.let {
fun transform(color:
‘try/catch’... String):
// execute this
expression block Int { null
if not
} return when (color) {
"Red" -> 0
fun test() {
‘if’ expression "Green" -> 1
val "Blue"
result ->
= try
2 {
count()
else -> throw IllegalArgumentException("Invalid color param value")
} }catch (e: ArithmeticException) {
} throw IllegalStateException(e)
}
12
fun foo(param: Int) {
val result = if (param == 1)
{ "one"
} else if (param == 2) {
"two"
} else {
"three"
}
}
fun arrayOfMinusOnes(size:
Single-expression functions Int): IntArray {
return IntArray(size).apply { fill(-1) }
}
Thisfun
is equivalent to
theAnswer() = 42
Thisfun
can be effectively combined
theAnswer(): Int {with other idioms, leading to shorter code. E.g. with the when-expression:
return 42
}
fun multiple
Calling transform(color:
methods on anString): Int =(‘with’)
object instance when (color) {
"Red" -> 0
"Green" -> 1
"Blue" -> 2
else -> throw IllegalArgumentException("Invalid color param value")
}
13
class Turtle {
fun
penDown()
fun penUp()
fun turn(degrees: Double)
fun forward(pixels: Double)
}
val stream
Convenient = Files.newInputStream(Paths.get("/some/file.txt"))
form for a generic function that requires the generic type information
stream.buffered().reader().use { reader ->
println(reader.readText())
// public final class Gson {
}
// ...
// public <T> T fromJson(JsonElement json, Class<T> classOfT)
throws JsonSyntaxException {
// ...
14
Coding Conventions
This page contains the current coding style for the Kotlin language.
Naming Style
If in doubt default to the Java Coding Conventions such as:
Colon
There is a space before colon where colon separates type and supertype and there’s no space where colon separates
instance and type:
Unit
If a function returns Unit, the return type should be omitted:
15
— returns the same result over invocations
16
Basics
Basic Types
In Kotlin, everything is an object in the sense that we can call member functions and properties on any variable. Some
types are built-in, because their implementation is optimized, but to the user they look like ordinary classes. In this section
we describe most of these types: numbers, characters, booleans and arrays.
Numbers
Kotlin handles numbers in a way close to Java, but not exactly the same. For example, there are no implicit widening
conversions for numbers, and literals are slightly different in some cases.
Kotlin provides the following built-in types representing numbers (this is close to Java):
Literal Constants
There are the following kinds of literal constants for integral values:
— Decimals: 123
— Longs are tagged by a capital L :123L
— Hexadecimals: 0x0F
— Binaries: 0b00001011
Representation
17
On the Java platform, numbers are physically stored as JVM primitive types, unless we need a nullable number reference
(e.g. Int? ) or generics are involved. In the latter cases numbers are boxed.
On the
valother
a: hand,
Int =it preserves
10000 equality:
print(a === a) // Prints 'true'
val boxedA: Int? = a
val Conversions
Explicit a: Int = 10000
val anotherBoxedA: Int? = a
print(a == a) // Prints 'true'
print(boxedA === anotherBoxedA) // !!!Prints 'false'!!!
Dueval boxedA:
to different Int? = a smaller types are not subtypes of bigger ones. If they were, we would have troubles of the
representations,
val anotherBoxedA:
following sort: Int? = a
print(boxedA == anotherBoxedA) // Prints 'true'
So not
// only identity, but even
Hypothetical equality
code, does would
nothave been lostcompile:
actually silently all over the place.
val a: Int? = 1 // A boxed Int (java.lang.Integer)
As a consequence, smaller types are NOT implicitly converted to bigger types. This means that we cannot assign a value of
val b: Long? = a // implicit conversion yields a boxed Long (java.lang.Long)
type Byte to an Int variable without an explicit conversion
print(a == b) // Surprise! This prints "false" as Long's equals() check for other
part to be Long as well
Every
valnumber type=supports
i: Int the following
b.toInt() // OK: conversions:
explicitly widened
— toByte(): Byte
— toShort(): Short
— toInt(): Int
— toLong(): Long
— toFloat(): Float
— toDouble(): Double
— toChar(): Char
18
Absence of implicit conversions is rarely noticeable because the type is inferred from the context, and arithmetical
operations are overloaded for appropriate conversions, for example
Kotlin supports the standard set of arithmetical operations over numbers, which are declared as members of appropriate
classes (but the compiler optimizes the calls down to the corresponding instructions). See Operator overloading.
As of bitwise operations, there’re no special characters for them, but just named functions that can be called in infix form, for
example:
Hereval
is the
x complete
= (1 shl list 2)
of bitwise operations (available for Int
and 0x000FF000 and Long only):
Characters
Characters are represented by the type Char . They can not be treated directly as numbers
Likefun
numbers, characters are boxed when
decimalDigitValue(c: a nullable
Char): Int {reference is needed. Identity is not preserved by the boxing operation.
if (c !in '0'..'9')
Booleans throw IllegalArgumentException("Out of range")
return c.toInt() - '0'.toInt() // Explicit conversions to numbers
}
19
The type Boolean represents booleans, and has two values: true and false.
— || – lazy disjunction
— && – lazy conjunction
— ! - negation
Arrays
Arrays in Kotlin are represented by the
Array class, that has get and set functions (that turn into [] by operator
overloading conventions), and size property, along with a few other useful member functions:
To create
classanArray<T>
array, we can use a library
private function arrayOf()
constructor() { and pass the item values to it, so thatarrayOf(1, 2, 3)
createsvalan array
size: [1, 2,
Int3]. Alternatively, the arrayOfNulls() library function can be used to create an array of a given size
filled with null elements.
fun get(index: Int): T
fun set(index: Int, value: T): Unit
Another option is to use a factory function that takes the array size and the function that can return the initial value of each
array element given its index:Iterator<T>
fun iterator():
// ...
}
As we
// said above, an
Creates the []
Array<String>
operation standswith values
for calls ["0",functions
to member "1", "4",
get()"9",and "16"]
set() .
val asc = Array(5, { i -> (i * i).toString() })
Note: unlike Java, arrays in Kotlin are invariant. This means that Kotlin does not let us assign an Array<String> to an
Array<Any> , which prevents a possible runtime failure (but you can use Array<out Any> , see Type Projections).
Kotlin also has specialized classes to represent arrays of primitive types without boxing overhead: ByteArray ,
ShortArray , IntArray and so on. These classes have no inheritance relation to the Array class, but they have the
same set of methods and properties. Each of them also has a corresponding factory function:
20
for (c in str)
{ println(c)
}
String Literals
Kotlin has two types of string literals: escaped strings that may have escaped characters in them and raw strings that can
contain newlines and arbitrary text. An escaped string is very much like a Java string:
Escaping
val sis =
done in the conventional
"Hello, world!\n"way, with a backslash. See Characters above for the list of supported escape
sequences.
A raw string is delimited by a triple quote ( """ ), contains no escaping and can contain newlines and any other characters:
Youval
can remove
text =leading
""" whitespace with trimMargin() function:
for (c in "foo")
By default print(c)
| is used as margin prefix, but you can choose another character and pass it as a parameter, like
val text = """
"""
trimMargin(">")
|Tell me .and I forget.
|Teach me and I remember.
|Involve me and I learn.
String Templates
|(Benjamin
Strings mayFranklin)
contain template expressions, i.e. pieces of code that are evaluated and whose results are concatenated into the
""".trimMargin()
string. A template expression starts with a dollar sign ($) and consists of either a simple name:
or an arbitrary
val i = expression
10 in curly braces:
val s = "i = $i" // evaluates to "i = 10"
Templates
val s are supported both inside raw strings and inside escaped strings. If you need to represent a
= "abc" $ character in
literal
vala raw string
str (which doesn’tis
= "$s.length support backslash escaping),
${s.length}" you can to
// evaluates use "abc.length
the following syntax:
is 3"
21
val price = """
$
{'$'}9.9
9 """
22
Packages
A source file may start with a package declaration:
or allimport
the accessible
foo.Barcontents
// Barof a is
scope
now(package, class, object
accessible withoutetc): qualification
If there is a name
import clash,
foo.* // we can disambiguate
everything by using
in 'foo' as keyword
becomes to locally rename the clashing entity:
accessible
import foo.Bar
The import keyword is//
notBar
restricted to importing classes; you can also use it to import other declarations:
is accessible
import bar.Bar as bBar // bBar stands for 'bar.Bar'
— top-level functions and properties;
— functions and properties declared in object declarations;
— enum constants
Unlike Java, Kotlin does not have a separate “import static” syntax; all of these declarations are imported using the regular
import keyword.
23
Control Flow
If Expression
In Kotlin, if is an expression, i.e. it returns a value. Therefore there is no ternary operator (condition ? then : else), because
ordinary if works fine in this role.
24
The else branch is evaluated if none of the other branch conditions are satisfied. If when is used as an expression, the
else branch is mandatory, unless the compiler can prove that all possible cases are covered with branch
conditions. If many cases should be handled in the same way, the branch conditions may be combined with a
comma:
when (x) {
0, 1 -> print("x == 0 or x == 1")
We can use arbitrary expressions (not only constants) as branch conditions
else -> print("otherwise")
}
We when
can also (x)check
{ a value for being in or !in a range or a collection:
parseInt(s) -> print("s encodes x")
Anotherelse -> print("s does not encode x")
whenpossibility
(x) { is to check that a value is or !is of a particular type. Note that, due to smart casts, you can access the
}
methodsinand properties
1..10 of the type is
-> print("x without any extra
in the checks.
range")
in validNumbers -> print("x is valid")
when !in 10..20
canhasPrefix
also -> as
be used print("x is outside
a replacement the range")
for an if-else if chain. If no argument is supplied, the branch conditions are
val = when(x) {
else
simply is
boolean -> print("none
expressions, and aof the
branch above")
is executed when its condition is true:
String -> x.startsWith("prefix")
}
else -> false
}
Seewhen
the grammar for when.
{
x.isOdd() -> print("x is odd")
x.isEven() -> print("x is
For Loops
even") else -> print("x is
for loop iterates through anything that provides an iterator. The syntax is as follows:
funny")
25
The body can be a block.
As mentioned
for (item:before,
Intfor
in iterates
ints)through
{ anything that provides an iterator, i.e.
// ...
— has a member- or extension-function iterator() , whose return type
}
— has a member- or extension-function next() , and
— has a member- or extension-function hasNext() that returns Boolean .
A for loop over an array is compiled to an index-based loop that does not create an iterator object.
If you want to iterate through an array or a list with an index, you can do it this way:
Notefor
that (i
this in
“iteration through a range” is compiled down to optimal implementation with no extra objects created.
array.indices)
print(array[i])
Alternatively, you can use the withIndex library function:
Seefor
the grammar for for
((index, .
value) in array.withIndex())
{ println("the element at $index is $value")
} Loops
While
while and do..while work as usual
Seewhile
the grammar
(x > for while.
0) { x--
}
Break and continue in loops
Kotlin
dosupports
{ traditional break and continue operators in loops. See Returns and jumps.
val y = retrieveData()
} while (y != null) // y is visible here!
26
Returns and Jumps
Kotlin has three structural jump operators
— return. By default returns from the nearest enclosing function or anonymous function.
— break. Terminates the nearest enclosing loop.
— continue. Proceeds to the next step of the nearest enclosing loop.
Now, we canfor
loop@ qualify
(i ain
break or a continue
1..100) { with a label:
// ...
}
A break
loop@qualified
for (iwith
ina 1..100)
label jumps{to the execution point right after the loop marked with that label. A continue
proceeds
forto (j
the next iteration of{that loop.
in 1..100)
if (...)
Return at break@loop
Labels
}
With}function literals, local functions and object expression, functions can be nested in Kotlin. Qualified returns allow us to
return from an outer function. The most important use case is returning from a lambda expression. Recall that when we write
this:
The fun
return-expression
foo() returns from the nearest enclosing function, i.e. foo . (Note that such non-local returns are
supported only for lambda expressions passed to inline functions.) If we need to return from a lambda expression, we have
{ ints.forEac
to labelhit {and qualify the return:
if (it == 0) return
print(it)
fun
} foo()
{ ints.forEach
lit@ {
if (it == 0) return@lit
print(it)
}
27
Now, it returns only from the lambda expression. Oftentimes it is more convenient to use implicits labels: such a label has the
same name as the function to which the lambda is passed.
Alternatively,
fun foo() we can replace the lambda expression with an anonymous function. A return statement in an anomymous
function
{ will return from the anonymous function itself.
ints.forEac
h {
When if (it == 0) return@forEach
fun foo()a {value, the parser gives preference to the qualified return, i.e.
returning
print(it)
ints.forEach(fun(value: Int)
}
means {“return 1 at label @a ” and not “return a labeled expression (@a 1) ”.
return@a 1
if (value == 0) return
print(value)
})
28
Classes and Objects
Classes and Inheritance
Classes
Classes in Kotlin are declared using the keyword class:
The class
class declaration
Invoice consists
{ of the class name, the class header (specifying its type parameters, the primary constructor
etc.)}and the class body, surrounded by curly braces. Both the header and the body are optional; if the class has no body,
curly braces can be omitted.
class Empty
Constructors
A class in Kotlin can have a primary constructor and one or more secondary constructors. The primary constructor is
part of the class header: it goes after the class name (and optional type parameters).
If theclass
primary constructor
Person does not have any annotations
constructor(firstName: or visibility
String) { modifiers, the constructor keyword can be omitted:
}
The class
primaryPerson(firstName:
constructor cannot contain any code.
String) { Initialization code can be placed in initializer blocks, which are prefixed
with}the init keyword:
Noteclass
that parameters of the primary
Customer(name: constructor
String) { can be used in the initializer blocks. They can also be used in property
initializersinit
declared
{ in the class body:
logger.info("Customer initialized with value ${name}")
}
}
29
class Customer(name: String) {
val customerKey = name.toUpperCase()
}
In fact, for declaring properties and initializing them from the primary constructor, Kotlin has a concise syntax:
For class
more details, see Visibility
Customer public Modifiers
@Inject . constructor(name: String) { ... }
Secondary Constructors
The class can also declare secondary constructors, which are prefixed with constructor:
30
NOTE: On the JVM, if all of the parameters of the primary constructor have default values, the compiler will
generate an additional parameterless constructor which will use the default values. This makes it easier to use
Kotlin with libraries such as Jackson or JPA that create class instances through parameterless constructors.
Noteval
that invoice
Kotlin does=not have a new keyword.
Invoice()
val
Class customer = Customer("Joe Smith")
Members
Inheritance
All classes in Kotlin have a common superclass Any , that is a default super for a class with no supertypes declared:
Anyclass
is not Example
java.lang.Object ; in particular,
// Implicitly inherits it does not have
from Any any members other than equals() hashCode() and
,
toString() . Please consult the Java interoperability section for more details.
To declare an explicit supertype, we place the type after a colon in the class header:
If the class has a primary constructor, the base type can (and must) be initialized right there, using the parameters of the
primary constructor.
If the class has no primary constructor, then each secondary constructor has to initialize the base type using the super
keyword, or to delegate to another constructor which does that. Note that in this case different secondary constructors can
call different constructors of the base type:
31
class MyView : View {
constructor(ctx: Context) : super(ctx) {
}
The open annotation on a class is the opposite of Java’s final: it allows others to inherit from this class. By default, all
classes in Kotlin are final, which corresponds to Effective Java, Item 17: Design and document for inheritance or else
prohibit it.
Overriding Members
As we mentioned before, we stick to making things explicit in Kotlin. And unlike Java, Kotlin requires explicit annotations for
overridable members (we call them open) and for overrides:
The override
open annotation
class Base { is required for Derived.v() . If it were missing, the compiler would complain. If there is no
openopen
annotation
fun v() on a{}
function, like Base.nv() , declaring a method with the same signature in a subclass is illegal,
either with
fun override
nv() {} or without it. In a final class (e.g. a class with no open annotation), open members are prohibited.
}
A member
class marked override
Derived() is itself{open, i.e. it may be overridden in subclasses. If you want to prohibit re-overriding, use
: Base()
final:override fun v() {}
}
open
Wait! How class AnotherDerived()
will I hack my libraries now?! : Base() {
final override fun v() {}
One}issue with our approach to overriding (classes and members final by default) is that it would be difficult to subclass
something inside the libraries you use to override some method that was not intended for overriding by the library designer,
and introduce some nasty hack there.
— Best practices say that you should not allow these hacks anyway
— People successfully use other languages (C++, C#) that have similar approach
— If people really want to hack, there still are ways: you can always write your hack in Java and call it from Kotlin ( see
Jav Interop), and Aspect frameworks always work for these purposes
Overriding Rules
32
In Kotlin, implementation inheritance is regulated by the following rule: if a class inherits many implementations of the same
member from its immediate superclasses, it must override this member and provide its own implementation (perhaps, using
one of the inherited ones). To denote the supertype from which the inherited implementation is taken, we use super
qualified by the supertype name in angle brackets, e.g. super<Base> :
It’s fine
opento inherit
classfrom
A {both and B , and we have no problems and since inherits only one
A with
open fun f() { print("A") } a() b() C
fun a()of{each
implementation print("a") }
of these functions. But for f() we have two implementations inherited by C , and thus we have to
} f() in C and provide our own implementation that eliminates the ambiguity.
override
interface B {
Abstract
funClasses
f() { print("B") } // interface members are 'open' by default
fun b() { print("b") }
A class and some of its members may be declared abstract. An abstract member does not have an implementation in its
}
class. Note that we do not need to annotate an abstract class or function with open – it goes without saying.
class C() : A(), B {
We can override a non-abstract open member with an abstract one
// The compiler requires f() to be overridden:
override fun f() {
super<A>.f()
open class Base { // call to A.f()
Companion Objects
opensuper<B>.f()
fun f() {} // call to B.f()
} } unlike Java or C#, classes do not have static methods. In most cases, it’s recommended to simply use package-
In Kotlin,
level}functions instead.
abstract class Derived : Base() {
If you need to writeabstract
override a function that
funcan be called without having a class instance but needs access to the internals of a
f()
class} (for example, a factory method), you can write it as a member of an object declaration inside that class.
Even more specifically, if you declare a companion object inside your class, you’ll be able to call its members with the same
syntax as calling static methods in Java/C#, using only the class name as a qualifier.
Sealed Classes
33
Sealed classes are used for representing restricted class hierarchies, when a value can have one of the types from a
limited set, but cannot have any other type. They are, in a sense, an extension of enum classes: the set of values for an
enum type is also restricted, but each enum constant exists only as a single instance, whereas a subclass of a sealed
class can have multiple instances which can contain state.
To declare a sealed class, you put the sealed modifier before the name of the class. A sealed class can have subclasses,
but all of them must be nested inside the declaration of the sealed class itself.
Notesealed
that classes which
class extend
Expr { subclasses of a sealed class (indirect inheritors) can be placed anywhere, not necessarily
inside theclass
declaration of the sealed
Const(val class. Double) : Expr()
number:
class Sum(val e1: Expr, val e2: Expr) :
The key benefit of using sealed classes comes into play when you use them in a when expression. If it’s possible to verify
Expr() object NotANumber : Expr()
that }the statement covers all cases, you don’t need to add an else clause to the statement.
34
Properties and Fields
Declaring Properties
Classes in Kotlin can have properties. These can be declared as mutable, using the var keyword or read-only using the val
keyword.
To use a property,
public class weAddress
simply refer
{ to it by name, as if it were a field in Java:
public var name: String = ...
public var street: String = ...
fun copyAddress(address: Address): Address {
Getters and Setters
public var city: String = ...
val result = Address() // there's no 'new' keyword in Kotlin
public var state: String? = ...
The fullresult.name = address.name
syntax for declaring a property is // accessors are called
public var zip: String = ...
result.street = address.street
}
// ...
The var
initializer, getter and setter<PropertyType>
<propertyName>: are optional. Property
[=type is optional if it can be inferred from the initializer or from the base
<property_initializer>]
return result
class member being overridden.
} [<getter>]
[<setter>]
Examples:
The var
full syntax of a read-onlyInt?
allByDefault: property
// declaration differs frominitializer
error: explicit a mutable one in two ways: itdefault
required, starts getter and of var
val instead
withsetter
and doesimplied
not allow a setter:
var initialized = 1 // has type Int, default getter and setter
val simple: Int? // has type Int, default getter, must be initialized in constructor
val inferredType = 1 // has type Int and a default getter
We can write custom accessors, very much like ordinary functions, right inside a property declaration. Here’s an example
of a custom getter:
35
val isEmpty: Boolean
get() = this.size == 0
field
The var identifier
counter = can
0 //onlythe
be used in the accessors
initializer value of the
is property.
written directly to the backing field
set(value) {
The compiler looks at the accessors’ bodies, and if they use the backing field (or the accessor implementation is left by
if (value >= 0)
default), a backing field is generated, otherwise it is not.
field = value
}
For example, in the following case there will be no backing field:
val Properties
Backing isEmpty: Boolean
get() = this.size == 0
If you want to do something that does not fit into this “implicit backing field” scheme, you can always fall back to having a
backing property:
36
private var _table: Map<String, Int>? = null
public val table: Map<String, Int>
get() {
if (_table == null)
_table = HashMap() // Type parameters are inferred
return _table ?: throw AssertionError("Set to null by another thread")
}
In all respects, this is just the same as in Java since access to private properties with default getters and setters is optimized
so that no function call overhead is introduced.
Compile-Time Constants
Properties the value of which is known at compile time can be marked as compile time constants using
const modifier.
the Such properties need to fulfil the following requirements:
— Top-level or member of an
object
— Initialized with a value of type String
or a primitive type
— No custom getter
Late-Initialized Properties
Normally, properties declared as having a non-null type must be initialized in the constructor. However, fairly often this is
not convenient. For example, properties can be initialized through dependency injection, or in the setup method of a unit
test. In this case, you cannot supply a non-null initializer in the constructor, but you still want to avoid null checks when
referencing the property inside the body of a class.
To handle this case, you can mark the property with the lateinit modifier:
The public
modifier can onlyMyTest
class { var properties declared inside the body of a class (not in the primary constructor), and
be used on
only whenlateinit
the property does
var not have aTestSubject
subject: custom getter or setter. The type of the property must be non-null, and it must not
be a primitive type.
@SetUp fun setup()
Accessing a lateinit
{ subject property
= before it has been initialized throws a special exception that clearly identifies the property
being accessedTestSubject()
and the fact that it hasn’t been initialized.
}
37
Overriding Properties
See Overriding Members
Delegated Properties
The most common kind of properties simply reads from (and maybe writes to) a backing field. On the other hand, with
custom getters and setters one can implement any behaviour of a property. Somewhere in between, there are certain
common patterns of how a property may work. A few examples: lazy values, reading from a map by a given key, accessing
a database, notifying listener on access, etc.
38
Interfaces
Interfaces in Kotlin are very similar to Java 8. They can contain declarations of abstract methods, as well as method
implementations. What makes them different from abstract classes is that interfaces cannot store state. They can have
properties but these need to be abstract or to provide accessor implementations.
interface MyInterface {
Implementing Interfaces
fun bar()
A class orfun foo()
object {
can implement one or more interfaces
// optional body
}
class
} Child : MyInterface {
Properties in Interfaces
override fun bar() {
// body
You can declare properties in interfaces. A property declared in an interface can either be abstract, or it can provide
}
implementations for accessors. Properties declared in interfaces can’t have backing fields, and therefore accessors
}
declared in interfaces can’t reference them.
interface MyInterface {
Resolving overriding conflicts
val property: Int // abstract
When we declare many types in our supertype list, it may appear that we inherit more than one implementation of the same
valexample
method. For propertyWithImplementation: String
get() = "foo"
fun foo() {
print(property)
}
}
39
interface A {
fun foo() { print("A") }
fun bar()
}
interface B {
fun foo() { print("B") }
fun bar() { print("bar") }
}
class C : A {
override fun bar() { print("bar") }
}
class D : A, B {
override fun foo() {
super<A>.foo()
super<B>.foo()
}
}
Interfaces A and B both declare functions foo() and bar(). Both of them implement foo(), but only B implements bar() (bar()
is not marked abstract in A, because this is the default for interfaces, if the function has no body). Now, if we derive a
concrete class C from A, we, obviously, have to override bar() and provide an implementation. And if we derive D from A
and B, we don’t have to override bar(), because we have inherited only one implementation of it. But we have inherited two
implementations of foo(), so the compiler does not know which one to choose, and forces us to override foo() and say what
we want explicitly.
40
Visibility Modifiers
Classes, objects, interfaces, constructors, functions, properties and their setters can have visibility modifiers. (Getters
always have the same visibility as the property.) There are four visibility modifiers in Kotlin: private , protectedinternal,
and public . The default visibility, used if there is no explicit modifier, is public .
Below please find explanations of these for different type of declaring scopes.
Packages
Functions, properties and classes, objects and interfaces can be declared on the “top-level”, i.e. directly inside a package:
— //
If you do not
file specify
name: any visibility
example.kt public is used by default, which means that your declarations will be visibl
modifier, everywhere;
package foo
— If you mark a declaration private , it will only be visible inside the file containing the declaration;
fun baz() {}
— If you mark it internal , it is visible everywhere in the same module;
class Bar {}
— protected is not available for top-level declarations.
Examples:
— private means visible inside this class only (including all its members);
— protected — same as private + visible in subclasses too;
— internal — any client inside this module who sees the declaring class sees its internal members;
— public — any client who sees the declaring class sees its public members.
NOTE for Java users: outer class does not see private members of its inner classes in Kotlin.
Examples:
41
open class Outer {
private val a = 1
protected val b =
2 internal val c =
3
val d = 4 // public by default
Constructors
To specify a visibility of the primary constructor of a class, use the following syntax (note that you need to add an explicit
constructor keyword):
Hereclass
the constructor
C private is private. By default, all constructors
constructor(a: Int) { ...are} public , which effectively amounts to them being visible
everywhere where the class is visible (i.e. a constructor of an internal class is only visible within the same module).
Local declarations
Local variables, functions and classes can not have visibility modifiers.
Modules
The internal
visibility modifier means that the member is visible with the same module. More specifically, a module is a
set of Kotlin files compiled together:
42
Extensions
Kotlin, similar to C# and Gosu, provides the ability to extend a class with new functionality without having to inherit from the
class or use any type of design pattern such as Decorator. This is done via special declarations called extensions. Kotlin
supports extension functions and extension properties.
Extension Functions
To declare an extension function, we need to prefix its name with a receiver type, i.e. the type being extended. The following
adds a swap function to MutableList<Int> :
The fun
thisMutableList<Int>.swap(index1:
keyword inside an extension function corresponds
Int, index2:to theInt)
receiver
{ object (the one that is passed before the dot).
Now, we
valcantmp
call =
such a function on any
this[index1] // MutableList<Int>
'this' corresponds : to the list
this[index1] =
this[index2]
Of course, this[index2]
val l this function makes
= mutableListOf(1, sense for
2, any
3) MutableList<T> , and we can make it generic:
= tmp
l.swap(0, 2) // 'this' inside 'swap()' will hold the value of 'l'
We fun
declare
<T>theMutableList<T>.swap(index1:
generic type parameter before the function
Int, name for it to
index2: be available
Int) { in the receiver type expression. See
Generic functions.
val tmp = this[index1] // 'this' corresponds to the
list this[index1] = this[index2]
this[index2] = tmp
Extensions are resolved statically
}
Extensions do not actually modify classes they extend. By defining an extension, you do not insert new members into a class
but merely make new functions callable with the dot-notation on instances of this class.
We would like to emphasize that extension functions are dispatched statically, i.e. they are not virtual by receiver type. This
means that the extension function being called is determined by the type of the expression on which the function is invoked,
not by the type of the result of evaluating that expression at runtime. For example:
43
open class C
class D: C()
fun printFoo(c: C)
{ println(c.fo
o())
}
This example will print “c”, because the extension function being called depends only on the declared type of the parameter
c , which is theC class.
If a class has a member function, and an extension function is defined which has the same receiver type, the same name
and is applicable to given arguments, the member always wins. For example:
If weclass
call c.foo()
C { of any c of type C , it will print “member”, not “extension”.
fun foo() { println("member") }
}
Nullable Receiver
Notefun that C.foo()
extensions{canprintln("extension")
be defined with a nullable}receiver type. Such extensions can be called on an object variable even
if its value is null, and can check for this == null inside the body. This is what allows you to call toString() in Kotlin
without checking for null: the check happens inside the extension function.
44
Example:
val Foo.bar = 1 // error: initializers are not allowed for extension properties
Companion Object Extensions
If a class has a companion object defined, you can also define extension functions and properties for the companion object:
Justclass
like regular members
MyClass { of the companion object, they can be called using only the class name as the qualifier:
companion object { } // will be called "Companion"
}
MyClass.foo()
Scope of Extensions
fun MyClass.Companion.foo() {
Most of the time we define extensions on the top level, i.e. directly under packages:
// ...
}
To use such anfoo.bar
package extension outside its declaring package, we need to import it at the call site:
Seefun Baz.goo()
Imports
package
{ ... }
forcom.example.usage
more information.
importExtensions
Declaring foo.bar.goo // importing all extensions by name "goo"
as Members
// or
Inside a class,foo.bar.*
import you can declare
//extensions
importingfor another class. Inside
everything from such an extension, there are multiple implicit receivers -
"foo.bar"
objects members of which can be accessed without a qualifier. The instance of the class in which the extension is declared is
fun
called usage(baz:
dispatch receiver,Baz) { instance of the receiver type of the extension method is called extension receiver.
and the
baz.goo()
)
45
class D {
fun bar() { ... }
}
class C {
fun baz() { ... }
fun D.foo() {
bar() // calls
D.bar baz() //
calls C.baz
}
fun caller(d: D) {
d.foo() // call the extension function
}
In case of a name conflict between the members of the dispatch receiver and the extension receiver, the extension receiver
takes precedence. To refer to the member of the dispatch receiver you can use the qualified this syntax.
class C {
fun D.foo() {
toString() // calls D.toString()
[email protected]() // calls C.toString()
}
Extensions declared as members can be declared as open and overridden in subclasses. This means that the dispatch of
such functions is virtual with regard to the dispatch receiver type, but static with regard to the extension receiver type.
46
open class D {
}
class D1 : D() {
}
open class C {
open fun D.foo()
{ println("D.foo in C")
}
fun caller(d: D) {
d.foo() // call the extension function
}
}
class C1 : C() {
override fun D.foo()
{ println("D.foo in C1")
}
Motivation
In Java, we are used to classes named “*Utils”: FileUtils
StringUtils and so on. The famous
,
java.util.Collections belongs to the same breed. And the unpleasant part about these Utils-classes is that the code
that uses them looks like this:
Those
// class
Javanames are always getting in the way. We can use static imports and get this:
Collections.swap(list, Collections.binarySearch(list, Collections.max(otherList)),
ThisCollections.max(list))
is aJava
// little better, but we have no or little help from the powerful code completion of the IDE. It would be so much better if
we could say
swap(list, binarySearch(list, max(otherList)), max(list))
47
// Java
list.swap(list.binarySearch(otherList.max()), list.max())
But we don’t want to implement all the possible methods inside the class List , right? This is where extensions help us.
48
Data Classes
We frequently create a class to do nothing but hold data. In such a class some standard functionality is often mechanically
derivable from the data. In Kotlin, this is called a data class and is marked as data :
The data
compiler automatically
class User(val derives the following
name: String,members fromInt)
val age: all properties declared in the primary constructor:
If any of these functions is explicitly defined in the class body or inherited from the base types, it will not be generated.
To ensure consistency and meaningful behavior of the generated code, data classes have to fulfil the following requirements:
On the JVM, if the generated class needs to have a parameterless constructor, default values for all properties have
Copying
to be specified (see Constructors).
It’s often the case that we need to copy an object altering some of its properties, but keeping the rest unchanged. This is
data class User(val name: String = "", val age: Int = 0)
what copy() function is generated for. For the User class above, its implementation would be as follows:
49
The standard library provides Pair and Triple . In most cases, though, named data classes are a better design choice,
because they make the code more readable by providing meaningful names for properties.
50
Generics
As in Java, classes in Kotlin may have type parameters:
In general,
class toBox<T>(t:
create an instance
T) { of such a class, we need to provide the type arguments:
var value = t
But }
if the parameters
val box: may be=inferred,
Box<Int> e.g. from the constructor arguments or by some other means, one is allowed to omit
Box<Int>(1)
the type arguments:
val box = Box(1) // 1 has type Int, so the compiler figures out that we are talking
Variance
about Box<Int>
One of the most tricky parts of Java’s type system is wildcard types (see Java Generics FAQ). And Kotlin doesn’t have any.
Instead, it has two other things: declaration-site variance and type projections.
First, let’s think about why Java needs those mysterious wildcards. The problem is explained in Effective Java, Item 28: Use
bounded wildcards to increase API flexibility. First, generic types in Java are invariant, meaning that List<String> is no
a subtype of List<Object> . Why so? If List was not invariant, it would have been no better than Java’s arrays, since the
following code would have compiled and caused an exception at runtime:
So, //
JavaJava
prohibits such things in order to guarantee run-time safety. But this has some implications. For example, consider
the addAll()
List<String>method from=Collection
strs new ArrayList<String>();
interface. What’s the signature of this method? Intuitively, we’d put it this way:
List<Object> objs = strs; // !!! The cause of the upcoming problem sits here. Java
prohibits this!
// Java
objs.add(1); // Here we put an Integer into a list of Strings
interface
String s =Collection<E>
strs.get(0); ... { ClassCastException: Cannot cast Integer to String
// !!!
void addAll(Collection<E> items);
}
But then, we would not be able to do the following simple thing (which is perfectly safe):
(In Java, we learned this lesson the hard way, see Effective Java, Item 25: Prefer lists to arrays)
// Java
void copyAll(Collection<Object> to, Collection<String> from) {
to.addAll(from); // !!! Would not compile with the naive declaration of addAll:
// Collection<String> is not a subtype of Collection<Object>
}
51
That’s why the actual signature of addAll() is the following:
The // Java type argument ? extends T indicates that this method accepts a collection of objects of some subtype of
wildcard
notT itself. This
T ,interface means that we ...
Collection<E> can safely
{ read T ’s from items (elements of this collection are instances of a subclass
of T), but cannot
void write to it since we do not
addAll(Collection<? know what
extends E> objects
items);comply to that unknown subtype of T . In return for this
}
limitation, we have the desired behaviour: Collection<String> is a subtype of Collection<? extends Object> .
In “clever words”, the wildcard with an extends-bound (upper bound) makes the type covariant.
The key to understanding why this trick works is rather simple: if you can only take items from a collection, then using a
collection of String s and reading Object s from it is fine. Conversely, if you can only put items into the collection, it’s OK
to take a collection of Object s and put String s into it: in Java we List<? super String> a supertype of
have
List<Object> .
The latter is called contravariance, and you can only call methods that take String as an argument on List<? super
String> (e.g., you can call add(String) or set(int, String) ), while if you call something that returns T in
List<T> , you don’t get a String , but an Object .
Joshua Bloch calls those objects you only read from Producers, and those you only write to Consumers. He recommends:
“For maximum flexibility, use wildcard types on input parameters that represent producers or consumers”, and proposes the
following mnemonic:
NOTE: if you use a producer-object, say, List<? extends Foo> , you are not allowed to calladd() or set() on this
object, but this does not mean that this object is immutable: for example, nothing prevents you from calling clear() to
remove all items from the list, since clear() does not take any parameters at all. The only thing guaranteed by wildcards
(or other types of variance) is type safety. Immutability is a completely different story.
Declaration-site variance
// Java
interface Source<T>
{ T nextT();
}
Then, it would be perfectly safe to store a reference to an instance of Source<String> in a variable of type
Source<Object> – there are no consumer-methods to call. But Java does not know this, and still prohibits it:
// Java
void demo(Source<String> strs) {
Source<Object> objects = strs; // !!! Not allowed in Java
// ...
}
52
To fix this, we have to declare objects of type Source<? extends Object> , which is sort of meaningless, because we
can call all the same methods on such a variable as before, so there’s no value added by the more complex type. But the
compiler does not know that.
In Kotlin, there is a way to explain this sort of thing to the compiler. This is called declaration-site variance: we can annotat
the type parameter T of Source to make sure that it is only returned (produced) from members of Source<T> , and neve
consumed. To do this we provide the out modifier:
The abstract
general ruleclass
is: whenSource<out
a type parameter
T> {T of a class C is declared out, it may occur only in out-position in the
abstract fun nextT(): T
members of C , but in returnC<Base> can safely be a supertype of C<Derived> .
}
In “clever words” they say that the class C is covariant in the parameter T , or thatT is a covariant type parameter. You
can fun
think demo(strs:
of C as being Source<String>)
a producer of T ’s, {
and NOT a consumer of T ’s.
val objects: Source<Any> = strs // This is OK, since T is an out-parameter
The out //modifier
... is called a variance annotation, and since it is provided at the type parameter declaration site, we talk
about} declaration-site variance. This is in contrast with Java’s use-site variance where wildcards in the type usages
make the types covariant.
In addition to out, Kotlin provides a complementary variance annotation: in. It makes a type parameter contravariant: it can
only be consumed and never produced. A good example of a contravariant class is Comparable :
We abstract
believe that class
the words in and out are self-explaining
Comparable<in T> { (as they were successfully used in C# for quite some time already),
thus the
abstract fun compareTo(other: T): Int and one can rephrase it for a higher purpose:
mnemonic mentioned above is not really needed,
}
The Existential Transformation: Consumer in, Producer out! :-)
fun demo(x: Comparable<Number>) {
Type x.compareTo(1.0)
projections // 1.0 has type Double, which is a subtype of Number
// Thus, we can assign x to a variable of type Comparable<Double>
val y: Comparable<Double> = x // OK!
Use-site variance: Type projections
}
It is very convenient to declare a type parameter T as out and have no trouble with subtyping on the use site. Yes, it is, when
the class in question can actually be restricted to only return T ’s, but what if it can’t? A good example of this is Array:
53
class Array<T>(val size: Int) {
fun get(index: Int): T { /* ... */ }
fun set(index: Int, value: T) { /* ... */ }
}
This class cannot be either co- or contravariant in T . And this imposes certain inflexibilities. Consider the following function:
Thisfun
function is supposed
copy(from: to copy items from
Array<Any>, to: one array to another. Let’s try to apply it in practice:
Array<Any>)
{ assert(from.size == to.size)
Herevalfor
we run(iintointhefrom.indices)
same familiar
ints: Array<Int> = problem:
arrayOf(1, 2, 3)is invariant in T , thus neither
Array<T> and
to[i] = from[i]
val any = Array<Any>(3) of Array<Int>
}
copy(ints,
Array<Any> is aany) //ofError:
subtype the other.expects (Array<Any>,
Why? Again, because copyArray<Any>)
might be doing bad things, i.e. it might attempt to write,
say, a String to from , and if we actually passed an array Int there, a ClassCastException would have been
of thrown sometime later.
What has happened here is called type projection: we said that from is not simply an array, but a restricted ( projected)
one: we can only call those methods that return the type parameter T , in this case it means that we can only call get()
. This is our approach to use-site variance, and corresponds to Java’s Array<? extends Object> , but in a slightly
simpler way.
Sometimes you want to say that you know nothing about the type argument, but still want to use it in a safe way. The safe
way here is to define such a projection of the generic type, that every concrete instantiation of that generic type would be a
subtype of that projection.
54
— For Foo<out T> , where T is a covariant type parameter with the upper bound TUpper , Foo<*> is equivalent to
Foo<out TUpper> . It means that when theT is unknown you can safely read values of TUpper from Foo<*> .
— For Foo<in T> , where T is a contravariant type parameter, Foo<*> is equivalent to Foo<in Nothing> . It
means there is nothing you can write to Foo<*> in a safe way when T is unknown.
— For Foo<T> , where T is an invariant type parameter with the upper bound TUpper Foo<*>
, is equivalent to
Foo<out TUpper> for reading values and to Foo<in Nothing> for writing values.
If a generic type has several type parameters each of them can be projected independently. For example, if the type is
declared as interface Function<in T, out U> we can imagine the following star-projections:
Note: star-projections are very much like Java’s raw types, but safe.
Generic functions
Not only classes can have type parameters. Functions can, too. Type parameters are placed before the name of the function:
If type
funparameters are passed explicitly at T):
<T> singletonList(item: the call site, they{ are specified after the name of the function:
List<T>
// ...
}
val l = singletonList<Int>(1)
Generic constraints
fun <T> T.basicToString() : String { // extension function
The set//
of all
...possible types that can be substituted for a given type parameter may be restricted by generic constraints.
}
Upper bounds
The most common type of constraint is an upper bound that corresponds to Java’s extends keyword:
The fun
type <T
specified after a colon is thesort(list:
: Comparable<T>> upper bound:List<T>)
only a subtype
{ of Comparable<T> may be substituted for T . For
example
// ...
}
sort(listOf(1, 2, 3)) // OK. Int is a subtype of Comparable<Int>
sort(listOf(HashMap<Int, String>())) // Error: HashMap<Int, String> is not a subtype
of Comparable<HashMap<Int, String>>
55
The default upper bound (if none specified) is Any? . Only one upper bound can be specified inside the angle brackets. If
the same type parameter needs more than one upper bound, we need a separate where-clause:
56
Nested Classes
Classes can be nested in other classes
class Outer {
Inner classes
private val bar: Int = 1
A classclass
may beNested
marked as { inner to be able to access members of outer class. Inner classes carry a reference to an
object of an outer class: 2
fun foo() =
}
}
Seeclass
Qualified this {expressions to learn about disambiguation of this in inner classes.
Outer
valprivate
demo =val bar: Int = 1
Outer.Nested().foo() // == 2
inner class Inner {
fun foo() = bar
}
}
57
Enum Classes
The most basic usage of enum classes is implementing type-safe enums
Each enumclass
enum constant is an object. Enum constants are separated with commas.
Direction
{ NORTH, SOUTH, WEST,
EAST
Initialization
Since each enum is an instance of the enum class, they can be initialized
58
val name: String
val ordinal: Int
The enum constants also implement the Comparable interface, with the natural order being the order in which they are
defined in the enum class.
59
Object Expressions and Declarations
Sometimes we need to create an object of a slight modification of some class, without explicitly declaring a new subclass
for it. Java handles this case with anonymous inner classes. Kotlin slightly generalizes this concept with object expressions
and object declarations.
Object expressions
To create an object of an anonymous class that inherits from some type (or types), we write:
60
fun countClicks(window: JComponent) {
var clickCount = 0
var enterCount = 0
window.addMouseListener(object : MouseAdapter() {
override fun mouseClicked(e: MouseEvent)
{ clickCount++
}
Object declarations
Singleton is a very useful pattern, and Kotlin (after Scala) makes it easy to declare singletons:
Thisobject
is called DataProviderManager
an object declaration. If there’s
{ a name following the object keyword, we are not talking about an expression
anymore.
funWeregisterDataProvider(provider:
cannot assign such a thing to a variable, but we can refer {to it by its name. Such objects can have supertypes:
DataProvider)
// ...
NOTE: }objectDefaultListener
declarations can’t be :local (i.e. be nested directly inside a function), but they can be nested into other object
object MouseAdapter() {
declarations or non-inner classes.
override fun mouseClicked(e: MouseEvent) {
val allDataProviders: Collection<DataProvider>
// ...
get() = // ...
}
Companion Objects
}
An object declaration
override funinside a class can be marked
mouseEntered(e: with the companion
MouseEvent) { keyword:
// ...
}
}
61
class MyClass {
companion object Factory {
fun create(): MyClass = MyClass()
}
}
Members of the companion object can be called by using simply the class name as the qualifier:
The val
nameinstance
of the companion object can be omitted, in which case the name Companion will be used:
= MyClass.create()
Noteclass
that, even though the members of companion objects look like static members in other languages, at runtime those are
MyClass
still instance
{ companion of real objects, and can, for example, implement interfaces:
members
object {
} on the JVM you can have members of companion objects generated as real static methods and fields, if you use
However,
interface Factory<T> {
}
the @JvmStatic annotation. See the Java interoperability section for more details.
fun create(): T
}
Semantic difference between object expressions and declarations
There is oneMyClass
class important {semantic difference between object expressions and object declarations:
companion object : Factory<MyClass> {
— objectoverride
declarations
funarecreate():
initialized lazily, when accessed
MyClass for the first time
= MyClass()
} expressions are executed (and initialized) immediately, where they are used
— object
}
62
Delegation
Class Delegation
The Delegation pattern has proven to be a good alternative to implementation inheritance, and Kotlin supports it natively
requiring zero boilerplate code. A Derived can inherit from an interface Base and delegate all of its public methods
class to a specified object:
interface Base {
fun print()
}
fun main() {
val b = BaseImpl(10)
Derived(b).print() // prints 10
}
The by-clause in the supertype list for Derived indicates that b will be stored internally in objects of Derived
and the
compiler will generate all the methods of Base that forward to b .
63
Delegated Properties
There are certain common kinds of properties, that, though we can implement them manually every time we need them,
would be very nice to implement once and for all, and put into a library. Examples include
— lazy properties: the value gets computed only upon first access,
— observable properties: listeners get notified about changes to this property,
— storing properties in a map, not in separate field each.
The class
syntax is: val/var
Example { <property name>: <Type> by <expression> . The expression after by is the delegate,
because
varget() (and set()
p: String ) corresponding to the property will be delegated to its getValue() and setValue()
by Delegate()
methods.
} Property delegates don’t have to implement any interface, but they have to provide a getValue() function (and
setValue() — for var’s). For example:
When we read
class from
Delegate { delegates to an instance of Delegate ,
that function from Delegate is called,
operator fun p the
getValue(thisRef: Any?, property: KProperty<*>):
getValue() String {
so that itsreturn "$thisRef,
first parameter thank
is the object you pfor
we read delegating '${property.name}' to me!"
from and the second parameter holds a description of p itself (e.g. you
}
can take its name). For example:
Similarly, when we assign to p , setValue() function is called. The first two parameters are the same, and the third
the holds the value being assigned:
e.p = "NEW"
This prints
64
For a read-only property (i.e. a val), a delegate has to provide a function named getValue that takes the following
parameters:
— receiver — must be the same or a supertype of the property owner (for extension properties — the type being extended)
— metadata — must be of type KProperty<*> or its supertype,
this function must return the same type as property (or its subtype).
For a mutable property (a var), a delegate has to additionally provide a function named setValue
that takes the following
parameters:
getValue() and/or setValue() functions may be provided either as member functions of the delegate class or
extension functions. The latter is handy when you need to delegate property to an object which doesn’t originally provide
these functions. Both of the functions need to be marked with the operator keyword.
Standard Delegates
The Kotlin standard library provides factory methods for several useful kinds of delegates.
Lazy
lazy() is a function that takes a lambda and returns an instance of Lazy<T> which can serve as a delegate for
implementing a lazy property: the first call to get() executes the lambda passed to lazy() and remembers the result,
subsequent calls to get() simply return the remembered result.
65
import kotlin.properties.Delegates
class User {
var name: String by Delegates.observable("<no name>")
{ prop, old, new ->
println("$old -> $new")
}
}
fun main(args:
Array<String>) { val
user = User() user.name
= "first" user.name =
"second"
If you want to be able to intercept an assignment and “veto” it, use vetoable() instead of observable() . The handler
passed to the vetoable is called before the assignment of a new property value has been performed.
In this example,
class the constructor
User(val takes a map: Any?>) {
map: Map<String,
val name: String by map
Delegated val age: take
properties Int valuesby map
from this map (by the string keys –– names of properties):
val user = User(mapOf(
} "name" to "John Doe",
"age"
also forto
Thisprintln(user.name)
works 25 properties if you use a MutableMap instead of read-only Map :
var’s // Prints "John Doe"
))
println(user.age) // Prints 25
class MutableUser(val map: MutableMap<String, Any?>) {
var name: String by map
var age: Int by map
}
66
Functions and Lambdas
Functions
Function Declarations
Functions in Kotlin are declared using the fun keyword
Calling
valmember
resultfunctions uses the dot notation
= double(2)
InfixSample().foo()
notation // create instance of class Sample and calls foo
1 shl 2
// is the same
as 1.shl(2)
67
Function parameters are defined using Pascal notation, i.e. name: type. Parameters are separated using commas. Each
parameter must be explicitly typed.
funArguments
Default powerOf(number: Int, exponent: Int) {
...
}
Function parameters can have default values, which are used when a corresponding argument is omitted. This allows for a
reduced number of overloads compared to other languages.
Default
funvalues are defined
read(b: using the =off:
Array<Byte>, after type
Intalong
= 0,with the value.
len: Int = b.size()) {
...
} Arguments
Named
Function parameters can be named when calling functions. This is very convenient when a function has a high number of
parameters or default ones.
68
reformat(str, wordSeparator = '_')
Note that the named argument syntax cannot be used when calling Java functions, because Java bytecode does not always
preserve names of function parameters.
Unit-returning functions
If a function does not return any useful value, its return type is Unit Unit
is a type with only one value - Unit . This
. value does not have to be returned explicitly
The Unit return type declaration is also optional. The above code is equivalent to
fun printHello(name:
Single-Expression functions String?) {
...
} a function returns a single expression, the curly braces can be omitted and the body is specified after a = symbol
When
fun return
Explicit double(x:
types Int) = x * 2
Functions with block body must always specify return types explicitly, unless it’s intended for them to return Unit , in
which case it is optional. Kotlin does not infer return types for functions with block bodies because such functions may have
complex control flow in the body, and the return type will be non-obvious to the reader (and sometimes even for the
compiler)
A parameter of a function (normally the last one) may be marked with vararg
modifier:
69
allowing a variable number of arguments to be passed to the function:
Inside a function
val lista =vararg -parameter
asList(1, 2, 3) of T is visible as an array of T , i.e. ts variable in the example above has
type type Array<out T> . the
Only one parameter may be marked as vararg . If a parameter is not the last one in the list, values for the
vararg
following parameters can be passed using the named argument syntax, or, if the parameter has a function type, by passing a
lambda outside parentheses.
When we call a vararg -function, we can pass arguments one-by-one, e.g. asList(1, 2, 3) , or, if we already have
an array and want to pass its contents to the function, we use the spread operator (prefix the array with * ):
val a = arrayOf(1, 2, 3)
Function Scope
val list = asList(-1, 0, *a, 4)
In Kotlin functions can be declared at top level in a file, meaning you do not need to create a class to hold a function, like
languages such as Java, C# or Scala. In addition to top level functions, Kotlin functions can also be declared local, as
member functions and extension functions.
Local Functions
Local function
fun can access
dfs(graph: local variables
Graph) { of outer functions (i.e. the closure), so in the case above, the visited can be a local
variablefun dfs(current: Vertex, visited: Set<Vertex>) {
if (!visited.add(current)) return
for (v in current.neighbors)
fun Functions
Member dfs(graph: Graph) {
dfs(v, visited)
val visited = HashSet<Vertex>()
}
fun dfs(current: Vertex) {
if (!visited.add(current)) return
dfs(graph.vertices[0], HashSet())
for (v in current.neighbors)
}
dfs(v)
}
dfs(graph.vertices[0])
}
70
A member function is a function that is defined inside a class or object
Member functions
class are called
Sample() { with dot notation
fun foo() { print("Foo") }
For }
more information on //
Sample().foo() classes and overriding
creates instance members see Classes
of class Sampleand Inheritance
and calls foo
Generic Functions
Functions can have generic parameters which are specified using angle brackets before the function name
For fun
more <T>
information on generic functions T):
singletonList(item: see Generics
List<T> {
// ...
} Functions
Inline
Inline functions are explained here
Extension Functions
Extension functions are explained in their own section
Thistailrec
code calculates the fixpoint of cosine,Double
fun findFixPoint(x: which is =a mathematical
1.0): Double constant. It simply calls Math.cos repeatedly starting at
1.0 until the result
= if doesn’t
(x ==change any more, yielding
Math.cos(x)) x else a result of 0.7390851332151607. The resulting code is equivalent to
findFixPoint(Math.cos(x))
this more traditional style:
71
private fun findFixPoint(): Double {
var x = 1.0
while (true) {
val y =
Math.cos(x) if (x
== y) return y x =
y
}
To be eligible for the tailrec modifier, a function must call itself as the last operation it performs. You cannot use tail
recursion when there is more code after the recursive call, and you cannot use it within try/catch/finally blocks. Currently tail
recursion is only supported in the JVM backend.
72
Higher-Order Functions and Lambdas
Higher-Order Functions
A higher-order function is a function that takes functions as parameters, or returns a function. A good example of such a
function is lock() that takes a lock object and a function, acquires the lock, runs the function and releases the lock:
Let’sfun
examine
<T> the
lock(lock: body body:
code above:Lock, has a function
() -> type
T):: ()
T {-> T , so it’s supposed to be a function that takes no
parameters and returns
lock.lock() a value of type T . It is invoked inside the try-block, while protected by the lock , and its result is
returned { lock() function.
by the
try
return body()
If we want
} to call lock() , we can pass another function to it as an argument (see function references):
finally {
Another, lock.unlock
fun often more convenient way= issharedResource.operation()
toBeSynchronized() to pass a lambda expression:
()
}
val expressions
Lambda result = lock(lock,
described in::toBeSynchronized)
val result = arelock(lock, { more detail below, but for purposes of})
sharedResource.operation() continuing this section, let’s see a brief
overview:
In Kotlin, there is a convention that if the last parameter to a function is a function, that parameter can be specified outside
of the parentheses:
Another
lockexample
(lock)of a
{ higher-order function would be map() :
sharedResource.operation()
}
73
fun <T, R> List<T>.map(transform: (T) -> R): List<R> {
val result = arrayListOf<R>()
for (item in this)
result.add(transform(item))
return result
}
Noteval
that doubled
the parentheses in a call can
= ints.map { itbe ->
omitted
it *entirely
2 } if the lambda is the only argument to that call.
One other helpful convention is that if a function literal has only one parameter, its declaration may be omitted (along with the
-> ), and its name will be it :
These conventions
ints.map allow
{ it * to
2 write
} LINQ-style code:
fun compare(a:
Function Types String, b: String): Boolean = a.length() < b.length()
For a function to accept another function as a parameter, we have to specify a function type for that parameter. For example
the abovementioned function max is defined as follows:
74
The parameter is of type (T, T) -> Boolean , i.e. a function that takes two parameters of and returns a
less type T
Boolean : true if the first one is smaller than the second one.
In the body, line 4, less is used as a function: it is called by passing two arguments of type T .
A function type is written as above, or may have named parameters, if you want to document the meaning of each parameter
val Expression
Lambda compare: (x: T, y: T) -> Int = ...
Syntax
The full syntactic form of lambda expressions, i.e. literals of function types, is as follows:
A lambda expression
val sum = { x: is always
Int, y:surrounded
Int -> byx curly
+ y braces,
} parameter declarations in the full syntactic form go inside
parentheses and have optional type annotations, the body goes after an -> sign. If we leave all the optional annotations
out, what’s left looks like this:
It’s very common that a lambda expression has only one parameter. If Kotlin can figure the signature out itself, it allows us
not to declare the only parameter, and will implicitly declare it for us under the name it :
Noteints.filter
that if a function{ takes
it >another
0 } // function
this as the last parameter,
literal is of typethe lambda
'(it: expression
Int) -> argument
Boolean'can be passed
outside the parenthesized argument list. See the grammar for callSuffix.
Anonymous Functions
One thing missing from the lambda expression syntax presented above is the ability to specify the return type of the
function. In most cases, this is unnecessary because the return type can be inferred automatically. However, if you do need
to specify it explicitly, you can use an alternative syntax: an anonymous function.
An anonymous
fun(x: Int, function
y: looks
Int):very
Intmuch
= xlike
+ ayregular function declaration, except that its name is omitted. Its body can be
either an expression (as shown above) or a block:
The fun(x:
parameters
Int,andy:the Int):
return type
Intare{ specified in the same way as for regular functions, except that the parameter types
can bereturn
omitted ifxthey
+ ycan be inferred from context:
}
75
The return type inference for anonymous functions works just like for normal functions: the return type is inferred
automatically for anonymous functions with an expression body and has to be specified explicitly (or is assumed to be
Unit ) for anonymous functions with a block body.
Note that anonymous function parameters are always passed inside the parentheses. The shorthand syntax allowing to
leave the function outside the parentheses works only for lambda expressions.
One other difference between lambda expressions and anonymous functions is the behavior of non-local returns. A return
statement without a label always returns from the function declared with the fun keyword. This means that a return
inside a lambda expression will return from the enclosing function, whereas a return inside an anonymous function will
return from the anonymous function itself.
Closures
A lambda expression or anonymous function (as well as a local function and an object expression) can access its closure,
i.e. the variables declared in the outer scope. Unlike Java, the variables captured in the closure can be modified:
var sum
Function = 0with Receiver
Literals
ints.filter { it > 0 }.forEach
{ sum +=
Kotlin provides the it
ability to call a function literal with a specified receiver object. Inside the body of the function literal, you
can }call methods on that receiver object without any additional qualifiers. This is similar to extension functions, which allow
you print(sum)
to access members of the receiver object inside the body of the function. One of the most important examples of their
usage is Type-safe Groovy-style builders.
The sum
function literal can be called
: Int.(other: Int)as->
if it Int
were a method on the receiver object:
The 1.sum(2)
anonymous function syntax allows you to specify the receiver type of a function literal directly. This can be useful if you
need to declare a variable of a function type with receiver, and to use it later.
Lambda
val expressions
sum = funcan be used as function
Int.(other: Int):literals
Int =with receiver
this when the receiver type can be inferred from context.
+ other
76
class HTML {
fun body() { ... }
}
77
Inline Functions
Using higher-order functions imposes certain runtime penalties: each function is an object, and it captures a closure, i.e.
those variables that are accessed in the body of the function. Memory allocations (both for function objects and classes) and
virtual calls introduce runtime overhead.
But it appears that in many cases this kind of overhead can be eliminated by inlining the lambda expressions. The functions
shown above are good examples of this situation. I.e., the lock() function could be easily inlined at call-sites. Consider
the following case:
lock(l) { foo() }
Instead of creating a function object for the parameter and generating a call, the compiler could emit the following code
Isn’tl.lock()
it what we wanted from the very beginning?
try {
To make the compiler do this, we need to mark the lock() inline
foo() function with the modifier:
}
finally {
inline fun lock<T>(lock: Lock, body: () -> T): T {
l.unlock()
} // ...
}
The inline
modifier affects both the function itself and the lambdas passed to it: all of those will be inlined into the call
site.
Inlining may cause the generated code to grow, but if we do it in a reasonable way (do not inline big functions) it will pay off in
performance, especially at “megamorphic” call-sites inside loops.
noinline
In case you want only some of the lambdas passed to an inline function to be inlined, you can mark some of your function
parameters with the noinline modifier:
Inlinable lambdas
inline fun can only be called ()
foo(inlined: inside
-> the inline noinline
Unit, functions or notInlined:
passed as inlinable arguments,
() -> Unit) { noinline ones can
but be //
manipulated
... in any way we like: stored in fields, passed around etc.
Note} that if an inline function has no inlinable function parameters and no reified type parameters, the compiler will issue a
warning, since inlining such functions is very unlikely to be beneficial (you can suppress the warning if you are sure the
inlining is needed).
Non-local returns
78
In Kotlin, we can only use a normal, unqualified return to exit a named function or an anonymous function. This means
that to exit a lambda, we have to use a label, and a bare return is forbidden inside a lambda, because a lambda can not
make the enclosing function return:
But fun
if the foo()
function the lambda is passed to is inlined, the return can be inlined as well, so it is allowed:
{ ordinaryFuncti
Such on { (located in a lambda, but exiting the enclosing function) are called non-local returns. We are used to this sort of
returns
fun foo() {
constructs return // ERROR:
in loops, which inline can not
functions make
often `foo` return here
enclose:
inlineFunction {
}
return // OK: the lambda is inlined
Notefun }
that hasZeros(ints:
some inline functions may call the lambdas passed to them as parameters not directly from the function body, but
List<Int>): Boolean
from}another execution
{ ints.forEach { context, such as a local object or a nested function. In such cases, non-local control flow is also not
allowed inifthe(it
lambdas. To return
== 0) indicate that,
truethe//lambda parameter
returns fromneeds to be marked with thecrossinline modifier:
hasZeros
}
return false
inline
} fun f(crossinline body: () -> Unit) {
Reified type
val fparameters
= object: Runnable {
override fun run() = body()
Sometimes } we need to access a type passed to us as a parameter:
// ...
}
break and continue are not yet available in inlined lambdas, but we are planning to support them too
79
fun <T> TreeNode.findParentOfType(clazz: Class<T>): T? {
var p = parent
while (p != null && !clazz.isInstance(p))
{ p = p?.parent
}
@Suppress("UNCHECKED_CAST")
return p as T
}
Here, we walk up a tree and use reflection to check if a node has a certain type. It’s all fine, but the call site is not very pretty:
What we actually want is simply pass a type to this function, i.e. call it like this:
myTree.findParentOfType(MyTreeNodeType::class.java)
To enable this, inline functions support reified type parameters, so we can write something like this:
myTree.findParentOfType<MyTreeNodeType>()
We inline
qualified the
funtype parameter
<reified T>with the reified modifier, now it’s accessible
TreeNode.findParentOfType(): T? { inside the function, almost as if it were a
normal class.
var Since
p = the function is inlined, no reflection is needed, normal operators like !is and as are working now.
parent
Also, we can call it(pas!=
while mentioned
null &&above:
p !ismyTree.findParentOfType<MyTreeNodeType>()
T) .
{ p = p?.parent
Though reflection
} may not be needed in many cases, we can still use it with a reified type parameter:
return p as T
}
Normal functions
inline fun(not marked as
<reified T>inline) can not have
membersOf() = reified parameters. A type that does not have a run-time representation
T::class.members
(e.g. a non-reified type parameter or a fictitious type like Nothing ) can not be used as an argument for a reified type
parameter.
fun main(s: Array<String>) {
println(membersOf<StringBuilder>().joinToString("\n"))
For }
a low-level description, see the spec document.
80
Other
Destructuring Declarations
Sometimes it is convenient to destructure an object into a number of variables, for example:
Thisval
syntax is called
(name, a destructuring
age) = persondeclaration. A destructuring declaration creates multiple variables at once. We have
declared two new variables: name and age , and can use them independently:
A destructuring
println(name)declaration is compiled down to the following code:
println(age)
component1()
The val and component2() functions are another example of the principle of conventions widely used in
name = person.component1()
Kotlin (see operators like + and * , for-loops etc.). Anything can be on the right-hand side of a destructuring
val age = person.component2()
declaration, as long as the required number of component functions can be called on it. And, of course, there can be
component3()
and component4() and so on.
Variables
for ((a,
a andb)
b in
get collection) { ...
the values returned }
by component1() and component2() called on elements of the collection.
81
data class Result(val result: Int, val status: Status)
fun function(...): Result {
// computations
Since data classes automatically declare componentN() functions, destructuring declarations work here.
82
Collections
Unlike many languages, Kotlin distinguishes between mutable and immutable collections (lists, sets, maps, etc). Precise
control over exactly when collections can be edited is useful for eliminating bugs, and for designing good APIs.
It is important to understand up front the difference between a read only view of a mutable collection, and an actually
immutable collection. Both are easy to create, but the type system doesn’t express the difference, so keeping track of that (if
it’s relevant) is up to you.
The Kotlin List<out T> type is an interface that provides read only operations like size ,get and so on. Like in Java,
it inherits from Collection<T> and that in turn inherits from Iterable<T> . Methods that change the list are added
by the MutableList<T> interface. This pattern holds also for Set<out T>/MutableSet<T> and
Map<K, out
V>/MutableMap<K, V> .
We can see basic usage of the list and set types below:
Kotlin does not have dedicated syntax constructs for creating lists or sets. Use methods from the standard library, such as
listOf() , mutableListOf() , setOf() , mutableSetOf() . For creating maps in a not performance-critical code a
simple idiom may be used: mapOf(a to b, c to d)
Note that the readOnlyView variable points to the same list and changes as the underlying list changes. If the only
references that exist to a list are of the read only variety, we can consider the collection fully immutable. A simple way to
create such a collection is like this:
Note that the read only types are covariant. That means, you can take a List<Rectangle> and assign it to
List<Shape> assuming Rectangle inherits from Shape. This wouldn’t be allowed with the mutable collection types
because it would allow for failures at runtime.
Sometimes you want to return to the caller a snapshot of a collection at a particular point in time, one that’s guaranteed to no
change:
toListController
The class extension method
{ just duplicates the lists items, thus, the returned list is guaranteed to never change.
private val _items = mutableListOf<String>()
There are various useful extension methods on lists and sets that are worth being familiar with:
val items: List<String> get() = _items.toList()
}
83
val items = listOf(1, 2, 3, 4)
items.first == 1
items.last == 4
items.filter { it % 2 == 0 } // Returns [2,
4] rwList.requireNoNulls()
if (rwList.none { it > 6 }) println("No items above 6")
val item = rwList.firstOrNull()
… as well as all the utilities you would expect such as sort, zip, fold, reduce and so on.
Maps follow the same pattern. They can be easily instantiated and accessed like this:
84
Ranges
Range expressions are formed with rangeTo functions that have the operator form .. which is complemented by in and
!in. Range is defined for any comparable type, but for integral primitive types it has an optimized implementation. Here are
some examples of using ranges
Integral
if (itypein
ranges ( IntRange
1..10) , LongRangeof, CharRange
{ // equivalent 1 <= i && )ihave<= an extra feature: they can be iterated over. The
compiler takes care
10 println(i) of converting this analogously to Java’s indexed for-loop, without extra overhead.
}
What if you
for (iwant
in to iterateprint(i)
1..4) over numbers
// inprints
reverse "1234"
order? It’s simple. You can use downTo() function defined in the
the standard library
for (i in 4..1) print(i) // prints nothing
for (i in 4 downTo 1) print(i) // prints "4321"
Is it possible to iterate over numbers with arbitrary step, not equal to 1? Sure, the step() function will help you
ClosedRange<T> denotes a closed interval in the mathematical sense, defined for comparable types. It has two
endpoints: start and endInclusive , which are included in the range. The main operation is contains , usually
used in the form of in/!in operators.
A progression is a subtype of Iterable<N> , whereN is Int , Long or Char respectively, so it can be used in for-
loops and functions like map , filter , etc. Iteration over Progression is equivalent to an indexed for-loop in
Java/JavaScript:
85
For integral types, the .. operator creates an object which implements both ClosedRange<T> and *Progression .
For example, IntRange implements ClosedRange<Int> and extends IntProgression , thus all operations defined
for IntProgression are available for IntRange as well. The result of the downTo() and step() functions is
always a *Progression .
Progressions are constructed with the fromClosedRange function defined in their companion objects:
Utility functions
rangeTo()
class Int {
//...
operator fun rangeTo(other: Long): LongRange = LongRange(this, other)
//...
operator fun rangeTo(other: Int): IntRange = IntRange(this, other)
//...
}
Floating point numbers ( Double , Float ) do not define rangeTo operator, and the one provided by the standard
their library for generic Comparable types is used instead:
downTo()
The downTo() extension function is defined for any pair of integral types, here are two examples:
86
fun IntProgression.reversed(): IntProgression {
return IntProgression.fromClosedRange(last, first, -increment)
}
step()
step() extension functions are defined for *Progression classes, all of them return progressions with modified step
values (function parameter). The step value is required to be always positive, therefore this function never changes the
direction of iteration.
87
Type Checks and Casts
We can check whether an object conforms to a given type at runtime by using the
is operator or its negated form !is :
if (obj is String) {
print(obj.length)
}
Smart Casts
In many cases, one does not need to use explicit cast operators in Kotlin, because the compiler tracks the is -checks for
immutable values and inserts (safe) casts automatically when needed:
The fun
compiler is smart
demo(x: enough
Any) { to know a cast to be safe if a negative check leads to a return:
if (x is String) {
or in the print(x.length)of && //andx||is: automatically cast to String
ifright-hand
(x !is side
String) return
}
print(x.length) // x is automatically cast to String
}
Such smart
// xcasts work for when-expressions
is automatically cast toand while-loops
string on the as right-hand
well: side of `||`
if (x !is String || x.length == 0) return
Notewhen
that smart
(x) casts
{ do not work when the compiler cannot guarantee that the variable cannot change between the check
and the// x isMore
automatically
is Int -> print(x + smart
usage. specifically, cast to string on the right-hand side of `&&`
1) casts are applicable according to the following rules:
if (x is String && x.length > 0)
is String -> print(x.length + 1)
print(x.length) // x is automatically cast to String
is IntArray -> print(x.sum())
}
88
— val local variables - always;
— val properties - if the property is private or internal or the check is performed in the same module where the property
is declared. Smart casts aren’t applicable to open properties or properties that have custom getters;
— var local variables - if the variable is not modified between the check and the usage and is not captured in a
lambda that modifies it;
— var properties - never (because the variable can be modified at any time by other code).
Noteval
that x:
null cannot=bey cast
String as String as this type is not nullable, i.e. if is null, the code above throws an exception.
to String y
In order to match Java cast semantics we have to have nullable type at cast right hand side, like
Noteval
that x:
despite the fact= that
String? String side of as? is a non-null typeString the result of the cast is nullable.
the right-hand
y as?
89
This Expression
To denote the current receiver, we use this expressions:
— In an extension function or a function literal with receiver, this denotes the receiver parameter that is passed on
the left-hand side of a dot.
If this has no qualifiers, it refers to the innermost enclosing scope. To refer to this in other scopes, label qualifiers are
used:
Qualified this
To access this from an outer scope (a class, or extension function, or labeled function literal with receiver) we write
this@label where @label is a label on the scope this is meant to be from:
90
Equality
In Kotlin there are two types of equality:
Referential equality
Referential equality is checked by the
=== operation (and its negated counterpart !== a === b evaluates to true if
a b ).
and only if and point to the same object.
Structural equality
Structural equality is checked by the
== operation (and its negated counterpart != ). By convention, an expression like a
== b is translated to
I.e. if a is not null , it calls equals(Any?) function, otherwise (i.e. a is null ) it checks that b is referentially
the equal to null .
91
Operator overloading
Kotlin allows us to provide implementations for a predefined set of operators on our types. These operators have fixed
symbolic representation (like + or * ) and fixed precedence. To implement an operator, we provide a member function or an
extension function with a fixed name, for the corresponding type, i.e. left-hand side type for binary operations and argument
type for unary ones. Functions that overload operators need to be marked with the operator modifier.
Conventions
Here we describe the conventions that regulate operator overloading for different operators.
Unary operations
ExpressionTranslated to
+a a.unaryPlus()
-a a.unaryMinus()
!a a.not()
This table says that when the compiler processes, for example, an expression +a , it performs the following steps:
Note that these operations, as well as all the others, are optimized for Basic types and do not introduce overhead of function
calls for them.
ExpressionTranslated to
a++ a.inc() + see below
a-- a.dec() + see below
These operations are supposed to change their receiver and (optionally) return a value.
The compiler performs the following steps for resolution of an operator in the postfix form, e.g. a++ :
Binary operations
ExpressionTranslated to
a + b a.plus(b)
a - b a.minus(b)
a * b a.times(b)
a / b a.div(b)
a % b a.mod(b)
a..b a.rangeTo(b)
For the operations in this table, the compiler just resolves the expression in the Translated to column.
ExpressionTranslated to
a in b b.contains(a)
a !in b !b.contains(a)
For in
and !in the procedure is the same, but the order of arguments is reversed.
SymbolTranslated to
a[i] a.get(i)
a[i, j] a.get(i, j)
a[i_1, ..., i_n] a.get(i_1, ...,
i_n) a[i] = b a.set(i, b)
a[i, j] = b a.set(i, j, b)
SymbolTranslated to
a() a.invoke()
a(i) a.invoke(i)
a(i, j) a.invoke(i, j)
a(i_1, ...,
i_n) a.invoke(i_1, ...
, i_n)
ExpressionTranslated to
a += b a.plusAssign(b)
a -= b a.minusAssign(b)
93
a *= b a.timesAssign(b)
94
aEx/p=resbsionaTr.adnisvlaAtsesditgon(b)
a %= b a.modAssign(b)
For the assignment operations, e.g. a += b , the compiler performs the following steps:
ExpressionTranslated to
a == b a?.equals(b) ?: b === null
a != b !(a?.equals(b) ?: b ===
null)
Note: ===
and !== (identity checks) are not overloadable, so no conventions exist for them
The == operation is special: it is translated to a complex expression that screens for null ’s, andnull == null is
true .
SymbolTranslated to
All comparisons are translated into calls to compareTo , that is required to return Int .
95
Null Safety
One of the most common pitfalls in many programming languages, including Java is that of accessing a member of a null
references, resulting in null reference exceptions. In Java this would be the equivalent of aNullPointerException or
NPE for short.
Kotlin’s type system is aimed to eliminate NullPointerException ’s from our code. The only possible causes of NPE’s
may be
— An explicit call
to throw NullPointerException()
In Kotlin, the type system distinguishes between references that can hold null (nullable references) and those that can not
(non-null references). For example, a regular variable of type String can not hold null:
To allow
var nulls, we can declare
a: String = "abc" a variable as nullable string, written String? :
a = null // compilation error
Now,varif you
b:call a method= or access a property on a , it’s guaranteed not to cause an NPE, so you can safely say
String?
"abc" b = null // ok
But val
if youlwant to access the same property on b , that would not be safe, and the compiler reports an error:
= a.length
But val
we still
l need to access //
= b.length that error:
property,variable
right? There'b'
are acan
few be
ways of doing that.
null
First, you can explicitly check if b is null, and handle the two options separately:
The val
compiler
l = tracks
if (bthe!=
information about the check
null) b.length elseyou
-1performed, and allows the call to length inside the if. More
complex conditions are supported as well:
96
if (b != null && b.length > 0)
print("String of length $
{b.length}")
else
Note that this only works where b is immutable (i.e. a local variable which is not modified between the check and the usage
or a member val which has a backing field and is not overridable), because otherwise it might happen b changes to
that
null after the check.
Safe Calls
Your second option is the safe call operator, written ?. :
returns b.length if b is not null, and null otherwise. The type of this expression is Int? .
Thisb?.length
Safe calls are useful in chains. For example, if Bob, an Employee, may be assigned to a Department (or not), that in turn
may have another Employee as a department head, then to obtain the name of Bob’s department head, if any), we write
the following:
Elvis Operator
When we have a nullable reference r , we can say
r is not null, use it, otherwise use some non-null value x ”:
“if
Along with the complete if-expression, this can be expressed with the Elvis operator, written ?: :
If theval
expression ?: -1is not null, the elvis operator returns it, otherwise it returns the expression to the right. Note
to the left of?:
l = b?.length
that the right-hand side expression is evaluated only if the left-hand side is null.
Note that, since throw and return are expressions in Kotlin, they can also be used on the right hand side of the elvis
operator. This can be very handy, for example, for checking function arguments:
97
val l = b!!.length()
Thus, if you want an NPE, you can have it, but you have to ask for it explicitly, and it does not appear out of the blue.
Safe Casts
Regular casts may result into a ClassCastException
if the object is not of the target type. Another option is to use safe
casts that return null if the attempt was not
successful:
98
Exceptions
Exception Classes
All exception classes in Kotlin are descendants of the class Throwable . Every exception has a message, stack trace
and an optional cause.
To catch
throwan MyException("Hi
exception, use the try-expression
There!")
There
trymay{ be zero or more catch blocks. finally blocks may be omitted. However at least one catch or finally
block should
// somebe present.
code
}
Try catch (e: SomeException) {
is an expression
// handler
try} is an expression, i.e. it may have a return value.
finally {
// optional finally block
The val
returned value of
a: Int? = atry
try-expression is either the last
{ parseInt(input) expression
} catch (e: inNumberFormatException)
the try block or the last expression
{ nullin}the catch
}
block (or blocks). Contents of the finally block do not affect the result of the expression.
Checked Exceptions
Kotlin does not have checked exceptions. There are many reasons for this, but we will provide a simple example.
99
try {
log.append(message)
}
catch (IOException e) {
// Must be safe
}
And this is no good, see Effective Java, Item 65: Don’t ignore exceptions.
Examination of small programs leads to the conclusion that requiring exception specifications could both enhance
developer productivity and enhance code quality, but experience with large software projects suggests a different
result
Java Interoperability
Please see the section on exceptions in the Java Interoperability section for information about Java interoperability.
100
Annotations
Annotation Declaration
Annotations are means of attaching metadata to code. To declare an annotation, put the annotation modifier in front of a
class:
Additional attributesclass
annotation of the annotation
Fancy can be specified by annotating the annotation class with meta-annotations:
— @Target specifies the possible kinds of elements which can be annotated with the annotation (classes,
functions, properties, expressions etc.);
— @Retention specifies whether the annotation is stored in the compiled class files and whether it’s visible
through reflection at runtime (by default, both are true);
— @Repeatable allows using the same annotation on a single element multiple times;
— @MustBeDocumented specifies that the annotation is part of the public API and should be included in the class
or method signature shown in the generated API documentation.
Usage@Target(AnnotationTarget.CLASS, AnnotationTarget.FUNCTION,
AnnotationTarget.VALUE_PARAMETER, AnnotationTarget.EXPRESSION)
@Retention(AnnotationRetention.SOURCE)
If you need toclass
@Fancy annotate
@MustBeDocumented the {primary constructor of a class, you need to add the constructor keyword to the constructor
Foo
declaration,
public and
@Fancy add the
annotation
fun annotations beforeInt):
class Fancy
baz(@Fancy foo: it: Int {
return (@Fancy 1)
Youclass} also annotate property accessors:
can Foo @Inject constructor(dependency: MyDependency) {
}
// ...
}
class Foo {
Constructors
var x: MyDependency? = null
Annotations may @Inject set
have constructors that take parameters.
}
101
annotation class Special(val why: String)
If an annotation is used as a parameter of another annotation, its name is not prefixed with the @ character:
public can
Annotations annotation
also be used class Deprecated(
on lambdas. They will be applied to the invoke()
method into which the body of the lambda
val message: String,
is generated. This is useful for frameworks like Quasar, which uses annotations for concurrency control.
val replaceWith: ReplaceWith = ReplaceWith(""))
The class
same syntax can be used to annotate
Example(@field:Ann val the entire file.
foo, // To do this, put
annotate an annotation with the
Java file at the top level o
target a file, before the field
package@get:Ann
directive orval
before all imports
bar, if the file isJava
// annotate in the default package:
getter
@file:JvmName("Foo")
package org.jetbrains.demo
102
If you have multiple annotations with the same target, you can avoid repeating the target by adding brackets after the target
and putting all the annotations inside the brackets:
The class
full list of supported{ use-site targets is:
Example
@set:[Inject VisibleForTesting]
— file
public var collaborator: Collaborator
— }property (annotations with this target are not visible to Java)
— field
— get (property getter)
— set (property setter)
— receiver (receiver parameter of an extension function or property)
To annotate the receiver parameter of an extension function, use the following syntax:
If you don’t
fun specify a use-site target,
@receiver:Fancy the target is chosen according
String.myExtension() { } to the @Target annotation of the annotation being
used. If there are multiple applicable targets, the first applicable target from the following list is used:
— param
— property
— field
Java Annotations
Java annotations are 100% compatible with Kotlin:
class Tests {
@Test fun simple() {
assertEquals(42, getTheAnswer())
}
}
103
// Java
public @interface Ann {
int intValue();
String
stringValue();
Just// in Java, a special case is the value parameter; its value can be specified without an explicit name.
likeKotlin
@Ann(intValue = 1, stringValue = "abc") class C
If the//value
Java
argument in Java has an array type, it becomes a parameter in Kotlin:
public @interface AnnWithValue
{ String value();
}
// Java
public @interface AnnWithArrayValue {
String[] value();
//
} Kotlin
@AnnWithValue("abc") class
C
If you//need to specify a class as an argument of an annotation, use a Kotlin class ( KClass). The Kotlin compiler will
Kotlin
automatically convert it to a Java class,"foo",
@AnnWithArrayValue("abc", so that the Java code
"bar") will C
class be able to see the annotations and arguments normally.
Values of an annotation
import instance are exposed as properties to Kotlin
kotlin.reflect.KClass varargcode.
// Kotlin
fun foo(ann: Ann) {
val i = ann.value
}
104
Reflection
Reflection is a set of language and library features that allows for introspecting the structure of your own program at runtime.
Kotlin makes functions and properties first-class citizens in the language, and introspecting them (i.e. learning a name or a
type of a property or function at runtime) is closely intertwined with simply using a functional or reactive style.
On the Java platform, the runtime component required for using the reflection features is distributed as a separate JAR file (kotlin-ref
Class References
The most basic reflection feature is getting the runtime reference to a Kotlin class. To obtain the reference to a statically
known Kotlin class, you can use the class literal syntax:
The val
reference
c = is a value of type KClass.
MyClass::class
Note that a Kotlin class reference is not the same as a Java class reference. To obtain a Java class reference, use the
.java property on a KClass instance.
Function References
When we have a named function declared like this:
We fun
can easily call it directly
isOdd(x: Int) (= isOdd(5)
x % 2 != ),0but we can also pass it as a value, e.g. to another function. To do this, we use the
:: operator:
::isOdd
Hereval numbers is a=value of function2,
listOf(1, type
3) (Int) -> Boolean .
println(numbers.filter(::isOdd)) // prints [1, 3]
Note that right now the :: operator cannot be used for overloaded functions. In the future, we plan to provide a syntax for
specifying parameter types so that a specific overload of a function could be selected.
If we need to use a member of a class, or an extension function, it needs to be qualified. e.g. String::toCharArray
gives us an extension function for type String : String.() -> CharArray .
fun <A, B, C> compose(f: (B) -> C, g: (A) -> B): (A) -> C {
return { x -> f(g(x)) }
}
105
It returns a composition of two functions passed to it: compose(f, g) = f(g(*)) . Now, you can apply it to callable
references:
The expression ::x evaluates to a property object of type KProperty<Int> , which allows us to read its value using
get() or retrieve the property name using name property. For more information, please refer to the docs on the
the
KProperty class.
returns a value of type KMutableProperty<Int>, which has a set()
For a mutable property, e.g. var y = 1 ::y
,
method.
To access a property
val strs that is a member
= listOf("a", of a "def")
"bc", class, we qualify it:
println(strs.map(String::length)) // prints [1, 2,
For 3]
an extension
class A(valproperty:
p: Int)
106
On the Java platform, standard library contains extensions for reflection classes that provide a mapping to and from Java
reflection objects (see package kotlin.reflect.jvm ). For example, to find a backing field or a Java method that
serves as a getter for a Kotlin property, you can say something like this:
Using ::Foo
class Foo, the zero-argument constructor of the class Foo, we can simply call it like this:
107
Type-Safe Builders
The concept of builders is rather popular in the Groovy community. Builders allow for defining data in a semi-declarative
way. Builders are good for generating XML, laying out UI components, describing 3D scenes and more…
For many use cases, Kotlin allows to type-check builders, which makes them even more attractive than the dynamically-
typed implementation made in Groovy itself.
For the rest of the cases, Kotlin supports Dynamic types builders.
Thisimport
is completely legitimate Kotlin code.
com.example.html.* //You
seecandeclarations
play with this code online (modify it and run in the browser) here.
below
fun
How result(args: Array<String>) =
it works
html {
Let’s walkhead
through{ the mechanisms of implementing type-safe builders in Kotlin. First of all we need to define the model we
want to build,
title
in this {+"XML
case we need
encoding
to model
with
HTML tags. It is easily done with a bunch of classes. For example, HTML is a
Kotlin"}
class that}describes the <html> tag, i.e. it defines children like <head> and <body> . (See its declaration below.)
body {
h1 {+"XML
Now, let’s recall why we canencoding with like
say something Kotlin"}
this in the code:
p {+"this format can be used as an alternative markup to XML"}
// mixed
content p {
+"This is
some" b
{+"mixed"}
+"text. For more see the"
a(href = "http://kotlinlang.org") {+"Kotlin"}
+"project"
}
p {+"some text"}
// content generated
by p {
for (arg in args)
+arg
}
}
108
html {
// ...
}
html is actually a function call that takes a lambda expression as an argument This function is defined as follows:
Thisfun
function takes one parameter
html(init: HTML.() named
-> Unit):init HTML
, which
{ is itself a function. The type of the function is HTML.() -> Unit ,
which is
vala function
html = type with receiver. This means that we need to pass an instance of type HTML (a receiver) to the
function, and we can call members of that instance inside the function. The receiver can be accessed through the this
HTML()
html.init()
keyword:
return html
Actually
fun these two functions
head(init: do just->
Head.() the Unit)
same thing, so we{ can have a generic version, initTag :
: Head
val head =
Head()
head.init()
children.add(hea
d) return head
}
109
protected fun <T : Element> initTag(tag: T, init: T.() -> Unit): T
{ tag.init()
children.add(tag)
return tag
}
Andfun
we can use them to Head.()
head(init: build <head>
-> Unit) = initTag(Head(), init)
and <body> tags.
Onefun
otherbody(init:
thing to be discussed
Body.()here
->isUnit)
how we=add text to tag bodies. In
initTag(Body(), the example above we say something like
init)
html { we just put a string inside a tag body, but there is this little + in front of it, so it is a function call that invokes a
So basically,
prefix unaryPlus()
head { operation. That operation is actually defined by an extension function unaryPlus() that is a
member of the TagWithText
title abstractwith
{+"XML encoding class Kotlin"}
(a parent of Title ):
}
// ...
fun String.unaryPlus() {
}
children.add(TextElement(this))
}
All this is defined in a package com.example.html that is imported at the top of the builder example above. In the next
section you can read through the full definition of this package.
This is how the package com.example.html is defined (only the elements used in the example above). It builds an HTML
tree. It makes heavy use of extension functions and lambdas with receiver.
package com.example.html
interface Element {
fun render(builder: StringBuilder, indent: String)
}
110
abstract class Tag(val name: String) : Element {
val children = arrayListOf<Element>()
val attributes = hashMapOf<String, String>()
111
val a = initTag(A(),
init) a.href = href
}
}
112
Dynamic Type
Being a statically typed language, Kotlin still has to interoperate with untyped or loosely typed environments, such as the
JavaScript ecosystem. To facilitate these use cases, the dynamic type is available in the language:
dynamic
The val dyn: type basically
dynamic turns off Kotlin’s type checker:
= ...
— a value of this type can be assigned to any variable or passed anywhere as a parameter,
— any value can be assigned to a variable of type dynamic dynamic
or passed to a function that takes as a parameter
— null -checks are disabled for such values.
On the JavaScript platform this code will be compiled “as is”: dyn.whatever(1)
in Kotlin becomes dyn.whatever(1)
in the generated JavaScript code.
A dynamic call always returns as a result, so we can chain such calls freely:
dynamic
When we pass a lambda to a dynamic call, all of its parameters by default have the type dynamic :
dyn.foo().bar.baz()
For dyn.foo
a more technical
{ description, see the spec document.
x -> x.bar() // x is dynamic
}
113
Reference
114
115
Grammar
We are working on revamping the Grammar definitions and give it some style! Until then, please check the Grammar from
the old site
116
Interop
Calling Java code from Kotlin
Kotlin is designed with Java Interoperability in mind. Existing Java code can be called from Kotlin in a natural way, and Kotlin
code can be used from Java rather smoothly as well. In this section we describe some details about calling Java code from
Kotlin.
Pretty much all Java code can be used without any issues
import java.util.*
Getters and Setters
fun demo(source:
Methods List<Int>)
that follow the Java { for getters and setters (no-argument methods with names starting
conventions
get and
val list = ArrayList<Int>()
with single-argument methods with names starting with set ) are represented as properties in Kotlin. For
// 'for'-loops work for Java collections:
example:
for (item in source)
list.add(item)
import java.util.Calendar
// Operator conventions work as well:
for (i in 0..source.size() - 1)
fun calendarDemo()
list[i] = source[i] { // get and set are called
} val calendar = Calendar.getInstance()
if (calendar.firstDayOfWeek == Calendar.SUNDAY) { // call
getFirstDayOfWeek() calendar.firstDayOfWeek = Calendar.MONDAY // call
setFirstDayOfWeek()
}
Note that, if the Java class only has a setter, it will not be visible as a property in Kotlin, because Kotlin does not support set-
only properties at this time.
117
Some of the Kotlin keywords are valid identifiers in Java: in, object, is, etc. If a Java library uses a Kotlin keyword for a
method, you can still call the method escaping it with the backtick (`) character
foo.`is`(bar)
Null-Safety and Platform Types
Any reference in Java may be null, which makes Kotlin’s requirements of strict null-safety impractical for objects
coming from Java. Types of Java declarations are treated specially in Kotlin and called platform types. Null-checks are
relaxed for such types, so that safety guarantees for them are the same as in Java (see more below).
Whenvalwelist
call methods on variables of platform//
= ArrayList<String>() types, Kotlin does
non-null not issue nullability
(constructor result)errors at compile time, but the call
maylist.add("Item")
fail at runtime, because of a null-pointer exception or an assertion that Kotlin generates to prevent nulls from
propagating:
val size = list.size() // non-null (primitive int)
val item = list[0] // platform type inferred (ordinary Java object)
Platform types are non-denotable,
item.substring(1) meaning that
// allowed, mayone can not
throw anwrite them down
exception ifexplicitly
item == in the language. When a platform
null
value is assigned to a Kotlin variable, we can rely on type inference (the variable will have an inferred platform type then,
as
item has in the example above), or we can choose the type that we expect (both nullable and non-null types are allowed):
If weval
choose a non-nullString?
nullable: type, the compiler
= item will
// emit an assertion
allowed, upon works
always assignment. This prevents Kotlin’s non-null variables
fromval
holding nulls. Assertions are also emitted when
notNull: String = item // allowed, may fail atwe pass platform values to Kotlin functions expecting non-null values
runtime
etc. Overall, the compiler does its best to prevent nulls from propagating far through the program (although sometimes this
is impossible to eliminate entirely, because of generics).
As mentioned above, platform types cannot be mentioned explicitly in the program, so there’s no syntax for them in the
language. Nevertheless, the compiler and IDE need to display them sometimes (in error messages, parameter info etc), so
we have a mnemonic notation for them:
— means “ T or T?
T! ”,
— (Mutable)Collection<T>! means “Java collection of T may be mutable or not, may be nullable or not”,
— T
Array<(out) T>! means “Java array of (or a subtype of T ), nullable or not”
Nullability annotations
Java types which have nullability annotations are represented not as platform types, but as actual nullable or non-null Kotlin
types. Currently, the compiler supports the JetBrains flavor of the nullability annotations ( @Nullable and @NotNull from
the org.jetbrains.annotations package).
118
Mapped types
Kotlin treats some Java types specially. Such types are not loaded from Java “as is”, but are mapped to corresponding Kotlin
types. The mapping only matters at compile time, the runtime representation remains unchanged. Java’s primitive types are
mapped to corresponding Kotlin types (keeping platform types in mind):
float kotlin.Float
doublekotlin.Double
boolean kotlin.Boolean
java.lang.Deprecated kotlin.Deprecated!
java.lang.Voidkotlin.Nothing!
java.lang.CharSequence kotlin.CharSequence!
java.lang.Stringkotlin.String!
java.lang.Number kotlin.Number!
java.lang.Throwablekotlin.Throwable!
Collection types may be read-only or mutable in Kotlin, so Java’s collections are mapped as follows (all Kotlin types in this
table reside in the package kotlin ):
Java type Kotlin read-only Kotlin mutable type Loaded platform type
type
Iterator<T> Iterator<T> MutableIterator<T> (Mutable)Iterator<T>!
Iterable<T> Iterable<T> MutableIterable<T> (Mutable)Iterable<T>!
Collection<T> Collection<T> MutableCollection<T> (Mutable)Collection<T>!
Set<T> Set<T> MutableSet<T> (Mutable)Set<T>!
List<T> List<T> MutableList<T> (Mutable)List<T>!
ListIterator<T> ListIterator<T> MutableListIterator<T> (Mutable)ListIterator<T>!
Map<K, V> Map<K, V> MutableMap<K, V> (Mutable)Map<K, V>!
Map.Entry<K, V> Map.Entry<K, V> MutableMap.MutableEntry<K,V> (Mutable)Map.
(Mutable)Entry<K,
V>!
119
Java typeKotlin type
int[] kotlin.IntArray!
String[] kotlin.Array<(out)
String>!
Like Java’s, Kotlin’s generics are not retained at runtime, i.e. objects do not carry information about actual type arguments
passed to their constructors, i.e. ArrayList<Integer>() is indistinguishable from ArrayList<Character>() . This
makes it impossible to perform is-checks that take generics into account. Kotlin only allows is-checks for star-projected
generic types:
String>! ).
Arrays are used with primitive datatypes on the Java platform to avoid the cost of boxing/unboxing operations. As Kotlin hides
those implementation details, a workaround is required to interface with Java code. There are specialized classes for every
type of primitive array ( IntArray , DoubleArray , CharArray , and so on) to handle this case. They are not related to
the Array class and are compiled down to Java’s primitive arrays for maximum performance.
To pass an array
public of primitive
class values you can {
JavaArrayExample do the following in Kotlin:
120
When compiling to JVM byte codes, the compiler optimizes access to arrays so that there’s no overhead introduced:
Even when
val we navigate
array with an index,
= arrayOf(1, 2, it3,
does
4) not introduce any overhead
array[x] = array[x] * 2 // no actual calls to get() and set() generated
forin-checks
Finally, (x in array)
have no // no iterator
overhead either
for (i in array.indices) // no iterator
created print(x)
created array[i] += 2
if (i in array.indices) { // same as (i >= 0 && i < array.size)
Java Varargs
print(array[i])
Java} classes sometimes use a method declaration for the indices with a variable number of arguments (varargs).
public
It’s currently void removeIndices(int...
not possible indices)
to pass null to a method that { as varargs.
is declared
val javaObj = JavaArray()
// code here...
val array = intArrayOf(0, 1, 2,
}
3)
Operators
}
javaObj.removeIndicesVarArg(*array
Since Java has no way of marking methods for which it makes sense to use the operator syntax, Kotlin allows using any Jav
methods with the right name and signature as operator overloads and other conventions ( invoke() etc.) Calling Java
methods using the infix call syntax is not allowed.
Checked Exceptions
In Kotlin, all exceptions are unchecked, meaning that the compiler does not force you to catch any of them. So, when you
cal a Java method that declares a checked exception, Kotlin does not force you to do anything:
121
fun render(list: List<*>, to: Appendable) {
for (item in list)
to.append(item.toString()) // Java would require us to catch IOException here
}
Object Methods
When Java types are imported into Kotlin, all the references of the type java.lang.Object are turned into Any .
Any Since is not platform-specific, it only declares toString() , hashCode() and equals() as its members, so to
make
other members of java.lang.Object available, Kotlin uses extension functions.
wait()/notify()
(foo as java.lang.Object).wait()
getClass()
To retrieve the type information from an object, we use the javaClass extension property.
Do not forgetExample
class about Effective Java, Item{11: Override clone judiciously.
: Cloneable
override fun clone(): Any { ... }
}
finalize()
To override finalize() , all you need to do is simply declare it, without using the override keyword:
According
class toC Java’s
{ rules, finalize() must not be private.
protected fun finalize() {
// finalization logic
}
}
122
Inheritance from Java classes
At most one Java class (and as many Java interfaces as you like) can be a supertype for a class in Kotlin.
if (Character.isLetter(a)) {
Java Reflection
// ...
Java} reflection works on Kotlin classes and vice versa. As mentioned above, you can use instance.javaClass or
ClassName::class.java to enter Java reflection through java.lang.Class .
Other supported cases include acquiring a Java getter/setter method or a backing field for a Kotlin property, a KProperty
for a Java field, a Java method or constructor for a KFunction and vice versa.
SAM Conversions
Just like Java 8, Kotlin supports SAM conversions. This means that Kotlin function literals can be automatically converted
int implementations of Java interfaces with a single non-default method, as long as the parameter types of the interface
method match the parameter types of the Kotlin function.
…and
valin method calls:= Runnable { println("This runs in a runnable") }
runnable
If theval
Javaexecutor
class has multiple methods taking functional interfaces, you can choose the one you need to call by using an
= ThreadPoolExecutor()
adapter function that converts
// Java signature: void a lambda to a specific SAM type.
execute(Runnable Those adapter functions are also generated by the compiler
command)
when needed.
executor.execute { println("This runs in a thread pool") }
Noteexecutor.execute(Runnable
that SAM conversions only work for
{ interfaces, not for abstract
println("This runs in classes, even if pool")
a thread those also
})have just a single abstract
method.
Also note that this feature works only for Java interop; since Kotlin has proper function types, automatic conversion of
functions into implementations of Kotlin interfaces is unnecessary and therefore unsupported.
123
external fun foo(x: Int): Double
The rest of the procedure works in exactly the same way as in Java.
124
Calling Kotlin from Java
Kotlin code can be called from Java easily.
Properties
Property getters are turned into get-methods, and setters – into set-methods.
Package-Level Functions
All the functions and properties declared in a file
example.kt inside a package org.foo.bar are put into a Java class
named org.foo.bar.ExampleKt .
// example.kt
package demo
class Foo
fun bar() {
}
The //
name of the generated Java class can be changed using the @JvmName annotation:
Java
new demo.Foo();
demo.ExampleKt.bar();
@file:JvmName("DemoUtils")
Having multiple files which have the same generated Java class name (the same package and the same name or the same
@JvmName annotation) is normally an error. However, the compiler has the ability to generate a single Java facade class
package
which has the specified name and contains all the declarations from all the files which have that name. To enable the
generation of such a facade, use the @JvmMultifileClass annotation in all of the files.
demo class
Foo fun
bar() {
// Java
new demo.Foo();
demo.DemoUtils.bar();
125
// oldutils.kt
@file:JvmName("Utils")
@file:JvmMultifileClass
package demo
fun foo() {
}
// newutils.kt
Instance Fields
@file:JvmName("Utils")
@file:JvmMultifileClass
If you need to expose a Kotlin property as a field in Java, you need to annotate it with the @JvmField annotation. The field
will have the same
package demovisibility as the underlying property. You can annotate a property with @JvmField if it has a backing
field, is not private, does not have open ,override or const modifiers, and is not a delegated property.
fun bar() {
}
class C(id:
Late-Initialized String)
properties are also exposed as fields. The visibility of the field will be the same as the visibility oflateinit
{ @JvmField val ID =
property setter.
id
// Java
demo.Utils.foo(
Static
); Fields
// Java
demo.Utils.bar(
Kotlin properties declared in a named object or a companion object will have static backing fields either in that named
class JavaClient {
object or in the class
public containing
String the companion
getID(C c) { object.
return c.ID;
Usually these fields are private but they can be exposed in one of the following ways:
}
— }@JvmField annotation;
— lateinit modifier;
126
— const modifier.
Annotating such a property with @JvmField makes it a static field with the same visibility as the property itself.
class Key(val
A late-initialized value:
property Int)or a companion object has a static backing field with the same visibility as the property
in an object
setter. { companion object {
@JvmField
val COMPARATOR: Comparator<Key> = compareBy<Key> { it.value }
object} Singleton {
Properties annotated with const (in classes as well as at the top level) are turned into static fields in Java:
} lateinit var provider: Provider
}
In Java:
// file example.kt
// Java
Key.COMPARATOR.compare(key1,
object
// Obj {
intJava
c = Obj.CONST;
Static Methods
key2);
const val CONST ==1new Provider();
Singleton.provider
int d = ExampleKt.MAX;
}
// public static non-final field in Singleton class
int v = above,
As mentioned C.VERSION;
Kotlin generates static methods for package-level functions. Kotlin can also generate static methods
for functions defined in named objects or companion objects if you annotate those functions as @JvmStatic . For
class C {
example: companion object {
const val VERSION = 9
}
}
127
class C {
companion object {
@JvmStatic fun foo()
{} fun bar() {}
}
}
Now, foo()
is static in Java, while bar() is not:
In Java:
object Obj {
@JvmStatic fun foo() {}
fun bar()
@JvmStatic {} can also be applied on a property of an object or a companion object making its getter and setter
annotation
Obj.foo(); // works fine
}
methods be static members
Obj.bar(); // errorin that object or the class containing the companion object.
Obj.INSTANCE.bar(); // works, a call through the singleton instance
Obj.INSTANCE.foo(); // works too
Handling signature clashes with @JvmName
Sometimes we have a named function in Kotlin, for which we need a different JVM name the byte code. The most prominent
example happens due to type erasure:
These
funtwoList<String>.filterValid():
functions can not be defined side-by-side, because their JVM signatures are the same:
List<String>
filterValid(Ljava/util/List;)Ljava/util/List;
fun List<Int>.filterValid(): List<Int> . If we really want them to have the same name in Kotlin, we
can annotate one (or both) of them with @JvmName and specify a different name as an argument:
From Kotlin
fun name filterValid , but from Java it will befilterValid and
they will be accessible by the sameList<String>
List<String>.filterValid():
filterValidInt .
@JvmName("filterValidInt")
The fun
sameList<Int>.filterValid():
trick applies when we need to have a property x alongside with a function getX() :
List<Int>
128
val x: Int
@JvmName("getX_prop")
get() = 15
fun getX() = 10
Overloads Generation
Normally, if you write a Kotlin method with default parameter values, it will be visible in Java only as a full signature, with all
parameters present. If you wish to expose multiple overloads to Java callers, you can use the @JvmOverloads annotation.
For @JvmOverloads
every parameter withfuna default
f(a: value, this will
String, b: generate
Int = 0,onec:additional
Stringoverload,
= "abc") which
{ has this parameter and all
parameters to
... the right of it in the parameter list removed. In this example, the following methods will be generated:
}
The //
annotation
Java also works for constructors, static methods etc. It can’t be used on abstract methods, including methods
defined
voidin interfaces.
f(String a, int b, String c) { }
void f(String a, int b) { }
Note that, as described in Secondary Constructors, if a class has default values for all constructor parameters, a public no-
void f(String a) { }
argument constructor will be generated for it. This works even if the @JvmOverloads annotation is not specified.
Checked Exceptions
As we mentioned above, Kotlin does not have checked exceptions. So, normally, the Java signatures of Kotlin functions do
not declare exceptions thrown. Thus if we have a function in Kotlin like this:
And//
we example.kt
want to call it from Java and catch the exception:
package demo
// Java
fun foo() {
try {
throw IOException()
demo.Example.foo();
}
}
catch (IOException e) { // error: foo() does not declare IOException in the throws list
// ...
}
129
we get an error message from the Java compiler, because foo() does not declare IOException . To work around this
problem, use the @Throws annotation in Kotlin:
@Throws(IOException::class)
Null-safety
fun foo() {
throw
When calling IOException()
Kotlin functions from Java, nobody prevents us from passing null as a non-null parameter. That’s why Kotlin
}
generates runtime checks for all public functions that expect non-nulls. This way we get a NullPointerException in the
Java code immediately.
Variant generics
When Kotlin classes make use of declaration-site variance, there are two options of how their usages are seen from the Java
code. Let’s say we have the following class and two functions that use it:
A naive
classwayBox<out
of translating these value:
T>(val functions T)
into Java would be this:
The interface
Box<Derived>
Base
problem is that inboxDerived(Derived
Kotlin we can say unboxBase(boxDerived("s"))
value) { ... , but in Java that would be impossible, because
class
in Java the Derived
class Box :is Base
invariant in its
} Base unboxBase(Box<Base> box) { ... } parameter T , and thus Box<Derived> is not a subtype of Box<Base> . To make
it work in Java we’d have to define unboxBase as follows:
fun boxDerived(value: Derived): Box<Derived> = Box(value)
fun unboxBase(box: Box<Base>): Base = box.value
HereBase
we make use of Java’s wildcards
unboxBase(Box<? types
extends ( ? extends
Base> box) { Base
... }) to emulate declaration-site variance through use-site
variance, because it is all Java has.
To make Kotlin APIs work in Java we generate Box<Super> as Box<? extends Super> for covariantly defined Box
(or Foo<? super Bar> for contravariantly defined Foo ) when it appears as a parameter. When it’s a return value, we
don’t generate wildcards, because otherwise Java clients will have to deal with them (and it’s against the common Java
coding style). Therefore, the functions from our example are actually translated as follows:
// parameter - wildcards
Base unboxBase(Box<? extends Base> box) { ... }
130
NOTE: when the argument type is final, there’s usually no point in generating the wildcard, so Box<String> is always
Box<String> , no matter what position it takes.
If we need wildcards where they are not generated by default, we can use the @JvmWildcard annotation:
On the other hand, if we don’t need wildcards where they are generated, we can use @JvmSuppressWildcards :
fun@JvmSuppressWildcards
NOTE: can be used not only on individual
unboxBase(box: Box<@JvmSuppressWildcards Base>): typeBase
arguments, but on entire declarations, such as
= box.value
functions
// isor translated
classes, causing
toall wildcards inside them to be suppressed.
// Base unboxBase(Box<Base> box) { ... }
Translation of type Nothing
The type Nothing is special, because it has no natural counterpart in Java. Indeed, every Java reference type, including
java.lang.Void , accepts null as a value, and Nothing doesn’t accept even that. So, this type cannot be accurately
represented in the Java world. This is why Kotlin generates a raw type where an argument of type Nothing is used:
131
Tools
Documenting Kotlin Code
The language used to document Kotlin code (the equivalent of Java’s JavaDoc) is called KDoc. In its essence, KDoc
combines JavaDoc’s syntax for block tags (extended to support Kotlin’s specific constructs) and Markdown for inline markup.
Dokka has plugins for Gradle, Maven and Ant, so you can integrate documentation generation into your build process.
KDoc Syntax
Just like with JavaDoc, KDoc comments start with
/** and end with */ . Every line of the comment may begin with an
asterisk, which is not considered part of the contents of the comment.
By convention, the first paragraph of the documentation text (the block of text until the first blank line) is the summary
description of the element, and the following text is the detailed description.
Every block tag begins on a new line and starts with the @ character.
/**
Block Tags
* A group of *members*.
KDoc*currently supports the following block tags:
* This class has no useful logic; it's just a documentation example.
*
@param <name>
* @param T the type of a member in this group.
* @property name the name of this group.
* @constructor Creates an empty group.
*/
class Group<T>(val name: String) {
/**
* Adds a [member] to this group.
* @return the new size of the group.
*/
fun add(member: T): Int { ... }
}
132
Documents a value parameter of a function or a type parameter of a class, property or function. To better separate the
parameter name from the description, if you prefer, you can enclose the name of the parameter in brackets. The following
two syntaxes are therefore equivalent:
@return
@constructor
@property <name>
Documents the property of a class which has the specified name. This tag can be used for documenting properties
declared in the primary constructor, where putting a doc comment directly before the property definition would be awkward.
Documents an exception which can be thrown by a method. Since Kotlin does not have checked exceptions, there is also
no expectation that all possible exceptions are documented, but you can still use this tag when it provides useful
information for users of the class.
@sample <identifier>
Embeds the body of the function with the specified qualified name into the documentation for the current element, in order to
show an example of how the element could be used.
@see <identifier>
Adds a link to the specified class or method to the See Also block of the documentation.
@author
@since
Specifies the version of the software in which the element being documented was introduced.
@suppress
Excludes the element from the generated documentation. Can be used for elements which are not part of the official API of a
module but still have to be visible externally.
KDoc does not support the @deprecated tag. Instead, please use the @Deprecated annotation.
Inline Markup
For inline markup, KDoc uses the regular Markdown syntax, extended to support a shorthand syntax for linking to other
elements in the code.
133
Linking to Elements
To link to another element (class, method, property or parameter), simply put its name in square brackets:
If you want to specify a custom label for the link, use the Markdown reference-style syntax:
You can also use qualified names in the links. Note that, unlike JavaDoc, qualified names always use the dot character to
separate the components, even before a method name:
Names in links are resolved using the same rules as if the name was used inside the element being documented. In
particular, this means that if you have imported a name into the current file, you don’t need to fully qualify it when you use it
in a KDoc comment.
Note that KDoc does not have any syntax for resolving overloaded members in links. Since the Kotlin documentation
generation tool puts the documentation for all overloads of a function on the same page, identifying a specific overloaded
function is not required for the link to work.
134
Using Maven
Define the version of Kotlin you want to use via kotlin.version. The correspondence between Kotlin releases and versions is
displayed below:
Milestone Version
1.0.1 hotfix update 2 1.0.1-2
1.0.1 hotfix update 1.0.1-1
1.0.1 1.0.1
1.0 GA 1.0.0
Release Candidate 1.0.0-rc-1036
Beta 4 1.0.0-beta-4589
Beta 3 1.0.0-beta-3595
Beta 2 1.0.0-beta-2423
Beta 1.0.0-beta-1103
Beta Candidate 1.0.0-beta-1038
M14 0.14.449
M13 0.13.1514
M12.1 0.12.613
M12 0.12.200
M11.1 0.11.91.1
M11 0.11.91
M10.1 0.10.195
M10 0.10.4
M9 0.9.66
M8 0.8.11
M7 0.7.270
M6.2 0.6.1673
M6.1 0.6.602
M6 0.6.69
M5.3 0.5.998
Dependencies
Kotlin has an extensive standard library that can be used in your applications. Configure the following dependency in the pom
file
<dependencies>
<dependency>
<groupId>org.jetbrains.kotlin</groupId>
<artifactId>kotlin-stdlib</artifactId>
<version>${kotlin.version}</version>
</dependency>
</dependencies>
135
Compiling Kotlin only source code
To compile source code, specify the source directories in the tag:
The <sourceDirectory>${project.basedir}/src/main/kotlin</sourceDirectory>
Kotlin Maven Plugin needs to be referenced to compile the sources:
<testSourceDirectory>${project.basedir}/src/test/kotlin</testSourceDirectory>
<plugin>
Compiling Kotlin and Java sources
<artifactId>kotlin-maven-plugin</artifactId>
<groupId>org.jetbrains.kotlin</groupId>
To compile mixed code applications Kotlin compiler should be invoked before Java compiler. In maven terms that
<version>${kotlin.version}</version>
means kotlin-maven-plugin should be run before maven-compiler-plugin.
It could be<executions>
done by moving Kotlin compilation to previous phase, process-sources (feel free to suggest a better solution if
you have one):<execution>
<id>compile</id>
<goals> <goal>compile</goal> </goals>
<plugin> </execution>
<artifactId>kotlin-maven-plugin</artifactId>
<groupId>org.jetbrains.kotlin</groupId>
<execution>
<version>${kotlin.version}</version>
<id>test-compile</id>
<goals> <goal>test-compile</goal> </goals>
<executions>
</execution>
<execution>
</executions>
</plugin> <id>compile</id>
<phase>process-sources</phase>
<goals> <goal>compile</goal> </goals>
</execution>
<execution>
<id>test-compile</id>
<phase>process-test-sources</phase>
<goals> <goal>test-compile</goal> </goals>
</execution>
</executions>
</plugin>
136
OSGi
For OSGi support see the Kotlin OSGi page.
Examples
An example Maven project can be downloaded directly from the GitHub repository
137
Using Ant
These tasks are defined in the kotlin-ant.jar library which is located in the lib folder for the Kotlin Compiler
where ${kotlin.lib}
<project points to theTask
name="Ant folderTest"
where the Kotlin standalone compiler was unzipped.
default="build">
<typedef
resource="org/jetbrains/kotlin/ant/antlib.xml"
Targeting JVM with Kotlin-only source and multiple roots
classpath="${kotlin.lib}/kotlin-ant.jar"/>
If a project consists of multiple source roots, use src as elements to define paths
<target name="build">
<kotlinc src="hello.kt" output="hello.jar"/>
<project name="Ant Task Test" default="build">
Targeting JVM with Kotlin and Java source
</target>
<typedef
resource="org/jetbrains/kotlin/ant/antlib.xml"
If a project consists of both Kotlin and Java source code, while it is possible to use kotlinc, to avoid repetition of task
classpath="${kotlin.lib}/kotlin-ant.jar"/>
parameters, it is recommended to use withKotlin task
<target name="build">
<kotlinc output="hello.jar">
<src path="root1"/>
<src path="root2"/>
</kotlinc>
</target>
138
<project name="Ant Task Test" default="build">
<typedef
resource="org/jetbrains/kotlin/ant/antlib.xml"
classpath="${kotlin.lib}/kotlin-ant.jar"/>
<target name="build">
<delete dir="classes" failonerror="false"/>
<mkdir dir="classes"/>
<javac destdir="classes" includeAntRuntime="false" srcdir="src">
<withKotlin/>
</javac>
<jar destfile="hello.jar">
<fileset dir="classes"/>
</jar>
</target>
To specify additional command line arguments for <withKotlin> , you can use a nested<compilerArg> parameter.
The full list of arguments that can be used is shown when you run kotlinc -help . You can also specify the name of the
module being compiled as the moduleName attribute:
<withKotlin moduleName="myModule">
Targeting JavaScript with single source folder
<compilerarg value="-no-stdlib"/>
</withKotlin>
<project name="Ant Task Test" default="build">
Targeting JavaScript with Prefix, PostFix and sourcemap options
<typedef
resource="org/jetbrains/kotlin/ant/antlib.xml"
classpath="${kotlin.lib}/kotlin-ant.jar"/>
<project name="Ant Task Test" default="build">
Targeting JavaScript with single source folder and metaInfo option
<taskdef
<target
metaInfo name="build">
The resource="org/jetbrains/kotlin/ant/antlib.xml"
option is useful, if you want to distribute the result of translation as a Kotlin/JavaScript library. If metaInfo
was set to true , then duringsrc="root1"
<kotlin2js
classpath="${kotlin.lib}/kotlin-ant.jar"/> output="out.js"/>
compilation additional JS file with binary metadata will be created. This file should
</target>
be distributed together with the result of translation.
<target name="build">
<kotlin2js src="root1" output="out.js" outputPrefix="prefix"
outputPostfix="postfix" sourcemap="true"/>
</target>
139
<project name="Ant Task Test" default="build">
<typedef
resource="org/jetbrains/kotlin/ant/antlib.xml"
classpath="${kotlin.lib}/kotlin-ant.jar"/>
<target name="build">
<!-- out.meta.js will be created, which contains binary descriptors -->
<kotlin2js src="root1" output="out.js" metaInfo="true"/>
</target>
References
Complete list of elements and attributes are listed below
kotlinc Attributes
kotlin2js Attributes
NameDescriptionRequired
output Destination file Yes
library Library files (kt, dir, jar) No
outputPrefix Prefix to use for generated JavaScript files No
outputSuffix Suffix to use for generated JavaScript files No
140
Using Gradle
In order to build Kotlin with Gradle you should set up the kotlin-gradle plugin, apply it to your
project and add kotlin-stdlib dependencies. Those actions may also be performed automatically in Kotlin Configure
IntelliJ IDEA by invoking the Tools Kotlin in
Project
action.
The buildscript
correspondence{between Kotlin releases and versions is displayed below:
ext.kotlin_version = '<version to use>'
Milestone Version
1.0.1 hotfix update 2 1.0.1-2
repositories {
mavenCentral()
1.0.1 hotfix update 1.0.1-1
}
1.0.1 1.0.1
1.0 GAdependencies 1.0.0
{
Release Candidate
classpath 1.0.0-rc-1036
"org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"
Beta 4} 1.0.0-beta-4589
}
Beta 3 1.0.0-beta-3595
Beta 2 1.0.0-beta-2423
Beta 1.0.0-beta-1103
Beta Candidate 1.0.0-beta-1038
M14 0.14.449
M13 0.13.1514
M12.1 0.12.613
M12 0.12.200
M11.1 0.11.91.1
M11 0.11.91
M10.1 0.10.195
M10 0.10.4
M9 0.9.66
M8 0.8.11
M7 0.7.270
M6.2 0.6.1673
M6.1 0.6.602
141
M6ilestone0V.e6r.s6i9o n
M5.3 0.5.998
Kotlin sources can be mixed with Java sources in the same folder, or in different folders. The default convention is using
different folders:
The project
corresponding sourceSets property should be updated if not using the default convention
- src
- main (root)
sourceSets {
Targeting JavaScript
- kotlin
main.kotlin.srcDirs += 'src/main/myKotlin'
- java
main.java.srcDirs
When targeting += 'src/main/myJava'
JavaScript, a different plugin should be applied:
}
Thisapply
plugin only works for
plugin: Kotlin files so it is recommended to keep Kotlin and Java files separate (if it’s the case that the
"kotlin2js"
same project contains Java files). As with targeting the JVM, if not using the default convention, we need to specify the
source folder using sourceSets
compileKotlin2Js
Targeting Android
{ kotlinOptions.metaInfo =
trueGradle model is a little different from ordinary Gradle, so if we want to build an Android project written in Kotlin, we
Android’s
need kotlin-android plugin instead of kotlin:
142
buildscript {
...
}
apply plugin:
'com.android.application' apply
plugin: 'kotlin-android'
Android Studio
Thisandroid
lets Android
{ Studio know that the kotlin directory is a source root, so when the project model is loaded into the IDE it
will be ...
properly recognized.
sourceSets
Configuring {
Dependencies
main.java.srcDirs += 'src/main/kotlin'
In addition
} to the kotlin-gradle-plugin dependency shown above, you need to add a dependency on the Kotlin standard
}
library:
repositories {
mavenCentral()
}
dependencies {
compile "org.jetbrains.kotlin:kotlin-stdlib:$kotlin_version"
}
143
For OSGi support see the Kotlin OSGi page.
Examples
The Kotlin Repository contains examples:
— Kotlin
— Mixed Java and Kotlin
— Android
— JavaScript
144
Kotlin and OSGi
To enable Kotlin OSGi support you need to include kotlin-osgi-bundle instead of regular Kotlin libraries. It is
recommended to remove kotlin-runtime , kotlin-stdlib and kotlin-reflect dependencies askotlin-
osgi-bundle already contains all of them. You also should pay attention in case when external Kotlin libraries are
included. Most regular Kotlin dependencies are not OSGi-ready, so you shouldn’t use them and should remove them from
your project.
Maven
To include the Kotlin OSGi bundle to a Maven project:
To exclude the standard library from external libraries (notice that “star exclusion” works in Maven 3 only)
<dependencies>
<dependency>
<groupId>org.jetbrains.kotlin</groupId>
<dependency>
Gradle <artifactId>kotlin-osgi-bundle</artifactId>
<groupId>some.group.id</groupId>
<version>${kotlin.version}</version>
To include <artifactId>some.library</artifactId>
kotlin-osgi-bundle
</dependency> to a gradle project:
<version>some.library.version</version>
</dependencies>
compile <exclusions>
"org.jetbrains.kotlin:kotlin-osgi-bundle:$kotlinVersion"
<exclusion>
<groupId>org.jetbrains.kotlin</groupId>
To exclude default Kotlin libraries that comes as transitive dependencies you can use the following approach
<artifactId>*</artifactId>
</exclusion>
dependencies</exclusions>
FAQ
{ compile (
</dependency>
[group: 'some.group.id', name: 'some.library', version: 'someversion'],
.....) {
exclude group: 'org.jetbrains.kotlin'
}
145
Why not just add required manifest options to all Kotlin libraries
Even though it is the most preferred way to provide OSGi support, unfortunately it couldn’t be done for now due to so called
“package split” issue that could’t be easily eliminated and such a big change is not planned for now. There is Require-
Bundle feature but it is not the best option too and not recommended to use. So it was decided to make a separate
artifact for OSGi.
146
FAQ
FAQ
Common Questions
What is Kotlin?
Kotlin is a statically typed language that targets the JVM and JavaScript. It is a general-purpose language intended for
industry use.
It is developed by a team at JetBrains although it is an OSS language and has external contributors.
At JetBrains, we’ve been developing for the Java platform for a long time, and we know how good it is. On the other hand, we
know that the Java programming language has certain limitations and problems that are either impossible or very hard to fix
due to backward-compatibility issues. We know that Java is going to stand long, but we believe that the community can
benefit from a new statically typed JVM-targeted language free of the legacy trouble and having the features so desperately
wanted by the developers.
How is it licensed?
Kotlin is an OSS language and is licensed under the Apache 2 OSS License. The IntelliJ Plug-in is also
Is it Java Compatible?
Yes. The compiler emits Java byte-code. Kotlin can call Java, and Java can call Kotlin. See Java interoperability.
Kotlin generates bytecode which is compatible with Java 6 or newer. This ensures that Kotlin can be used in environments
such as Android, where Java 6 is the latest supported version.
147
Is there tooling support?
Yes. There is an IntelliJ IDEA plugin that is available as an OSS project under the Apache 2 License. You can use Kotlin
both in the free OSS Community Edition and Ultimate Edition of IntelliJ IDEA.
Yes. You can download the standalone compiler and other builds tools from the release page on GitHub
Kotlin is an Object-Orientated language. However it has support for higher-order functions as well as lambda expressions
and top-level functions. In addition, there are a good number of common functional language constructs in the standard
Kotlin library (such as map, flatMap, reduce, etc.). Also, there’s no clear definition on what a Functional Language is so we
couldn’t say Kotlin is one.
Kotlin supports generics. It also supports declaration-site variance and usage-site variance. Kotlin also does not have
wildcard types. Inline functions support reified type parameters.
Yes.
We believe it makes the code more readable. Besides, it enables some nice syntactic features. For instance, it is easy to
leave type annotations out. Scala has also proven pretty well this is not a problem.
No. It won’t. We can still implement suggestions for variable names, etc.
Is Kotlin extensible?
We are planning on making it extensible in a few ways: from inline functions to annotations and type loaders.
Yes. Kotlin provides a few features that help: Operator overloading, Custom Control Structures via inline functions, Infix
function calls, Extension Functions, Annotations and language quotations.
Currently at 5.
148
Yes. There are plans to provide CommonJS and AMD support.
149
Comparison to Java
150
Comparison to Scala
The main goal of the Kotlin team is to create a pragmatic and productive programming language, rather than to advance
the state of the art in programming language research. Taking this into account, if you are happy with Scala, you most
likely do not need Kotlin.
— Built-in XML
— See Type-safe Groovy-style builders
— Structural types
— Value types
— We plan to support Project Valhalla once it is released as part of the JDK
— Yield operator
— Actors
— Kotlin supports Quasar, a third-party framework for actor support on the JVM
— Parallel collections
— Kotlin supports Java 8 streams, which provide similar functionality
— Smart casts
— Kotlin’s Inline functions facilitate Nonlocal jumps
— First-class delegation. Also implemented via 3rd party plugin: Autoproxy
— Member references (also supported in Java 8).
151
152