Download - Kotlin · Kotlin - Interoperability 100% interoperable with Java Calling Java directly from Kotlin and vice versa Can have both in the same project (but not in the same file)

Transcript

KotlinIN2000

Gaute Berge

Slides made by: Erlend Stenlund & Steffen Almås

Kotlin - Intro

● Replacement for Java● Multiplatform● .kt

Kotlin - Hello World

● Top level declaration● No class● println moved to stdlib● Semicolon● fun● Unit vs void● Optional args in main● public is default

public class Hey { public static void main(String[] args) { System.out.println("Hello World!"); }}

fun main() { println("Hello World!")}

Kotlin - Interoperability

● 100% interoperable with Java

● Calling Java directly from Kotlin

○ and vice versa

● Can have both in the same project

(but not in the same file)

Kotlin - Variables

val x = 5var y = "Foo"

x = 6y = "Bar"

Val cannot be reassigned

val x: Int = 5var y: String = "Foo"

Kotlin - Functions

fun hei() { println("Hello World")}

fun hei(): Unit { println("Hello World")}

Kotlin - Functions (cont.)

fun add(x: Int, y: Int): Int { return x + y}

fun add(x: Int, y: Int) = x + y

Standard function declaration

Expression function

Kotlin - Functions: Extension functions

public class StringUtils { public static char middle(String s) { return s.charAt(s.length() / 2); }}

String s = "hello";char mid = StringUtils.middle(s);

fun String.middle() = get(length / 2)

val s = "hello"val mid = s.middle()

Extends the functionality of a class

Kotlin - Jetpack

● Android Jetpack

● Android KTX

Kotlin - Types

● Int

● Double

● Float

● String

● Array<T>

● …

● No primitive types

Kotlin - String Templates

● String Templates are expressions that is evaluated

and concatenated in a String

val s = "abc"println("$s.length is ${s.length}")

>> abc.length is 3

Basert på

https://developer.android.com/training/basics/firstapp/creating-project

Control Flow

Kotlin - if

fun maxOf(a: Int, b: Int): Int { if (a > b) { return a } else { return b }}

fun maxOf(a: Int, b: Int) = if (a > b) a else b

Expression Function

Kotlin - when

when(x) { 0 -> print("Zero") 1 -> print("One") 2 -> print("Two") 3 -> print("Three") 4 -> print("Four") 5 -> print("Five") 6 -> print("Six") 7 -> print("Seven") 8 -> print("Eight") 9 -> print("Nine") else -> { print("What?") }}

● Think Switch Case in Java● Expression; not a statement● Exhaustive matching

Kotlin - for

val items = listOf("IN2000", "is", "cool")

for (item in items) { println(item)}

for ((index, value) in items.withIndex()) { println("$index : $value")}

Kotlin - for (cont.)

for (i in 6 downTo 0 step 2) { println(i)}

>> 6>> 4>> 2>> 0

for (i in 1..3) { println(i)}

>> 1>> 2>> 3

Kotlin - while

val items = listOf("IN2000", "is", "cool")var index = 0

while (index < items.size) { println("item at $index is ${items[index]}") index++}

Basert på

https://developer.android.com/training/basics/firstapp/creating-project

Null safety

Kotlin - Null safety

“ I call it my billion-dollar

mistake. It was the

invention of the null

reference in 1965 ”

- Tony Hoare -

Kotlin - Null safety (cont.)

● What is null?○ Pointer to nothing?

● Where does this fit into the type system?● One of the most common causes of crashes in Java

Kotlin - Nullable types

T?

T

Kotlin - Nullable types (cont.)

val x: String = null

val x: String? = null

Error: Null can not be a value of a non-null type String

Kotlin - Smart casting

val x: String? = null

if (x != null) { println(x.length)}

Kotlin - Smart casting (cont.)

val x: String? = null

