Upgrade to Pro — share decks privately, control downloads, hide ads and more …

Kotlin Language

Kotlin Language

Introduction to Kotlin Language.

D9e65f4b0af059ae9ba243c8c2265e4f?s=128

Jussi Pohjolainen

December 16, 2020
Tweet

Transcript

  1. Kotlin Language Jussi Pohjolainen

  2. Kotlin • Cross-platform, statically typed, general-purpose programming language • Designed

    to interoperate with Java and JVM
  3. 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
  4. Why Kotlin? • Less code • Safe (null pointer exceptions)

    • Interoperable (JVM Support) • Tool friendly, choose any Java IDE or command line
  5. 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
  6. Tools

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

    kotlinc Hello.kt $ java HelloKt Hello World!
  9. $ cat Hello.kt fun main(args: Array<String>) { 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
  10. 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.*
  11. $ 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
  12. 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 }
  13. Easier running $ cat Hello.kt fun main(args: Array<String>) { println("Hello

    World!") } $ kotlinc Hello.kt $ kotlin HelloKt Hello World! Kotlin generates HelloKt named class
  14. 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
  15. Tree tree . ├── Main.kt └── Util.kt 0 directories, 2

    files These are in root!
  16. 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
  17. Lab 01

  18. Quick Intro to Basics

  19. 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.
  20. Integer Numbers https://kotlinlang.org/docs/reference/basic-types.html

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

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

    1.0f // Double val oneDouble : Double = oneFloat.toDouble() } Use methods to make the cast
  25. 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?
  26. 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 ...
  27. 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()) }
  28. 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"
  29. fun main() { val value : Double = Math.random() val

    embed = "random = $value" val list = """ <ul> <li>Hello</li> </ul> """ println(list) println(embed) println(embed[0]) }
  30. 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
  31. Nullable

  32. 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?
  33. Problem 1: val vs var fun main() { val oneInt

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

    : Int? = 1 oneInt = null } Now internal type is Integer (object)
  35. 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?
  36. 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)
  37. 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 ..)
  38. 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!
  39. 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!
  40. 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
  41. 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
  42. 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!
  43. 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
  44. 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
  45. Lab 02

  46. Control Flow

  47. 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 }
  48. Control Flow: switch case, when when (x) { 1 ->

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

    == 0 or x == 1") else -> print("otherwise") }
  50. 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)
  51. Control Flow: while var i = 0 while(i < 10)

    { println(i) i++ }
  52. Control Flow: For - loop val myarray : Array<Int> =

    arrayOf(1,2,3) for(item in myarray) { println(item) } Must provide iterator
  53. 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
  54. Custom Range class Person(var weight: Int) : Comparable<Person> { 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()
  55. 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
  56. 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) }
  57. 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
  58. 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
  59. for + in + range val rangeInt : IntRange =

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

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

    { println(i) }
  62. Control Flow: For – loop using range expression for (i

    in 6 downTo 0 step 2) { println(i) }
  63. Control Flow: "Traditional" approach for arrays for (i in array.indices)

    { println(array[i]) }
  64. Strings

  65. 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 ==
  66. Iterating fun main() { for (c in "hello world") {

    println(c) } }
  67. Concat fun main() { val s = "abc" + 1

    println(s + "def") }
  68. String templates fun main() { val myarray = arrayOf("Hello", "World")

    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
  69. Trim margins fun main() { val myarray = arrayOf("Hello", "World")

    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.
  70. Arrays

  71. 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
  72. Creating arrays and collection classes val a : Array<Int> =

    arrayOf(1, 2, 3) val l : List<Int> = listOf(1, 2, 3) val m : MutableList<Int> = mutableListOf(1, 2, 3)
  73. Array<Int> fun main() { var t1 : Array<Int> = 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]) }
  74. Different methods available fun main() { var t1 : Array<Int>

    = arrayOf(1, 2, 3) println(t1.average()) }
  75. Array<Any> fun main() { var t1 : Array<Any> = arrayOf(1,

    "hello", 3) println(t1.get(1)) }
  76. Lab 04 + 05

  77. Functions and Lambdas

  78. Functions • Kotlin functions are first-class • passing functions as

    arguments to other functions • returning functions from frunctions • assigning functions into variables
  79. Basic Function fun sum(a : Int, b: Int) : Int

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

    { return a + b } fun main() { println(sum(a = 5, b = 5)) }
  81. 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
  82. 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 }
  83. Nothing fun iWillAlwaysThrowException() : Nothing { throw Exception("Unnecessary Exception") }

  84. 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
  85. 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
  86. 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"
  87. 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
  88. 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
  89. 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
  90. 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) } }
  91. 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)
  92. Lambdas

  93. 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
  94. 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)
  95. 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
  96. 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!
  97. Lambda with Unit return type fun map(myarray: Array<Int>, 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
  98. Lambda with Unit return type fun map(myarray: Array<Int>, 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
  99. Lambda with Unit return type fun map(myarray: Array<Int>, 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!
  100. 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
  101. Lambda's last line is return map( myarray, { item ->

    var returnValue = item - 1 if(item > 0) { returnValue = item + 1 } returnValue } )
  102. 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)
  103. Lab 06

  104. OO with Kotlin

  105. Simple classes class Dog {} class Cat fun main() {

    val dog = Dog() val cat = Cat() } If empty body you can omit curly braces
  106. Constructors • Class in Kotlin can have • Primary constructor

    • Secondary constructors • Primary constructor is part of the class header
  107. 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!
  108. 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
  109. 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
  110. 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!
  111. 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
  112. 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
  113. Inheritance

  114. 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
  115. 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
  116. 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!
  117. 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
  118. 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) }
  119. Lab 08

  120. Properties and Fields

  121. Declaring Getters and Setters class Person { var <propertyName>[: <PropertyType>]

    [= <property_initializer>] [<getter>] [<setter>] }
  122. Declaring Getters and Setters class Person { var age: Int

    [<getter>] [<setter>] }
  123. "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) }
  124. 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
  125. Declaring Getters and Setters class Person { var age: Int

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

    get() = field set(value) { field = value } } Special keyword field refers to the age here
  127. 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
  128. 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
  129. Lab 08

  130. Data Classes

  131. 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()
  132. Interfaces

  133. 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() }
  134. 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() }
  135. 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
  136. Lab 09

  137. Visibility

  138. Visibility • Visibility modifiers • private • protected • internal

    • public • Default modifier is public
  139. Packages ├── mypackage1 │ └── MyApp.kt └── mypackage2 └── Util.kt

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

  141. 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
  142. 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") } }
  143. internal and module • IntelliJ IDEA module • Maven project

    • Gradle source set • Set of files compiled with one invocation <kotlinc> with Ant
  144. Extensions

  145. 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
  146. 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
  147. Extending properties val <T> List<T>.lastIndex: Int get() = size -

    1 fun main() { var list : List<Int> = listOf(1,2,3,4) print(list.lastIndex) }
  148. Lab 10 + 11