Slide 1

Slide 1 text

Kotlin Language Jussi Pohjolainen

Slide 2

Slide 2 text

Kotlin • Cross-platform, statically typed, general-purpose programming language • Designed to interoperate with Java and JVM

Slide 3

Slide 3 text

Why Kotlin? • It's "Java" without the "boilerplate" • Compatible 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

Slide 4

Slide 4 text

Why Kotlin? • Less code • Safe (null pointer exceptions) • Interoperable (JVM Support) • Tool friendly, choose any Java IDE or command line

Slide 5

Slide 5 text

JVM • Java bytecode is the instruction set of the 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

Slide 6

Slide 6 text

Tools

Slide 7

Slide 7 text

Working with the Command Line Compiler • Download latest release • 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

Slide 8

Slide 8 text

$ cat Hello.kt fun main() { println("Hello World!") } $ kotlinc Hello.kt $ java HelloKt Hello World!

Slide 9

Slide 9 text

$ cat Hello.kt fun main(args: Array) { println("Hello World!") } $ 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

Slide 10

Slide 10 text

Default imports import java.lang.*; import kotlin.* import kotlin.annotation.* import kotlin.collections.* import kotlin.comparisons.* import kotlin.io.* import kotlin.ranges.* import kotlin.sequences.* import kotlin.text.*

Slide 11

Slide 11 text

$ cat Hello.kt fun main() { println("Hello World!") } $ 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

Slide 12

Slide 12 text

