5. What is Kotlin?
● statically-typed object oriented programming language
● targeting JVM, Android and JavaScript
● fully interoperable with Java
● third party library
● has excellent IDE support
6. Kotlin history
● developed by JetBrains
● unveiled to public in 2011.(development started in 2012.)
● 1.0 first stable version (February 2016.)
● current version 1.1 RC
8. Problems that we have:
Why do we need Kotlin?
● Java
○ is too verbose
○ burden of previous versions
○ Null Pointer Exception
issues
○ util “hell”
● Android
○ we need inheritance for
almost everything
○ api ceremony
○ nullability
○ lack of Java 8 features
(lambdas, stream api,
method reference...)
10. Variables
val avenger: String = “Tony Stark” //constants
avenger = “Ultron” // compile error
var age : Int = 18 //variable
age = 20 // compiles since age is mutable
var number = 20 // Int type is inferred
12. text.length // compiler error
var text: String? = null // This can be null or not-null
Nullability
var name: String = null // compile error
text?.length // compiles ⇔ if ( text != null) {
text.length // smart casted to not-nullable type
}
name.length // this is ok since type is not nullable
15. Functions
fun add(a: Int, b: Int): Int {
return a + b
}
Calling functions:
add(1, 3)
log(1, “Num is”)
//“Num is 1”
fun log(num: Int, msg: String): Unit {
println(“$msg $num”)
}
16. Functions
fun add(a: Int, b: Int): Int = a + b
fun log(num: Int, msg: String): Unit
= println(“$msg $num”)
Calling functions:
add(1, 3)
log(1, “Num is”)
//“Num is 1”
17. Functions
fun add(a: Int, b: Int) = a + b
fun log(num: Int, msg: String)
= println(“$msg $num”)
Calling functions:
add(1, 3)
log(1, “Num is”)
//“Num is 1”
18. Functions
fun add(a: Int = 0, b: Int = 0) = a + b
fun log(num: Int, msg: String = “Num is”)
= println(“$msg $num”)
add() //returns 0
add(1) //returns 1
add(b = 1) //returns 1
log(1) // “Num is 1”
log(msg = “Its ”, num = 2)
// “Its 2”
21. Classes and data classes
@Override public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
User user = (User) o;
if (age != user.age) return false;
if (!name.equals(user.name)) return false;
return email.equals(user.email);
}
@Override public int hashCode() {
int result = name.hashCode();
result = 31 * result + email.hashCode();
result = 31 * result + age;
return result;
}
}
class User {
private final String name;
private final String email;
private final int age;
User(String name, String email, int age) {
this.name = name;
this.email = email;
this.age = age;
}
public String getName() { return name; }
public String getEmail() { return email; }
public int getAge() { return age; }
@Override
public String toString() {
return "User{ name='" + name + ''' + ", email='" + email
+ ''' + ", age=" + age + '}';
}
22. Classes and data classes
@Override public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
User user = (User) o;
if (age != user.age) return false;
if (!name.equals(user.name)) return false;
return email.equals(user.email);
}
@Override public int hashCode() {
int result = name.hashCode();
result = 31 * result + email.hashCode();
result = 31 * result + age;
return result;
}
}
class User {
private final String name;
private final String email;
private final int age;
User(String name, String email, int age) {
this.name = name;
this.email = email;
this.age = age;
}
public String getName() { return name; }
public String getEmail() { return email; }
public int getAge() { return age; }
@Override
public String toString() {
return "User{ name='" + name + ''' + ", email='" + email
+ ''' + ", age=" + age + '}';
}
23. Classes and data classes
@Override public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
User user = (User) o;
if (age != user.age) return false;
if (!name.equals(user.name)) return false;
return email.equals(user.email);
}
@Override public int hashCode() {
int result = name.hashCode();
result = 31 * result + email.hashCode();
result = 31 * result + age;
return result;
}
class User (
val name: String,
val email: String,
val age: Int
)
@Override
public String toString() {
return "User{ name='" + name + ''' + ", email='" + email
+ ''' + ", age=" + age + '}';
}
24. Classes and data classes
data class User (
val name: String,
val email: String,
val age: Int
)
val user = User("John Smith", "johnsmith@mail.com", 24)
val newUser = user.copy(name = "Sam")
//newUser == User("Sam", "johnsmith@mail.com", 24)
val (name, email, age) = newUser
25. Data classes
data class User (
val name: String = "John Smith",
val email: String = "johnsmith@mail.com",
val age: Int = 24
)
val user = User ()
// user == User("John Smith", "johnsmith@mail.com", 24)
26. Classes and data classes
data class User( val name: String, val email: String, val age: Int)
● Kotlin classes are final by default
● we need to annotate class as open, if we want to inherit them
● data classes can’t be inherited
class limitations:
27. Classes and data classes
open class User( val name: String, val email: String, val age: Int)
● Kotlin classes are final by default
● we need to annotate class as open, if we want to inherit them
● data classes can’t be inherited
class limitations:
43. Function expressions
val add: (Int, Int) -> Int = { x,y -> x+y }
add(1,2)
val validator: (String) -> Boolean ={ value -> value.contains("@") }
validator("john@mail.com")
● function expressions are blocks of code which we can
instantiate(represent as type)
44. Function expressions
val add: (Int, Int) -> Int = { x,y -> x+y }
add(1,2)
● function expressions are blocks of code which we can
instantiate(represent as type)
val validator: (String) -> Boolean ={ it.contains("@") }
validator("john@mail.com")
45. Function expressions
val add: (Int, Int) -> Int = { x,y -> x+y }
add(1,2)
val validator: (String) -> Boolean ={ it.contains("@") }
validator("john@mail.com")
mailTextview.validateWith{ validator("john@mail.com") }
● function expressions are blocks of code which we can
instantiate(represent as type)
48. Higher order functions
fun <T> List<T>.filter(predicate: (T) -> Boolean): List<T>{
val items = ArrayList<T>()
return items
}
49. Higher order functions
fun <T> List<T>.filter(predicate: (T) -> Boolean): List<T>{
val items = ArrayList<T>()
for (item in this) {
}
return items
}
50. Higher order functions
fun <T> List<T>.filter(predicate: (T) -> Boolean): List<T>{
val items = ArrayList<T>()
for (item in this) {
if (predicate(item)) {
items.add(item)
}
}
return items
}
val cars = listOf("BMW", "Fiat", "Mercedes", "KIA", "Ford")
val filteredCars = cars.filter ({ it.startsWith("F") })
// filteredCars == listOf("Fiat", "Ford")
51. Higher order functions
fun <T> List<T>.filter(predicate: (T) -> Boolean): List<T>{
val items = ArrayList<T>()
for (item in this) {
if (predicate(item)) {
items.add(item)
}
}
return items
}
val cars = listOf("BMW", "Fiat", "Mercedes", "KIA", "Ford")
val filteredCars = cars.filter { it.startsWith("F") }
// filteredCars == listOf("Fiat", "Ford")
53. Quick overview
● Extension functions - adds functionality to types
without overriding existing methods
● Function expressions - undeclared function body used
as an expression
● Higher order function - function that accepts function or
returns function
55. fun saveUser(user: User) {
val editor = sharedPref.edit()
editor.putString(ACCESS_TOKEN, user.token)
editor.putString(USER_EMAIL, user.email)
editor.commit()
}
Extension / Higher order function expression combo
fun SharedPreferences.edit(editor : SharedPreferences.Editor, func: () -> Unit) {
func()
editor.commit()
}
56. Extension / Higher order function expression combo
fun saveUser(user: User) {
val editor = sharedPref.edit()
sharedPref.edit(editor) {
editor.putString(ACCESS_TOKEN, user.token)
editor.putString(USER_EMAIL, user.email)
}
}
fun SharedPreferences.edit(editor : SharedPreferences.Editor, func: () -> Unit) {
func()
editor.commit()
}
57. fun saveUser(user: User) {
val editor = sharedPref.edit()
sharedPref.edit(editor) {
editor.putString(ACCESS_TOKEN, user.token)
editor.putString(USER_EMAIL, user.email)
}
}
Extension / Higher order function expression combo
fun SharedPreferences.edit(editor : SharedPreferences.Editor, func: () -> Unit) {
func()
editor.commit()
}
58. fun saveUser(user: User) {
sharedPref.edit {
editor.putString(ACCESS_TOKEN, user.token)
editor.putString(USER_EMAIL, user.email)
}
}
Extension / Higher order function expression combo
fun SharedPreferences.edit(func: () -> Unit) {
val editor = edit()
func()
editor.commit()
}
59. fun saveUser(user: User) {
sharedPref.edit {
it.putString(ACCESS_TOKEN, user.token)
it.putString(USER_EMAIL, user.email)
}
}
Extension / Higher order function expression combo
fun SharedPreferences.edit(func: (SharedPreferences.Editor) -> Unit) {
val editor = edit()
func(editor)
editor.commit()
}
60. fun saveUser(user: User) {
sharedPref.edit {
it.putString(ACCESS_TOKEN, user.token)
it.putString(USER_EMAIL, user.email)
}
}
Extension / Higher order function expression combo
fun SharedPreferences.edit(func: (SharedPreferences.Editor) -> Unit) {
val editor = edit()
func(editor)
editor.commit()
}
61. fun saveUser(user: User) {
sharedPref.edit {
it.putString(ACCESS_TOKEN, user.token)
it.putString(USER_EMAIL, user.email)
}
}
Extension / Higher order function expression combo
fun SharedPreferences.edit(func: SharedPreferences.Editor.() -> Unit)) {
val editor = edit()
func(editor)
editor.commit()
}
62. fun saveUser(user: User) {
sharedPref.edit {
it.putString(ACCESS_TOKEN, user.token)
it.putString(USER_EMAIL, user.email)
}
}
Extension / Higher order function expression combo
fun SharedPreferences.edit(func: SharedPreferences.Editor.() -> Unit)) {
val editor = edit()
editor.func()
editor.commit()
}
63. fun saveUser(user: User) {
sharedPref.edit {
putString(ACCESS_TOKEN, user.token)
putString(USER_EMAIL, user.email)
}
}
Extension / Higher order function expression combo
fun SharedPreferences.edit(func: SharedPreferences.Editor.() -> Unit) {
val editor = edit()
editor.func()
editor.commit()
}
64. Extension / Higher order function expression combo
fun SharedPreferences.Editor.put(pair: Pair<String, Any>) {
val key = pair.first
val value = pair.second
when(value) {
is String -> putString(key, value)
is Int -> putInt(key, value)
is Boolean -> putBoolean(key, value)
is Float -> putFloat(key, value)
is Long -> putLong(key, value)
else -> error(“Only primitive types are supported”)
}
}
65. fun saveUser(user: User) {
sharedPref.edit {
putString(ACCESS_TOKEN, user.token)
putString(USER_EMAIL, user.email)
}
}
Extension / Higher order function expression combo
fun SharedPreferences.edit(func: SharedPreferences.Editor.() -> Unit)) {
val editor = edit()
editor.func()
editor.commit()
}
66. Extension / Higher order function expression combo
fun saveUser(user: User) {
sharedPref.edit {
put(Pair(ACCESS_TOKEN, user.token))
put(Pair(USER_EMAIL, user.email))
}
}
fun SharedPreferences.edit(func: SharedPreferences.Editor.() -> Unit) {
val editor = edit()
editor.func()
editor.commit()
}
67. fun saveUser(user: User) {
sharedPref.edit {
put(ACCESS_TOKEN to user.token)
put(USER_EMAIL to user.email)
}
}
Extension / Higher order function expression combo
fun SharedPreferences.edit(func: SharedPreferences.Editor.() -> Unit) {
val editor = edit()
editor.func()
editor.commit()
}
68. fun saveUser(user: User) {
sharedPref.edit {
put(ACCESS_TOKEN to user.token)
put(USER_EMAIL to user.email)
}
}
Extension / Higher order function expression combo
fun SharedPreferences.edit(func: SharedPreferences.Editor.() -> Unit) {
val editor = edit()
editor.func()
editor.commit()
}
public infix fun <A, B> A.to(that: B): Pair<A, B> = Pair(this, that)
69. fun saveUser(user: User) {
sharedPref.edit {
put(ACCESS_TOKEN to user.token)
put(USER_EMAIL to user.email)
}
}
Extension / Higher order function expression combo
inline fun SharedPreferences.edit(func: SharedPreferences.Editor.() -> Unit) {
val editor = edit()
editor.func()
editor.commit()
}
70. Extension / Higher order function expression combo
From this:
fun saveUser(user: User) {
val editor = sharedPref.edit()
editor.putString(ACCESS_TOKEN, user.token)
editor.putString(USER_EMAIL, user.email)
editor.commit()
}
To this:
inline fun saveUser(user: User) {
sharedPref.edit {
put(ACCESS_TOKEN to user.token)
put(USER_EMAIL to user.email)
}
}
72. Summary
● immutable and mutable variables
● nullability
● functions(default values and named arguments)
● classes and data classes
● extension functions and properties
● function expression
● higher order functions
● ultra mega giga combo of three above concepts
● use inline modifier
73. Resources
● Official Kotlin documentation
● Official Kotlin Github
● Anko
● Kotlin koans
● Awesome Kotlin – collection of materials
● Slack kanal
● Design patterns in Kotlin
● Keddit - demo app
● Kotlin For Android (at DevFest İzmir 2016)
● Kotlin – Ready for Production – Hadi Hariri
● Android development with Kotlin – Jake Wharton
76. Nebojša Vukšić
Android developer @ codecentric
Founder of Kotlin User Group Serbia
Nesh_Wolf
nebojsa92vuksic@gmail.com
Kotlin User Group Serbia
https://www.meetup.com/Serbia-Kotlin-User-Group
https://www.facebook.com/kotlinserbia/
https://twitter.com/kotlin_serbia