if (x == null) { // Can't use members of b in here} else { println(x.length)}

Kotlin - Null safe call operator

x?.foo()

if (x != null) x.foo() else null

x?.foo()?.bar()

Kotlin - Elvis operator (null default operator)

val z = x ?: y

Kotlin - Non-null assertion

x!!

x ?: throw NullPointerException()

Basert på

https://developer.android.com/training/basics/firstapp/creating-project

Collections

Kotlin - Standard collections

Immutable MutableList<T> MutableList<T>

Set<T> MutableSet<T>

Map<K, V> MutableMap<K, V>

Array<T>

Kotlin - Standard collections (cont.)

Immutable MutablelistOf() mutableListOf()

setOf() mutableSetOf()

mapOf() mutableMapOf()

arrayOf()

Kotlin - Collection interfaces

https://kotlinlang.org/docs/reference/collections-overview.html

Basert på

https://developer.android.com/training/basics/firstapp/creating-project

Classes and Objects

Kotlin - Class

class Person { val age = 10}

val person = Person()println(person.age)

>> 10

Kotlin - Class: Constructors

● Primary constructor

● Secondary constructor

● Primary constructor with properties

● init block

Kotlin - Class: Secondary Constructor

class Person { val age: Int constructor(age: Int) { this.age = age }}

Kotlin - Class: Primary Constructor

class Person(age: Int) { val age: Int = age}

Kotlin - Class: Primary Constructor with property

● Fields in primary constructor● No need for getters and setters

class Person(val age: Int)

Kotlin - Class: Init

● Init will run when object is created● Can have multiple init blocks● Can be used for complicated initialization logic

class Person(val age: Int) { init { println("Creating person with age: $age") }}

public class Person {

private String name; private int age;

public Person(String name, int age) { this.name = name; this.age = age; }

public String getName() { return name; }

public void setName(String name) { this.name = name; }

public int getAge() { return age; }

public void setAge(int age) { this.age = age; }

@Override public String toString() { return "Person{" + "name='" + name + '\'' + ", age=" + age + '}'; }

@Override public boolean equals(Object o) { if (this == o) return true; if (o == null || getClass() != o.getClass()) return false; Person person = (Person) o; return age == person.age && Objects.equals(name, person.name); }

@Override public int hashCode() { return Objects.hash(name, age); }}

Kotlin - POJO Class

Kotlin - Data Class

data class Person(var name: String, var age: Int)

Kotlin - Getters and Setters

● Why do we have them in Java?● Encapsulation● Auto-generated, but also customizable

var stringRepresentation: Stringget() = this.toString()set(value) {

setDataFromString(value) }

Kotlin - Getters and Setters interoperability

public class Person {

private String name;

public Person(String name) {this.name = name;

}

public String getName() {return name;

}

public void setName(String name) {

this.name = name;}

}

val person = Person("Alice")

person.name // Same as person.getName()

person.name = "Bob" // Same as person.setName("Bob")

Kotlin - Inheritance

● : both used for extends and implements

● Classes and fields are final by default

● Uses primary constructor instead of super() when extending

open class Base(p: Int)

class Derived(p: Int) : Base(p)

Kotlin - Inheritance (cont.)

● override is a keyword

open class Shape { open fun draw() { /*...*/ } fun fill() { /*...*/ }}

class Circle() : Shape() { override fun draw() { /*...*/ }}

Kotlin - Abstract class and Interface

● Same as Java :)

Kotlin - Sealed classes

● An abstract class with known inheritors

● Exhaustive matching with when

sealed class Exprdata class Const(val number: Double) : Expr()data class Sum(val e1: Expr, val e2: Expr) : Expr()object NotANumber : Expr()

Kotlin - Objects

● Used to create Singletons● Managing state● Lazily initialized