Output contents of class file > javap -c HelloKt.class Compiled from "Hello.kt" public final class HelloKt { public static final void main(java.lang.String[]); Code: 0: aload_0 1: ldc #9 // String args 3: invokestatic #15 // Method kotlin/jvm/internal/Intrinsics.checkNotNullParameter:(Ljava/lang/Object;Ljava/lang/String;)V 6: ldc #17 // String Hello World! 8: astore_1 9: iconst_0 10: istore_2 11: getstatic #23 // Field java/lang/System.out:Ljava/io/PrintStream; 14: aload_1 15: invokevirtual #29 // Method java/io/PrintStream.println:(Ljava/lang/Object;)V 18: return }

Slide 13

Slide 13 text

Easier running $ cat Hello.kt fun main(args: Array) { println("Hello World!") } $ kotlinc Hello.kt $ kotlin HelloKt Hello World! Kotlin generates HelloKt named class

Slide 14

Slide 14 text

Working with Packages $ cat Main.kt package com.organisation.main import fi.util.*; fun main() { println(sum(5,5)) } $ cat Util.kt package fi.util fun sum(a: Int, b: Int) : Int { return a + b } MacBook-Pro-7:test pohjus$ Declare package Importing package

Slide 15

Slide 15 text

Tree tree . ├── Main.kt └── Util.kt 0 directories, 2 files These are in root!

Slide 16

Slide 16 text

Compiling $ kotlinc *.kt $ tree . ├── META-INF │ └── 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

Slide 17

Slide 17 text

Lab 01

Slide 18

Slide 18 text

Quick Intro to Basics

Slide 19

Slide 19 text

Basic Types • Everything seems to be an object, even 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.

Slide 20

Slide 20 text

Integer Numbers https://kotlinlang.org/docs/reference/basic-types.html

Slide 21

Slide 21 text

Floating-point Numbers https://kotlinlang.org/docs/reference/basic-types.html

Slide 22

Slide 22 text

// Int val one = 1 // Declaring a type 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

Slide 23

Slide 23 text

Type Conversion fun main() { // Float val oneFloat = 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

Slide 24

Slide 24 text

Type Conversion fun main() { // Float val oneFloat = 1.0f // Double val oneDouble : Double = oneFloat.toDouble() } Use methods to make the cast

Slide 25

Slide 25 text

Type Conversion between classes open class Person { fun drink() { 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?

Slide 26

Slide 26 text

Other • Characters • Char • Cannot be treated directely 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 ...

Slide 27

Slide 27 text

Simple Example fun main() { // character val x : Char = 'a' // a print(x) // 97 print(x.toInt()) val value : Boolean = 1 < 2 // true print(value) // false print(value.not()) }

Slide 28

Slide 28 text

String • Strings are immutable • You can access characters using string[i] syntax • Can be iterated using for • Can concatenat using + • You can use ', " or """ • You can embed variables: "i = $i"

Slide 29

Slide 29 text

fun main() { val value : Double = Math.random() val embed = "random = $value" val list = """
  • Hello
""" println(list) println(embed) println(embed[0]) }

Slide 30

Slide 30 text

fun main() { val value = "hello world" for(i in 0..value.length - 1) { println(value[i]) } for(i in 0 until value.length) { println(value[i]) } } Using ranges

Slide 31

Slide 31 text

Nullable

Slide 32

Slide 32 text

Nullable fun main() { val oneInt : Int = 1 oneInt = null } Internally oneInt is a primitive type... If it is a primitive type can you do this?

Slide 33

Slide 33 text

Problem 1: val vs var fun main() { val oneInt : Int = 1 oneInt = null } val is constant

Slide 34

Slide 34 text

Problem 2: Int vs Int? fun main() { var oneInt : Int? = 1 oneInt = null } Now internal type is Integer (object)

Slide 35

Slide 35 text

Problem? fun generate(): String? { val random = (Math.random() * 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?

Slide 36

Slide 36 text

Common pitfall: Null Pointer Exceptions • In Kotlin, the type 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)

Slide 37

Slide 37 text

Checking for null conditions:if fun generate(): String? { val random = (Math.random() * 2).toInt() if(random == 0) { return "Hello World"; } else { return null; } } fun main() { val value : String? = generate() val length = if(value != null) value.length else -1 println(length) } null checking! Generate 0 or 1 (kotlin has a nicer way of doing this ..)

Slide 38

Slide 38 text

Checking for null conditions: if fun generate(): String? { val random = (Math.random() * 2).toInt() if(random == 0) { return "Hello World"; } else { return null; } } fun main() { val value : String? = generate() if(value != null) println(value.length) } Works also!

Slide 39

Slide 39 text

Checking for null conditions: if fun generate(): String? { val random = (Math.random() * 2).toInt() if(random == 0) { return "Hello World"; } else { return null; } } fun main() { val value : String? = generate() if(value != null && value.length > 0) println("It is not empty string") } Works also!

Slide 40

Slide 40 text

Checking for null conditions: Save Call fun generate(): String? { val random = (Math.random() * 2).toInt() if(random == 0) { return "Hello World"; } else { return null; } } fun main() { val value : String? = generate() println(value?.length) } Returns either 11 or null

Slide 41

Slide 41 text

Checking for null conditions: Save Call fun myrandom() : Boolean { 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

Slide 42

Slide 42 text

Checking for null conditions: Elvis operator ?: fun main() { 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!

Slide 43

Slide 43 text

Checking for null operators: !! fun main() { val hello : String? = if((0..1).random() == 0) "hello world" else null val length = hello!!.length println(length) } Crashes the app if hello is null

Slide 44

Slide 44 text

Safe Cast: as? • You can use save cast between objects • val circle : Circle? = object as? Circle • Now the circle here may contain null or the object

Slide 45

Slide 45 text

Lab 02

Slide 46

Slide 46 text

Control Flow

Slide 47

Slide 47 text

Control Flow: If • No ternary operator! Just use if: • val max = if (a > b) a else b • Or: val max = if (a > b) { print("Choose a") a } else { print("Choose b") b }

Slide 48

Slide 48 text

Control Flow: switch case, when when (x) { 1 -> print("x == 1") 2 -> print("x == 2") else -> { print("x is neither 1 nor 2") } }

Slide 49

Slide 49 text

Control Flow: when when (x) { 0, 1 -> print("x == 0 or x == 1") else -> print("otherwise") }

Slide 50

Slide 50 text

Control Flow: when val grade = 8 val output = when(grade) { 1,2,3,4 -> "Fail" 5,6,7,8 -> "Ok" 9,10 -> "Great" else -> "Unknown" } println(output)

Slide 51

Slide 51 text

Control Flow: while var i = 0 while(i < 10) { println(i) i++ }

Slide 52

Slide 52 text

Control Flow: For - loop val myarray : Array = arrayOf(1,2,3) for(item in myarray) { println(item) } Must provide iterator

Slide 53

Slide 53 text

Ranges • Create ranges of values using rangeTo() function • Range defines interval with two endpoint values • Ranges are defined for comparable types • Has order • IntRange, LongRange and CharRange can be also iterated

Slide 54

Slide 54 text

Custom Range class Person(var weight: Int) : Comparable { override 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()

Slide 55

Slide 55 text

Example of rangeTo (and ..) function val rangeInt1 : IntRange = 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

Slide 56

Slide 56 text

Combine range with in function fun main() { val rangeInt : IntRange = 1..10 // False println(0 in rangeInt) // True println(1 in rangeInt) // False println(12 in rangeInt) }

Slide 57

Slide 57 text

Progression • Integral type ranges (Int, Long, Char) has extra feature: they are also progressions • Progressions can be iterated over • Progressions have three essential properties • first • last • step

Slide 58

Slide 58 text

For – loop to Kotlin loop for (int i = first; i <= last; i += step) { // ... } for (i in first..last step step) print(i) Traditional loop (not kotlin) Kotlin approach

Slide 59

Slide 59 text

for + in + range val rangeInt : IntRange = 1..10 for(i in rangeInt) { println(i) }

Slide 60

Slide 60 text

for + in + range for(i in 1..10) { println(i) }

Slide 61

Slide 61 text

for + in + range for(i in 1..10 step 2) { println(i) }

Slide 62

Slide 62 text

Control Flow: For – loop using range expression for (i in 6 downTo 0 step 2) { println(i) }

Slide 63

Slide 63 text

Control Flow: "Traditional" approach for arrays for (i in array.indices) { println(array[i]) }

Slide 64

Slide 64 text

Strings

Slide 65

Slide 65 text

Comparing Strings fun main() { val secret = "ken sent me" println("Give password:") val password : String? = readLine() if(password != null) { println(password == secret) println(password === secret) } } translates to equals translates to ==

Slide 66

Slide 66 text

Iterating fun main() { for (c in "hello world") { println(c) } }

Slide 67

Slide 67 text

Concat fun main() { val s = "abc" + 1 println(s + "def") }

Slide 68

Slide 68 text

String templates fun main() { val myarray = arrayOf("Hello", "World") val simpleStr = "again" val str : String = """
  • ${myarray.get(0)}
  • ${myarray.get(1)}
  • $simpleStr
""" println(str) } Can contain expression or a simple value

Slide 69

Slide 69 text

Trim margins fun main() { val myarray = arrayOf("Hello", "World") val simpleStr = "again" val str : String = """ |
    |
  • ${myarray.get(0)}
  • |
  • ${myarray.get(1)}
  • |
  • $simpleStr
  • |
""".trimMargin("|") println(str) } Clears extra whitespaces. "|" is on by default, you can omit that.

Slide 70

Slide 70 text

Arrays

Slide 71

Slide 71 text

Arrays • Arrays are presented by Array – class • 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

Slide 72

Slide 72 text

Creating arrays and collection classes val a : Array = arrayOf(1, 2, 3) val l : List = listOf(1, 2, 3) val m : MutableList = mutableListOf(1, 2, 3)

Slide 73

Slide 73 text

Array fun main() { var t1 : Array = arrayOf(1, 2, 3) println(t1.size) println(t1.get(0)) t1.set(0, 12) t1[0] = 12 println(t1.get(0)) println(t1[0]) }

Slide 74

Slide 74 text

Different methods available fun main() { var t1 : Array = arrayOf(1, 2, 3) println(t1.average()) }

Slide 75

Slide 75 text

Array fun main() { var t1 : Array = arrayOf(1, "hello", 3) println(t1.get(1)) }

Slide 76

Slide 76 text

Lab 04 + 05

Slide 77

Slide 77 text

Functions and Lambdas

Slide 78

Slide 78 text

Functions • Kotlin functions are first-class • passing functions as arguments to other functions • returning functions from frunctions • assigning functions into variables

Slide 79

Slide 79 text

Basic Function fun sum(a : Int, b: Int) : Int { return a + b } fun main() { println(sum(5, 5)) }

Slide 80

Slide 80 text

Basic Function fun sum(a : Int, b: Int) : Int { return a + b } fun main() { println(sum(a = 5, b = 5)) }

Slide 81

Slide 81 text

Any, Unit • Java has Object (root class) and void 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

Slide 82

Slide 82 text

Unit usage fun doIt1() : Unit { println("Hello world") } fun doIt2() { println("Hello world") } fun main() { val a = doIt1() println(a) // kotlin.Unit val b = doIt2() println(b) // kotlin.Unit }

Slide 83

Slide 83 text

Nothing fun iWillAlwaysThrowException() : Nothing { throw Exception("Unnecessary Exception") }

Slide 84

Slide 84 text

Basic function with default arguments fun repeat(text: String, amount: Int = 1) : String { var newString = "" for(i in 1..amount) { newString += text } return newString } fun main() { println(repeat("hello", 10)) } Return type Default value

Slide 85

Slide 85 text

Named arguments fun repeat(text: String, wordSeparator : String = "_", 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

Slide 86

Slide 86 text

Named arguments fun repeat(text: String, wordSeparator : String = "_", 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"

Slide 87

Slide 87 text

Single-expressions fun sum(a : Int, b: Int) : Int = a + b fun main() { println(sum(5,5)) } You can omit { and } and even return if only one line

Slide 88

Slide 88 text

Varargs fun sum(vararg numbers : Int) : Int { var 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

Slide 89

Slide 89 text

infix notation class Person { infix fun drinkBeer(beer: String) { 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

Slide 90

Slide 90 text

Prebuild infix notation fun main() { val progression1 : IntProgression = 6.downTo(0) val progression2 : IntProgression = 6 downTo 0 for(i in progression1) { println(i) } for(i in progression2) { println(i) } for(i in 6 downTo 0) { println(i) } }

Slide 91

Slide 91 text

Local Functions fun main() { fun outer(a: Int) { fun inner(b: Int) : Int { return a + b } println(inner(5)) } outer(5) } local function can access outer functions variables (closure)

Slide 92

Slide 92 text

Lambdas

Slide 93

Slide 93 text

Function Type and Reference fun sum(a : Int, b : Int) : Int = a + b fun main() { var myfun: (Int, Int) -> Int myfun = ::sum println(myfun(4,4)) } Type here is a function Function reference

Slide 94

Slide 94 text

Lambda example fun main() { var myfun: (Int, Int) -> Int myfun = { a, b -> a + b } println(myfun(4,4)) } local function can access outer functions variables (closure)

Slide 95

Slide 95 text

Lambda Example fun readFile(path: String, callback: (data: String, err: String) -> Unit) { callback("some data", "") } fun main() { readFile("file.txt", { data: String, err: String -> if(err.length > 0) { throw Exception("failed") } println(data) }) } Passing lambda

Slide 96

Slide 96 text

Lambda fun readFile(path: String, callback: (data: String) -> Unit) { 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!

Slide 97

Slide 97 text

Lambda with Unit return type fun map(myarray: Array, callback: (item: 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

Slide 98

Slide 98 text

Lambda with Unit return type fun map(myarray: Array, callback: (item: 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

Slide 99

Slide 99 text

Lambda with Unit return type fun map(myarray: Array, callback: (item: Int) -> Int) { for(i in myarray.indices) { myarray[i] = callback(myarray[i]) } } fun main() { val myarray = arrayOf(1,2,3) map( myarray, { item -> item + 1 } ) } Returns Int Lambda returns the last line!

Slide 100

Slide 100 text

Lambda's last line is return fun main() { val myarray = arrayOf(-1, -2, 3, 4, 5) map( myarray, { item -> if(item > 0) { return item + 1 } else { return item -1 } } ) myarray.forEach { println(it) } } Hello.kt:11:13: error: 'return' is not allowed here return item + 1

Slide 101

Slide 101 text

Lambda's last line is return map( myarray, { item -> var returnValue = item - 1 if(item > 0) { returnValue = item + 1 } returnValue } )

Slide 102

Slide 102 text

Example of map - function val list = arrayOf(1, 2) 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)

Slide 103

Slide 103 text

Lab 06

Slide 104

Slide 104 text

OO with Kotlin

Slide 105

Slide 105 text

Simple classes class Dog {} class Cat fun main() { val dog = Dog() val cat = Cat() } If empty body you can omit curly braces

Slide 106

Slide 106 text

Constructors • Class in Kotlin can have • Primary constructor • Secondary constructors • Primary constructor is part of the class header

Slide 107

Slide 107 text

Primary Constructor class Dog constructor(name: String) {} class Cat(name: String) { } 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!

Slide 108

Slide 108 text

init block class Cat(name: String) { var name : String init { println("initializer here!") this.name = name } } fun main() { val cat = Cat("onni") println(cat.name) } init block is executed

Slide 109

Slide 109 text

init block omit class Cat(name: String) { var name : String = name } fun main() { val cat = Cat("onni") println(cat.name) } If only one line, we can do this directly without the need for a block

Slide 110

Slide 110 text

Declaring properties from primary constructor class Cat(var name: String) { } fun main() { val cat = Cat("onni") println(cat.name) } By adding var or val here it will initialize a property!

Slide 111

Slide 111 text

Visibility class Cat private constructor(var name: String) { } fun 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

Slide 112

Slide 112 text

Secondary Constructor class Cat (var name: String) { var age: Int = 0 constructor(name: String, age: Int) : this(name) { this.age = age } } fun main() { val cat = Cat("onni", 3) println(cat.name) println(cat.age) } Secondary constructor must call primary constructor

Slide 113

Slide 113 text

Inheritance

Slide 114

Slide 114 text

Inheritance • All classes inherit superclass Any • class Dog // 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

Slide 115

Slide 115 text

Example open class Person(var name: String) class Programmer(name : String, 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

Slide 116

Slide 116 text

override open class Shape(var x : Int, var y : 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!

Slide 117

Slide 117 text

Abstract class abstract class Shape(var x : Int, var y : 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

Slide 118

Slide 118 text

Example of GUI import javax.swing.*; import java.awt.event.*; class MyWindow(title : String) : JFrame(title), ActionListener { private var button : JButton init { this.button = JButton("Click") add(this.button) } } fun main() { val mywindow = MyWindow("hello world") mywindow.setSize(500,500) mywindow.setVisible(true) }

Slide 119

Slide 119 text

Lab 08

Slide 120

Slide 120 text

Properties and Fields

Slide 121

Slide 121 text

Declaring Getters and Setters class Person { var [: ] [= ] [] [] }

Slide 122

Slide 122 text

Declaring Getters and Setters class Person { var age: Int [] [] }

Slide 123

Slide 123 text

"Traditional approach": backing property class Person { private var _age : Int = 0 var age: Int get() { return this._age } set(value) { this._age = value } } fun main() { var p = Person() p.age = 80 println(p.age) }

Slide 124

Slide 124 text

Using keyword field class Person { var age: Int = 12 get() { return field } } fun main() { var p = Person() println(p.age) } Special keyword field refers to the age here

Slide 125

Slide 125 text

Declaring Getters and Setters class Person { var age: Int get() = field [] } Shorter syntax for returning

Slide 126

Slide 126 text

Declaring Getters and Setters class Person { var age: Int get() = field set(value) { field = value } } Special keyword field refers to the age here

Slide 127

Slide 127 text

Properties must be initialized class Car { var motor: Motor 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

Slide 128

Slide 128 text

lateinit class Car { lateinit var motor: Motor fun start() { this.motor = Motor() this.motor.start() } } fun main() { val c = Car() c.start() } It works now lateinit works only on non-primitive types

Slide 129

Slide 129 text

Lab 08

Slide 130

Slide 130 text

Data Classes

Slide 131

Slide 131 text

Data class data class User(var name: String, var age: Int) 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()

Slide 132

Slide 132 text

Interfaces

Slide 133

Slide 133 text

Example interface Movable { fun move() } class Airplane : Movable { override fun move() { println("Airplane flies") } } class Bird : Movable { override fun move() { println("Bird flies") } } fun main() { var x : Movable = Bird() x.move() }

Slide 134

Slide 134 text

Object Expression with Functional Interfaces interface Movable { fun move() } fun main() { move(object : Movable { override fun move() { println("anonymouse moves") } }) } fun move(movable : Movable) { movable.move() }

Slide 135

Slide 135 text

Swing Example import javax.swing.*; import java.awt.event.*; class MyWindow(title: String) : 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

Slide 136

Slide 136 text

Lab 09

Slide 137

Slide 137 text

Visibility

Slide 138

Slide 138 text

Visibility • Visibility modifiers • private • protected • internal • public • Default modifier is public

Slide 139

Slide 139 text

Packages ├── mypackage1 │ └── MyApp.kt └── mypackage2 └── Util.kt

Slide 140

Slide 140 text

mypackage1/MyApp.kt package mypackage1; import mypackage2.*; fun main() { println(abs(-7)) }

Slide 141

Slide 141 text

mypackage2/Util.kt package mypackage2 // Visible inside of mypackage2/Util.kt private val 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

Slide 142

Slide 142 text

protected open class Person(name : String) { protected var name : String init { this.name = name } } class Programmer(name : String) : Person(name) { fun hello() { println("$name hello") } }

Slide 143

Slide 143 text

internal and module • IntelliJ IDEA module • Maven project • Gradle source set • Set of files compiled with one invocation with Ant

Slide 144

Slide 144 text

Extensions

Slide 145

Slide 145 text

Extensions • Ability to extend a class with new functionality without inheritance • You can write new functionality to third – party libraries (that would not be modifiable) • You can have • extension functions • extension properties

Slide 146

Slide 146 text

Example fun String.isPalindrome() : Boolean = this.reversed() == this fun main() { println( if (readLine()!!.isPalindrome()) "It was palindrome" else "It was not palindrome") } Extension to String class

Slide 147

Slide 147 text

Extending properties val List.lastIndex: Int get() = size - 1 fun main() { var list : List = listOf(1,2,3,4) print(list.lastIndex) }

Slide 148

Slide 148 text

Lab 10 + 11