Kotlin

Next level of Android Development

Kotlin history

Why JebBrains needed Kotlin?

2012 - 2015

2010

2011

2012

JetBrains unveiled Kotlin

Start Development

Open sourced

Development

Feb 2016

Mar 2018

Kotlin 1.1

Feb 2016

May 2016

May 2018

Official Android Support

Safeness

Language safeness - more errors can be prevented by checks at compile time instead of falling at run time. Also language is referred as safe when it is promoting way of coding that is know as more secure.

Billion-dollar mistake

Sir Charles Hoare

"This has led to innumerable errors, vulnerabilities, and system crashes, which have probably caused a billion dollars of pain and damage in the last forty years."

Null safety

var person: Person

Must be inilialized

var person: Person = null

Not null type cannot be null

var person: Person? = null

? after type makes it nullable

person.name

Nullable must be unpacked

Null safety

person?.name

Safe call (null if person is null)

person!!.name

Unsafe call (exception if person is null)

if(person != null) {
    person.name
}

Smart Cast (after nullability check, object is casted to not-null)

if(person == null)
    return

person.name
if(person != null && person.name == "Marcin")
if(person == null || person.age < 18)

Elvis operator

val name = person?.name ?: "unknown"
val name = person?.name ?: throw Error("No person or name is null")
val name = person?.name ?: return

Read-only properties

val name: String = "Marcin"

Read only

var name: String = "Marcin"

Read-write

val list = listOf("A", "B", "C")

val name: String by lazy { getNameFromForm() }

Read-only properties

MutableList

Mutable

List

Immutable

var list = listOf("A", "B", "C")
list += "D"
list -= "A"
val list = mutableListOf("A", "B", "C")
list.add("D")
list.remove("A")

Object-Oriented

Kotlin

Classes

Classes

// Java
public class PersonJava {
   private String name;
   private String surname;
   private int age;

   PersonJava(String name, String surname, int age) {
       this.setName(name);
       this.setSurname(surname);
       this.setAge(age);
   }

   public String getName() {
       return name;
   }

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

   public String getSurname() {
       return surname;
   }

   public void setSurname(String surname) {
       this.surname = surname;
   }

   public int getAge() {
       return age;
   }

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

Classes

class Person {
    var name: String
    var surname: String
    var age: Int

    constructor(name: String, surname: String, age: Int) {
        this.name = name
        this.surname = surname
        this.age = age
    }
}
class Person(name: String, surname: String, age: Int) {
    var name: String = name
    var surname: String = surname
    var age: Int = age
}
class Person(var name: String, var surname: String, var age: Int)

Classes

// Kotlin
class Person(
    var name: String, 
    var surname: String, 
    var age: Int
)
// Java
public class PersonJava {
   private String name;
   private String surname;
   private int age;

   PersonJava(String name, String surname, int age) {
       this.setName(name);
       this.setSurname(surname);
       this.setAge(age);
   }

   public String getName() {
       return name;
   }

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

   public String getSurname() {
       return surname;
   }

   public void setSurname(String surname) {
       this.surname = surname;
   }

   public int getAge() {
       return age;
   }

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

Data Classes

data class Person(
    var name: String, 
    var surname: String, 
    var age: Int
)
  • toString
  • equals / hashCode
  • copy
class Person(
    var name: String, 
    var surname: String, 
    var age: Int
)

Data Classes - toString

val person = Person("Johny", "Bravo", 34)
println(person)

normal classs: Person@5305068a

data class:        Person(name=Johny, surname=Bravo, age=34)

Data Classes - equals

val person1 = Person("Johny", "Bravo", 21)
val person2 = Person("Johny", "Bravo", 21)
println(person1 == person2)

Java default behaviour: false

Kotlin data class behaiour: true

Data Classes - copy

val person1 = Person("Johny", "Bravo", 21)
val person2 = person1.copy(surname = "Cage")
println(person1)
println(person2)

Prints:

Person(name=Johny, surname=Bravo, age=21)

Person(name=Johny, surname=Cage, age=21)

val person1 = Person("Johny", "Bravo", 21)
val person2 = person1.copy()
println(person1)
println(person2)

Prints:

Person(name=Johny, surname=Bravo, age=21)

Person(name=Johny, surname=Bravo, age=21)

Conciseness and

code reusability

Java Utils hell

Java Utils hell

Arrays.asList(1,2,3);
listOf(1,2,3)
List<Integer> list = new ArrayList();
list.add(1);
list.add(2);
list.add(3);

Java Utils hell

view.visibility = View.GONE
view.hide()
ViewUtils.hide(view)

Java Utils hell

val replacedStr = StringUtils.replaceAll(str, "name" to name, "surname" to surname)
val capitalizedStr = StringUtils.capitalize(replacedStr)
str.replaceAll("{name}" to name, "{surname}" to surname)
    .capitalize()

Functions everywhere

fun double(i: Int) = i * 2

class A() {

