with JVM • Android – development • 2017: first-class support for Kotlin in Android • 2019, preferred language for Android App Development • In Java, JDK 7 is fully supported, some JDK 8 features also available • Spring – development • Also possible to to use Kotlin -> JavaScript transpilers
Java virtual machine • When compiling .java -> .class you will end up with bytecode • javac App.java • Bytecode is run using JVM • java App • Java is the most common language for JVM • But there are others • Scala, Groovy, Clojure, Kotlin
• https://github.com/JetBrains/kotlin/releases/latest • Download only the compiler • Put the compiler to path • More information: • https://kotlinlang.org/docs/tutorials/command-line.html
$ kotlinc Hello.kt $ java HelloKt Exception in thread "main" java.lang.NoClassDefFoundError: kotlin/jvm/internal/Intrinsics at HelloKt.main(Hello.kt) Caused by: java.lang.ClassNotFoundException: kotlin.jvm.internal.Intrinsics at java.base/jdk.internal.loader.BuiltinClassLoader.loadClass(BuiltinClassLoader.java:606) at java.base/jdk.internal.loader.ClassLoaders$AppClassLoader.loadClass(ClassLoaders.java:168) at java.base/java.lang.ClassLoader.loadClass(ClassLoader.java:522) ... 1 more
kotlinc Hello.kt $ java -cp .:/path/to/kotlinc/lib/kotlin-runner.jar HelloKt Hello World! $ kotlinc Hello.kt -include-runtime -d app.jar $ java -jar app.jar Hello World! Kotlin classes It will dynamically add main class attribute to the class that holds main function
└── main.kotlin_module ├── Main.kt ├── Util.kt ├── com │ └── organisation │ └── main │ └── MainKt.class └── fi └── util └── UtilKt.class It creates dir structure Every top level function will be a class in the end. Rapid discover of top-level members with this meta data file
basic types! • Some of the types can have special internal representation, can be presented as primitive value • When using Int it is compiled to Integer or int to JVM • Use val for constant, var for variable.
val another : Int = 1 // Long val threeBillion = 3000000000 // Long val oneLong = 1L // Byte val oneByte: Byte = 1 // Float val oneFloat = 1.0f // Double val oneDouble = 1.0
1.0f // Double val oneDouble : Double = oneFloat } Code.kt:6:30: error: type mismatch: inferred type is Float but Double was expected val oneDouble : Double = oneFloat
{ println("Drink Water"); } } class Programmer : Person() { fun codeApps() { println("Code Apps") } } fun main() { val tina : Person = Programmer() tina.drink() val temp : Programmer = tina as Programmer temp.codeApps() } To type cast between objects, use as or as?
as numbers, use toInt() • Booleans • Boolean • Arrays • Array • Has [] operator overloading, size and other useful methods • You can create it using arrayOf() function • Also primitive type arrays available: IntArray, ByteArray ...
2).toInt() if(random == 0) { return "Hello World"; } else { return null; } } fun main() { val value : String? = generate() println(value.length) } What is the problem here?
system distinguishes between references that can hold null and those that can not • val a : String? = "Hello World" • a = null • To check null conditions (does variable contain null) • if • Safe call • Elvis Operator • !! Operator • Also casting available (Safe Casts)
{ return (0..1).random() == 0 } class Person { var pet : Pet? = if(myrandom()) Pet() else null } class Pet { var favoriteToy: Toy? = if(myrandom()) Toy() else null } class Toy { var name: String? = if(myrandom()) "ball" else null } fun main() { val person : Person? = if(myrandom()) Person() else null println(person?.pet?.favoriteToy?.name) } If some of these are null, output null Kotlin way of creating random value No need for ternary operator, if is enough
val hello : String? = if((0..1).random() == 0) "hello world" else null val length1 = if(hello != null) hello.length else -1 println(length1) val length2 = hello?.length ?: -1 println(length2) } Maybe "hello world" or null Outputs 11 or -1 Does the same but uses elvis operator!
Range defines interval with two endpoint values • Ranges are defined for comparable types • Has order • IntRange, LongRange and CharRange can be also iterated
fun compareTo(other: Person): Int { return this.weight - other.weight } } fun main() { val personRange = Person(50).rangeTo(Person(100)) print(Person(60) in personRange) } true You cannot iterate this, that must be implemented with custom iterator()
= 1.rangeTo(10) val rangeChar1 : CharRange = 'a'.rangeTo('z') // The same! val rangeInt2 : IntRange = 1..10 val rangeChar2 : CharRange = 'a'..'z' Operator form of range
val simpleStr = "again" val str : String = """ <ul> <li>${myarray.get(0)}</li> <li>${myarray.get(1)}</li> <li>$simpleStr</li> </ul> """ println(str) } Can contain expression or a simple value
val simpleStr = "again" val str : String = """ |<ul> | <li>${myarray.get(0)}</li> | <li>${myarray.get(1)}</li> | <li>$simpleStr</li> |</ul> """.trimMargin("|") println(str) } Clears extra whitespaces. "|" is on by default, you can omit that.
Presents array in JVM • Can be created • constructor, arrayOf, arrayOfNulls, EmptyArray • Lot of different methods available • Notice that Kotlin provides also it's own collection classes
to represent lack of type • Problem with primitive types, boxing • In Kotlin: Any is supertype for all non-nullable types • Also primitive types are any • In Kotlin: Unit is the same than void • Unit is a type, and can be used as type argument • It is returned implicitly, no need of a return statement • Unit is needed in generics
= 1) : String { var newString = "" for(i in 1..amount) { newString += text } return newString } fun main() { println(repeat("hello", 10)) } Return type Default value
amount: Int = 1) : String { var newString = "" for(i in 1..amount - 1) { newString += text + wordSeparator } newString += text return newString } fun main() { println(repeat("hello", amount = 10)) } Using named argument we change the last argument of the function
amount: Int = 1) : String { var newString = "" for(i in 1..amount - 1) { newString += text + wordSeparator } newString += text return newString } fun main() { println(repeat("hello", 10)) } Three arguments "error: the integer literal does not conform to the expected type String"
sum = 0 for(item in numbers) { sum += item } return sum } fun main() { println(sum(5,5,5)) val a = intArrayOf(1, 2, 3) println(sum(*a)) } We can send list of numbers Notice that if having array, use a spread (*) operator
println("drinking beer " + beer) } } fun main() { val jaska = Person() jaska drinkBeer "Lapin kulta" jaska.drinkBeer("lapin kulta") } infix functions must be 1) member functions or extension function 2) must have single parameter 3) must not use varargs You can now call the method if different syntax
callback("some data") } fun main() { readFile("file.txt", { data: String -> println(data) }) readFile("file.txt", { data -> println(data) }) readFile("file.txt") { data -> println(data) } readFile("file.txt") { println(it) } } Different syntax, does the same Second argument is a function Trailing lambda if last argument is function! When using only one argument you can use it!
Int) -> Unit) { for(i in myarray.indices) { callback(myarray[i]) } } fun main() { val myarray = arrayOf(1,2,3) map( myarray, { item -> println(item) } ) } Returns Unit, is a "void" function
Int) -> Unit) { for(i in myarray.indices) { callback(myarray[i]) } } fun main() { val myarray = arrayOf(1,2,3) map( myarray, { item -> item + 1 } ) } Returns Unit, is a "void" function Does not return anything
val another1 = list.map( { value : Int -> value + 1} ) val another2 = list.map( { value -> value + 1} ) val another3 = list.map() { value -> value + 1 } val another4 = list.map() { it -> it + 1 } val another5 = list.map() { it + 1 } println(another1) println(another2) println(another3) println(another4) println(another5)
{ } fun main() { val dog = Dog("spot") val cat = Dog("onni") } If no annotations you can omit constructor keyword constructor does not contain any code, this is done in init block!
main() { val cat = Cat("onni") println(cat.name) } Does NOT work because this is private Notice that if using visibility modifiers (or annotations) then constructor keyword is required
// inherites Any • Any has three methods • equals(), hashCode() and toString() • By default all classes are final, they cannot be inherited! • To make class open for inherit: • open class Mammal
var salary : Int) : Person(name) fun main() { val tina = Programmer("tina", 4000) println(tina.name) println(tina.salary) } You must initialize the base class here
Int) { open fun draw() { println("rect") } } class Circle(x : Int, y : Int, var radius: Int) : Shape(x, y) { override fun draw() { println("circle") } } fun main() { val c = Circle(5,5,5) c.draw() } overriding can be done only if function is declared as open!
: Int) { abstract fun draw() } class Circle(x : Int, y : Int, var radius: Int) : Shape(x, y) { override fun draw() { println("circle") } } fun main() { val c = Circle(5,5,5) c.draw() } Declaring class and method as abstract
fun start() { this.motor = Motor() this.motor.start() } } fun main() { val c = Car() c.start() } error: property must be initialized or be abstract var motor: Motor
fun main() { val a = User("jack", 40) val b = User("jack", 40) println(a.equals(b)) // true println(a.hashCode()) println(a.toString()) // "User(name=jack, age=40)" val c = b.copy() println(c) // User(name=jack, age=40) } equals / hashcode toString copy()
JFrame(title) { val button = JButton("click") init { button.addActionListener(object: ActionListener { override fun actionPerformed(e : ActionEvent) { println("hello") } }) button.addActionListener() { println("world!") } add(button) } } fun main() { val window = MyWindow("hello") window.pack() window.setVisible(true) } If using Java's functional interfaces, you can use lambda syntax here
PI = 3.14 // Visible everywhere public fun abs(value : Int) = if(value < 0) value * - 1 else value // Visible in the same module internal fun calculate(radius : Double) = PI * radius * radius // protected not available for top-level declarations
without inheritance • You can write new functionality to third – party libraries (that would not be modifiable) • You can have • extension functions • extension properties