План• О Kotlin
• Основные фичи
• Kotlin для
• Ресурсы
• Вопросы
2
План• О Kotlin
• Основные фичи
• Kotlin для
• Ресурсы
• Вопросы
3
О Kotlin• Прагматичный
• Выразительный
• Безопасный
• 100% совместим с Java
• Статически типизированный
• Мультипарадигмальный
4
О Kotlin• Прагматичный
• Выразительный
• Безопасный
• 100% совместим с Java
• Статически типизированный
• Мультипарадигмальный
5
Прагматичный
6
• Не исследовательский язык
• Не принуждает использовать определённую парадигму или стиль
• Нацелен на инструментарий (IDE)
Выразительныйpublic class HelloCodingMonday {
public static void main(String[] args) { System.out.println("Hello, Coding Monday!"); }
}
7
Выразительныйfun main (args: Array<String>) { println("Hello, Coding Monday!") }
8
Выразительныйpublic int sum(int a, int b) { return a+b; }
9
Выразительный
10
fun sum(a:Int, b:Int): Int { return a+b }
Выразительный
11
fun sum(a:Int, b:Int): Int = a+b
Выразительный
12
fun sum(a:Int, b:Int) = a+b
Выразительныйpublic class Cat { String name; int age; }
13
Выразительныйpublic class Cat { private String name; private int age; }
14
Выразительныйpublic class Cat { private String name; private int 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; } }
15
Cat cat = new Cat(); cat.setName("Meow"); cat.setAge(1);
Cat cat = new Cat("Meow", 1);
Выразительныйpublic class Cat { private String name; private int age;
public Cat(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; } }
16
Выразительный
17
class Cat(var name: String?, var age: Int)
Безопасный
18
• NullPointerException
• ClassCastException
Безопасный
19
• NullPointerException
• ClassCastException
Безопасный
20
var s1:String = "Hello, Coding Monday"
Безопасный
21
var s1:String = "Hello, Coding Monday"
println(s1.toUpperCase()) // Всё ок
Безопасный
22
var s1:String = "Hello, Coding Monday"
println(s1.toUpperCase()) // Всё ок
s1 = null // Ошибка компиляции
Безопасный
23
var s2:String? = null
Безопасный
24
var s2:String? = "Hello, Coding Monday"
println(s2.toUpperCase()) // Ошибка компиляции
Безопасный
25
var s2:String? = "Hello, Coding Monday"
println(s2?.toUpperCase()) // Всё ок
Безопасный
26
var s2:String? = "Hello, Coding Monday"
println(s2?.toUpperCase()) // Всё ок
println(null)
Безопасный
27
var s2:String? = "Hello, Coding Monday"
println(s2?.toUpperCase()) // Всё ок
println(null)
if (s2 != null) { println(s2.toUpperCase()) // Всё ок }
Безопасныйpublic void onClick(View view) { if (view instanceof TextView) { ((TextView) view).setText("Hello, Coding Monday!"); } }
28
Безопасный
29
fun onClick(view: View) { if (view is TextView) { view.text = "Hello, Coding Monday!" } }
100% совместим с Java
30
• Любой код на Java доступен в Kotlin
• Работает в обе стороны
• Код на Kotlin и Java в одном проекте
• Использует стандартную библиотеку Java
План• О Kotlin
• Основные фичи
• Kotlin для
• Ресурсы
• Вопросы
31
Основные фичи• Выведение типов • Значения по умолчанию • Именованные параметры
• Data классы
• Деструктуризация
• Функции расширения
• Инфиксные функции
• Свойства (атрибуты)
• Лямбды
• Лямбда-ресиверы
• when, if
32
Выведение типовpublic class BookCafe {
public void takeCoffee(int count) { // реализация }
}
33
Выведение типовclass BookCafe {
fun takeCoffee(count: Int): Unit { // реализация }
}
34
Выведение типовclass BookCafe {
fun takeCoffee(count: Int) { // реализация }
}
35
Выведение типовpublic class HelloCodingMonday {
public static void main(String[] args) { int a = 1; int b = 2; int c = a + b; }
}
36
Выведение типовfun main (args: Array<String>) { var a: Int = 1 var b: Int = 2 var c: Int = a + b }
37
Выведение типовfun main (args: Array<String>) { var a = 1 var b = 2 var c = a + b }
38
Основные фичи• Выведение типов • Значения по умолчанию • Именованные параметры
• Data классы
• Деструктуризация
• Функции расширения
• Инфиксные функции
• Свойства (атрибуты)
• Лямбды
• Лямбда-ресиверы
• when, if
39
Значения по умолчаниюclass BookCafe {
fun takeCoffee(count: Int) { // реализация }
}
40
// Где-то в коде val bookCafe = BookCafe() bookCafe.takeCoffee(3)
Значения по умолчаниюclass BookCafe {
fun takeCoffee(count: Int = 1) { // реализация }
}
41
// Где-то в коде val bookCafe = BookCafe() bookCafe.takeCoffee(3)
Значения по умолчаниюclass BookCafe {
fun takeCoffee(count: Int = 1) { // реализация }
}
42
// Где-то в коде val bookCafe = BookCafe() bookCafe.takeCoffee() // по умолчанию count = 1
Основные фичи• Выведение типов • Значения по умолчанию • Именованные параметры
• Data классы
• Деструктуризация
• Функции расширения
• Инфиксные функции
• Свойства (атрибуты)
• Лямбды
• Лямбда-ресиверы
• when, if
43
Именованные параметрыclass BookCafe {
fun takeCoffee(count: Int = 1, milk: Boolean = false) { // реализация }
}
44
// Где-то в коде val bookCafe = BookCafe() bookCafe.takeCoffee(true) // Ошибка компиляции
Именованные параметрыclass BookCafe {
fun takeCoffee(count: Int = 1, milk: Boolean = false) { // реализация }
}
45
// Где-то в коде val bookCafe = BookCafe() bookCafe.takeCoffee(milk = true) // count = 1
Основные фичи• Выведение типов • Значения по умолчанию • Именованные параметры
• Data классы
• Деструктуризация
• Функции расширения
• Инфиксные функции
• Свойства (атрибуты)
• Лямбды
• Лямбда-ресиверы
• when, if
46
Data классыpublic class Cat { private String name; private int age;
public Cat(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; } }
47
Data классыpublic class Cat { private final String name; private final int age;
public Cat(String name, int age) { this.name = name; this.age = age; }
public String getName() { return name; }
public int getAge() { return age; } }
48
Data классыpublic class Cat { private final String name; private final int age;
public Cat(String name, int age) { this.name = name; this.age = age; }
public String getName() { return name; }
public int getAge() { return age; } @Override public boolean equals(Object o) { if (this == o) return true; if (o == null || getClass() != o.getClass()) return false; Cat cat = (Cat) o; if (age != cat.age) return false; return name != null ? name.equals(cat.name) : cat.name == null; } }
49
Data классыpublic class Cat { private final String name; private final int age;
public Cat(String name, int age) { this.name = name; this.age = age; }
public String getName() { return name; }
public int getAge() { return age; } @Override public boolean equals(Object o) { if (this == o) return true; if (o == null || getClass() != o.getClass()) return false; Cat cat = (Cat) o; if (age != cat.age) return false; return name != null ? name.equals(cat.name) : cat.name == null; } @Override public int hashCode() { int result = name != null ? name.hashCode() : 0; result = 31 * result + age; return result; } }
50
Data классыpublic class Cat { private final String name; private final int age;
public Cat(String name, int age) { this.name = name; this.age = age; }
public String getName() { return name; }
public int getAge() { return age; } @Override public boolean equals(Object o) { if (this == o) return true; if (o == null || getClass() != o.getClass()) return false; Cat cat = (Cat) o; if (age != cat.age) return false; return name != null ? name.equals(cat.name) : cat.name == null; } @Override public int hashCode() { int result = name != null ? name.hashCode() : 0; result = 31 * result + age; return result; }
@Override public String toString() { return “Cat(" + "name='" + name + '\'' + ", age=" + age + ‘)'; } }
51
Data классы
52
data class Cat(val name: String?, val age: Int)
Основные фичи• Выведение типов • Значения по умолчанию • Именованные параметры
• Data классы
• Деструктуризация
• Функции расширения
• Инфиксные функции
• Свойства (атрибуты)
• Лямбды
• Лямбда-ресиверы
• when, if
53
Деструктуризацияval cat = Cat("Meow", 3) val (name, age) = cat
println("name = " + name) println("age = " + age)
54
component1() component2()
Деструктуризацияval cat = Cat("Meow", 3) val (name, age) = cat
println("name = " + name) println("age = " + age)
55
name = Meow age = 3
component1() component2()
Деструктуризацияval map = mapOf("One" to 1, "Two" to 2, "Three" to 3) for ((key, value) in map) { println(key + " = " + value)}
56
One = 1 Two = 2 Three = 3
Основные фичи• Выведение типов • Значения по умолчанию • Именованные параметры
• Data классы
• Деструктуризация
• Функции расширения
• Инфиксные функции
• Свойства (атрибуты)
• Лямбды
• Лямбда-ресиверы
• when, if
57
Функции расширенияfun ImageView.loadUrl(url: String) { Picasso.with(context).load(url).into(this) }
58
override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) ...
val img = findViewById(R.id.photo) as ImageView img.loadUrl("http://placekitten.com/g/200/300") }
Функции расширения
59
public final class ImageUtil { public static final void loadUrl(@NotNull ImageView img, @NotNull String url) { Picasso.with(img.getContext()).load(url).into(img); }}
Основные фичи• Выведение типов • Значения по умолчанию • Именованные параметры
• Data классы
• Деструктуризация
• Функции расширения
• Инфиксные функции
• Свойства (атрибуты)
• Лямбды
• Лямбда-ресиверы
• when, if
60
Инфиксные функции
61
infix fun Int.add(a:Int) = this+a
fun main (args: Array<String>) { println(1.add(10)) }
Инфиксные функции
62
infix fun Int.add(a:Int) = this+a
fun main (args: Array<String>) { println(1 add 10) }
Инфиксные функции
63
val map = mapOf("One" to 1, "Two" to 2, "Three" to 3) for ((key, value) in map) { println("$key = $value") }
Инфиксные функции
64
val map = mapOf("One" to 1, "Two" to 2, "Three" to 3) for ((key, value) in map) { println(key + " = " + value)}
infix fun String.to(that: Int): Pair<String, Int> { return Pair(this, that) }
Основные фичи• Выведение типов • Значения по умолчанию • Именованные параметры
• Data классы
• Деструктуризация
• Функции расширения
• Инфиксные функции
• Свойства (атрибуты)
• Лямбды
• Лямбда-ресиверы
• when, if
65
Свойства (атрибуты)
66
class Cat(val name: String?, var age: Int)
Свойства (атрибуты)
67
class Cat { val name: String? var age: Int constructor(name: String?, age: Int) { this.name = name this.age = age }}
Свойства (атрибуты)
68
class main (args: Array<String>) { val cat = Cat("Meow", 2) println("cat's age = ${cat.age}")
cat.age = 100 println("cat's age = ${cat.age}") }
cat's age = 2 cat's age = 100
Свойства (атрибуты)
69
class Cat { val name: String? var age: Int constructor(name: String?, age: Int) { this.name = name this.age = age }}
Свойства (атрибуты)
70
class Cat { val name: String? var age: Int set(value) { if (value in 1..20) field = value } constructor(name: String?, age: Int) { this.name = name this.age = age }}
Свойства (атрибуты)
71
class main (args: Array<String>) { val cat = Cat("Meow", 2)
cat.age = 100 println("cat's age = ${cat.age}") cat.age = 5 println("cat's age = ${cat.age}") }
cat's age = 2 cat's age = 5
Основные фичи• Выведение типов • Значения по умолчанию • Именованные параметры
• Data классы
• Деструктуризация
• Функции расширения
• Инфиксные функции
• Свойства (атрибуты)
• Лямбды
• Лямбда-ресиверы
• when, if
72
Лямбды
73
(1..10).filter { n -> n % 2 == 0 }.map { n -> println(n) }
2 4 6 8 10
Лямбды
74
(1..10).filter { it % 2 == 0 }.map { n -> println(n) }
2 4 6 8 10
Лямбды
75
(1..10).filter { it % 2 == 0 }.map(::println)
2 4 6 8 10
Лямбда-ресиверы
76
fun buildString(f: StringBuilder.() -> Unit): String { val sb = StringBuilder() sb.f() return sb.toString()}
Hello, Coding Monday
fun main (args: Array<String>) { val s = buildString({ append("Hello, ") append("Coding Monday") }) println(s) }
Лямбда-ресиверы
77
fun buildString(f: StringBuilder.() -> Unit): String { val sb = StringBuilder() sb.f() return sb.toString()}
Hello, Coding Monday
fun main (args: Array<String>) { val s = buildString { append("Hello, ") append("Coding Monday") } println(s) }
Основные фичи• Выведение типов • Значения по умолчанию • Именованные параметры
• Data классы
• Деструктуризация
• Функции расширения
• Инфиксные функции
• Свойства (атрибуты)
• Лямбды
• Лямбда-ресиверы
• when, if
78
when
79
val x = (Math.random() * 100).toInt()when (x) { 0 -> println("$x is zero") 1,2,3 -> println("$x is equals 1 or 2 or 3") in 4..50 -> println("$x in range: 4..50") is Int -> println("$x is Int") else -> println("$x is unknown") }
when
80
fun checkX(x: Int) = when (x) { 0 -> "$x is zero" 1,2,3 -> "$x is equals 1 or 2 or 3" in 4..50 -> "$x in range: 4..50" is Int -> "$x is Int" else -> "$x is unknown"}
val x = (Math.random() * 100).toInt()println(checkX(x))
if
81
fun max(a: Int, b: Int) = if (a > b) a else b
val a = (Math.random() * 100).toInt()val b = (Math.random() * 100).toInt()println("Max of $a and $b is ${max(a, b)}")
План• О Kotlin
• Основные фичи
• Kotlin для
• Ресурсы
• Вопросы
82
Как это работает?
84
Подготовка проекта• Создаём проект "как обычно" (с пустой Activity)
• ⌥⇧⌘K или в меню Code → Convert Java File to Kotlin File
• Меню Tools → Kotlin → Configure Kotlin in Project
• Синхронизируем Gradle
• Профит!
85
Полезные библиотеки• Kotlin Android Extensions
• apply plugin: 'kotlin-android-extensions'
• Anko
• https://github.com/Kotlin/anko
• Spek
• https://github.com/JetBrains/spek
• Kodein
• https://github.com/SalomonBrys/Kodein
86
План• О Kotlin
• Основные фичи
• Kotlin для
• Ресурсы
• Вопросы
87
Ресурсы
Ссылки• https://kotlinlang.org/docs/reference/
• http://try.kotlinlang.org
• https://kotlin.link
• https://t.me/kotlinized
89
Книги
Dmitry Jemerov Svetlana Isakova
Kotlin in Action
91
Antonio Leiva
Kotlin for Android Developers
92
Чаты• [ru] https://t.me/kotlin_lang
• [en] https://kotlinlang.slack.com
93
План• О Kotlin
• Основные фичи
• Kotlin для
• Ресурсы
• Вопросы
94
Вопросы?https://github.com/bendikv
https://twitter.com/vitaliy_bendikhttps://linkedin.com/in/bendikv
Всем Котлина!