    fun triple(i: Int) = i * 3

    fun twelveTimes(i: Int): Int {
        fun fourTimes() = double(double(i))
        return triple(fourTimes())
    }
}


fun main(args: Array<String>) {
    double(1) // 2
    A().twelveTimes(2) // 24
}

Top-level function

Mamber function

Local function

Kotlin extension functions

fun String.noLongerThen(max: Int): String {
    return this.substring(0, Math.min(max, this.length))
}

fun main(args: Array<String>) {
    println("Joe".noLongerThen(4)) // Joe
    println("James".noLongerThen(4)) // Jame
    println("Ashley".noLongerThen(4)) // Ashl
}
fun View.hide() {
    this.visibility = View.GONE
}

Kotlin extension properties

val Context.inflater
   get() = getSystemService(Context.LAYOUT_INFLATER_SERVICE) as LayoutInflater
var View.isVisible: Boolean
    get() = visibility == View.VISIBLE
    set(value) {
        visibility = if (value) View.VISIBLE else View.GONE
    }
context.inflater
progress.isVisible = true

Higher level of code extraction

fun sum(a: Int, b: Int): Int {
    var sum = 0
    for (i in a..b) {
        sum += i
    }
    return sum
}

fun product(a: Int, b: Int): Int {
    var product = 1
    for (i in a..b) {
        product *= i
    }
    return product
}

Higher level of code extraction

fun sum(a: Int, b: Int) = fold(a, b, 0, { acc, i -> acc + i })

fun product(a: Int, b: Int) = fold(a, b, 1, { acc, i -> acc * i })

fun fold(a: Int, b: Int, initial: Int, operation: (Int, Int)->Int): Int {
    var acc = initial
    for (i in a..b) {
        acc = operation(acc, i)
    }
    return acc
}
inline fun <T, R> Iterable<T>.map(transform: (T) -> R): List<R> {
   val destination = ArrayList<R>()
   for (item in this) destination.add(transform(item))
   return destination
}

inline fun <T> Iterable<T>.filter(predicate: (T) -> Boolean): List<T> {
   val destination = ArrayList<T>()
   for (item in this) if(predicate(item)) destination.add(item)
   return destination
}

...

Collection stream processing

"This is Sparta".map { it.toUpperCase() }.toString() // THIS IS SPARTA

Collection stream processing

//Imperative
val filteredList = arrayListOf<String>()
for (fruit in list) {
    if (fruit.startsWith('A'))
        filteredList.add(fruit)
}

Collection stream processing

//Declatative
val filteredList = list.filter{ it.startsWith("A")}
val list = listOf("Apple", "Lemon", "Avocado")

Collection stream processing

val filteredList = students.filter { it.passing }
                     .filter { it.averageGrade > 4.0 && it.averageGrade <= 4.5 }
                     .sortedBy { it.averageGrade }
                     .take(10)

Collection stream processing

val str = list.joinToString("|", "(", ")", 2, "...", { it.toUpperCase() })
    
val str = list.joinToString(separator = "|")

Result: Apple|Lemon|Avocado

val str = list.joinToString(separator = "|", prefix = "(", postfix = ")")

Result: (Apple|Lemon|Avocado)

val str = list.joinToString(separator = "|", transform = { it.toUpperCase() })

Result: APPLE|LEMON|AVOCADO

Collection sorting

val personList: List<Person> = listOf()
//...
val sortedList = personList.sortedWith(compareBy({ it.age }, { it.name }, { it.surname }))
val sortedList = personList.sortedWith(compareBy(Person::age, Person::name, Person::surname))
val sortedList = personList.sortedBy { it.name }

Multiplatfom development

https://github.com/MarcinMoskala/KotlinAcademyApp

Native development

Native bytecode

We can easily use all platform-specific libraries and solutions

We use native libraries and solutions like OpenGL or GLES

Let's start using Kotlin

Website

IDE

Android

Studio

Intellij

Idea

Eclipse

CLion

IDE

Interoperability

Project

Java 2 Kotlin Converter

  • Whole classes
  • Paste code

References

kotlin-academy.com

Resources

References

Getting started with Kotlin on Android  

https://developer.android.com/kotlin/get-started.html

 

Kotlin language reference

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

 

Kotlin Koans

https://kotlinlang.org/docs/tutorials/koans.html 

Any questions?

@igorwojda

igor.wojda@gmail.com

@marcinmoskala

marcinmoskala@gmail.com

Made with Slides.com