object DataProviderManager { fun registerDataProvider(provider: DataProvider) { // ... }

val allDataProviders: Collection<DataProvider> get() = // ...}

Kotlin - Companion Objects

Object declared inside a class

class MyClass { companion object { fun create(): MyClass = MyClass() }}

val instance = MyClass.create() Called like this

● Alternative to static

Kotlin - Nested Class

Classes can be nested into other classes

class Outer { private val bar: Int = 1 class Nested { fun foo() = 2 }}

val demo = Outer.Nested().foo()

>> 2

Kotlin - Inner Class

An inner class can access members of its outer class

class Outer { private val bar: Int = 1 inner class Inner { fun foo() = bar }}

val demo = Outer().Inner().foo()

>> 1

Kotlin - Anonymous Objects

● Made with the use of Object Expression● Used a lot in Android Studio

○ For instance: onClickListener()

window.addMouseListener(object : MouseAdapter() {

override fun mouseClicked(e: MouseEvent) { ... }

override fun mouseEntered(e: MouseEvent) { ... }})

Kotlin - Enums

● Class with known possible values● Type-safety

enum class Direction { NORTH, SOUTH, WEST, EAST}

Kotlin - Why we need enums

fun move(pos: Pair<Int, Int>, direction: String) = when (direction) { "NORTH" -> pos.first to pos.second+1 "SOUTH" -> pos.first to pos.second-1 "WEST" -> pos.first-1 to pos.second "EAST" -> pos.first+1 to pos.second }

‘when’ expression must be exhaustive, add necessary ‘else’ branch

Kotlin - Why we need enums (cont.)

fun move(pos: Pair<Int, Int>, direction: String) = when (direction) { "NORTH" -> pos.first to pos.second+1 "SOUTH" -> pos.first to pos.second-1 "WEST" -> pos.first-1 to pos.second "EAST" -> pos.first+1 to pos.second else -> throw IllegalArgumentException() }

Kotlin - Why we need enums (cont.)

fun move(pos: Pair<Int, Int>, direction: Direction) = when (direction) { Direction.NORTH -> pos.first to pos.second+1 Direction.SOUTH -> pos.first to pos.second-1 Direction.WEST -> pos.first-1 to pos.second Direction.EAST -> pos.first+1 to pos.second }

enum class Direction { NORTH, SOUTH, WEST, EAST}

Kotlin - Enums with properties

enum class Color(val rgb: Int) { RED(0xFF0000), GREEN(0x00FF00), BLUE(0x0000FF)}

Basert på

https://developer.android.com/training/basics/firstapp/creating-project

Operator overloading and destructuring

Kotlin - Operator overloading

● Defines what an operator cando for other types

● Looks after a function that is modified

● unaryMinus() → unary negation function

data class Point(val x: Int, val y: Int)

operator fun Point.unaryMinus() = Point(-x, -y)

val point = Point(10, 20)

fun main() { println(-point)}

>> Point(x=-10, y=-20)

Kotlin - Destructuring

● Convenient syntax● Often used in loops

val (name, age) = person

val name = person.component1()val age = person.component2()

val name = person.nameval age = person.age

Basert på

https://developer.android.com/training/basics/firstapp/creating-project

Functional Kotlin

Functional - What is functional programming?

● A paradigm

● Style

● Focus on functions

● Higher orders functions

● Immutable values

Functional - Functional languages

● ML

○ Haskell

○ Elm

● Lisp

○ Clojure

● Multi Paradigm

○ Kotlin

○ Scala

Kotlin - Functional programming

“ [...] functional programming can be viewed as a style of programming in which the basic method of computation is the application of functions to arguments.”

- Hutton, Graham (2005). Programming in Haskell.

Functional - In general

● Function as a value○ Higher order functions

● Pure functions○ No side effects

● Anonymous functions (lambda)

● Function composition

Programming without side-effects

● How do we change a value?

● Make a new one!

● What about more complex data structures?

var x = 5x += 1

val x = 5val y = x + 1

Without side-effectsWith side-effects

Functional Kotlin - In this course

● Functional in the LARGE○ Managed effects

○ Monads

● Functional in the SMALL

○ Higher order functions

○ Limited mutations

● We program functional in the SMALL

Kotlin - Higher Order Function

● Takes a function as a parameter

fun repeat(times: Int, action: (Int) -> Unit)

repeat(3) { println("Hello")}

>> Hello>> Hello>> Hello

repeat(0) { error("We should not get here!")}

>>

Kotlin - Lambda Expressions

val add: (Int, Int) -> Int = { x: Int, y: Int -> x + y }

val add = { x, y -> x + y } Without annotations

● Arguments and body are separated with an arrow● Annotations are optional● Can span multiple lines● Return value is the last expression in the body

Kotlin - Lambda type signature

● (Int) -> String

● Parameters in parentheses

● Return-type after arrow (→)

● Read as “from Int to String”

● val onClick: () -> Unit

● val add: (Int, Int) -> Int

Kotlin - Trailing lambdas

Can place lambda outside argument list

f(x, {...})

f(x) {...}

g {...}

Kotlin - it

Implicit single argument

{ x -> x}

{ it }

Kotlin - Working with Immutable Lists

fun squareList(items: List<Int>): List<Int> { val newItems = mutableListOf<Int>() for (item in items) { newItems += item * item } return newItems}

squareList(listOf(1, 2, 3))

>> [1, 4, 9]

Kotlin - Working with Immutable Lists (cont.)

listOf(1, 2, 3).map { it * it }

>> [1, 4, 9]

Kotlin - Map Filter Fold

listOf(1, 2, 3).map { it + 1 }

>> [2, 3, 4]

listOf(1, 2, 3).filter { it % 2 == 0 }

>> [2]

listOf(1, 2, 3).fold(1) { acc, e -> acc * e }

>> 6

Kotlin - Map Filter Fold (cont.)

val sumSquareEven = items .map { it * it } .filter { it % 2 == 0 } .fold(0) { a, v -> a + v }

Kotlin - Map Filter Fold (cont.)

val square = { x: Int -> x * x }val isEven = { x: Int -> x % 2 == 0 }val sumSquareEven = items .map(square) .filter(isEven) .fold(0, Int::plus) // or just sum()

Kotlin - Map Filter Fold (type signatures)

fun <T, R> Iterable<T>.map(transform: (T) -> R): List<R>

fun <T> Iterable<T>.filter(predicate: (T) -> Boolean): List<T>

fun <T, R> Iterable<T>.fold(initial: R, operation: (acc: R, T) -> R): R

Kotlin - Arrow

Functional programmering @ UiO

● IN2040 – Functional programming

● INF3110 – Programming Languages

Basert på

https://developer.android.com/training/basics/firstapp/creating-project

Scope functions

Kotlin - Scope functions

● Execute a block of code within a context

● Let● Run● With● Apply● Also

Kotlin - let

● The context object is available as an argument (it)● The return value is the lambda result● Useful in combination with ?.

fun <T, R> T.let(block: (T) -> R): R

val str: String? = "Hello"val length = str?.let { println("calculating length of $it") it.length}

Kotlin - run

● The context object is available as a receiver (this)● The return value is the lambda result

fun <T, R> T.run(block: T.() -> R): R

val str: String? = "Hello"val length = str?.run { println("calculating length of $this") length}

Kotlin - with

● The context object is passed as an argument ● Available as a receiver (this) inside the lambda● Return value is the lambda result

with (person) { println("Name: $name") println("Age: $age")}

fun <T, R> with(receiver: T, block: T.() -> R): R

Kotlin - apply

● The context object is available as a receiver (this)● The return value is the object itself

fun <T> T.apply(block: T.() -> Unit): T

val adam = Person("Clark").apply { age = 32 city = "Denver"}

Kotlin - also

● The context object is available as an argument (it)● The return value is the object itself

fun <T> T.also(block: (T) -> Unit): T

val numbers = mutableListOf("one", "two", "three")numbers .also { println("Elements before adding: $it") } .add("four")

>> Elements before adding: [one, two, three]

Kotlin - Scope functions overview

Kotlin - Flowchart

Source: https://medium.com/@elye.project/mastering-kotlin-standard-functions-run-with-let-also-and-apply-9cd334b0ef84

Basert på

https://developer.android.com/training/basics/firstapp/creating-project

Summary

Kotlin - Summary

● Forces you to make better decisions

○ Mutability

○ open, override, sealed classes

○ exhaustive matching

● Null safety

● Expression based

● Supports a functional style

Kotlin

Slides and examples are based on the official Kotlin documentation

https://kotlinlang.org/docs/reference/