2. Porque Kotlin?
• Linguagem moderna, concisa, intuitiva e fácil de aprender.
• Open Source, mantido pela JetBrains
• 100% Interoperável com Java. Você pode possuir código Java e
Kotlin no mesmo projeto.
• Suporte nativo no Android Studio.
• Menos verboso. Você escreve menos código.
• Null Safety
• Possui recursos de linguagens funcionais
• Extension functions, funções de alta ordem e muito mais
8. Kotlin bytecode?
data class Person(
var name: String,
var age: Int) {
override fun toString(): String {
return "$name - $age"
}
}
Person.kt
Compiler
kotlinc
________________
________________
________________
________________
________________
________________
________________
Person.class
9. val (imutável)
var (mutável)
val hello: String = "hello"
val world = "world"
println("$hello $world")
world = "bla" // compilation error
var helloWorld: String = "Hello"
helloWorld = "Hello World"
println(helloWorld)
10. Tipos de dados
val i: Int = 7
// no automatic conversion
val d: Double = i.toDouble()
var c: Char = 'c'
val s = "Example"
c = s[2] // Char 'a'
val i1: Int = c.toInt()
val i2 = 12 // Int
val iHex = 0x0f // Int em hexadecimal
val l = 3L // Long
val d1 = 3.5 // Double
val f = 3.5F // Float
val any: Any = 3 // Any=Object
* Não existem tipos primitivos
11. Range
val x = 5
if (IntRange(1, 10).contains(x)) {
// do something
}
if (1.rangeTo(10).contains(x)) {
// do something
}
if ((1..10).contains(x)) {
// do something
}
12. if/else e when
podem retornar valores
val max = if (a > b) a else b
val msg = when (x) {
in 1..10, 100 -> "x is in the range or is 100”
in validNumbers -> "x is valid"
!in 10..20 -> "x is outside the range"
else -> "none of the above"
}
13. try/catch também…
val content = try {
// load some data from file
return fileContent
} catch (e: Exception) {
return null
}
Importante! Kotlin não possui checked exceptions!
14. for
for (item in list) {
//... iterate over a list
}
for (i in 0..NUM_ROWS) {
//... i == NUM_ROWS
}
for (i in 0 until NUM_ROWS) {
//... i < NUM_ROWS
}
for (i in NUM_ROWS downTo 0) {
//... from NUM_ROWS to 0
}
for (i in 0..10 step 2) {
//... 0, 2, 4, 6, 8, 10
}
15. Métodos ou Funções?
// void = Unit
fun foo(text: String) : Unit {
println("Hi $text")
}
fun bar(text: String) {
println("Hey $text")
}
// more verbose method
fun sum1(x: Int, y: Int) : Int {
return x + y
}
// or simpler...
fun sum2(x:Int, y:Int): Int = x + y
// even simpler
fun sum3(x:Int, y:Int) = x + y
16. Parâmetros com valores
padrão
fun showMessage(title : String = "Hello",
name : String = "Glauber") {
println("$title $name")
}
// We can call this function using…
showMessage()
showMessage("Hey")
showMessage("Hello", "Nelson")
showMessage(name="José")
17. val employee = Employee("Nelson", 35, "99009900")
print("${employee.name} - " +
"${employee.age} / ${employee.id}")
Classes
open class Person(var name : String, var age : Int)
class Employee(name : String,
age : Int,
var id : String) : Person(name, age)
18. Classes
open class Person {
var name : String = ""
var age : Int = 0
}
class Employee(name : String,
age : Int,
var id : String) : Person() {
init {
this.name = name
this.age = age
}
}
val employee = Employee("Nelson", 35, "99009900")
print("${employee.name} - " +
"${employee.age} / ${employee.id}")
19. Classes
class Company {
init {
// Initialize some stuff...
}
constructor(name : String) {
// Initialize with name
}
constructor(id : Int) {
// Initialize with ID
}
}
20. Data Classes
data class Product(var name: String, var descr: String, var price: Float)
• Já possui as funções equals()/
hashCode()
• Já possui toString() no padrão
"Product(name=A, descr=B, price=42)”
• Já possui o método copy()
• destructuring functions correspondentes as
propriedades ordenadas por declaração
• Não pode ser estendida
p1 = Product("X", "Y", price = 10F)
p2 = p1.copy(price = 20F)
val (name, _, price) = p1
var p1 = Product("X", "Y", price = 10F)
var p2 = Product("X", "Y", price = 10F)
println(p1 == p2) // true
println(p1 === p2) // false
21. Interfaces
interface Foo {
val value : Int // must implement getter
fun sum(x : Int, y : Int) = x + y // default implementation
}
22. Modificadores de acesso
• public (padrão)
• private
• protected = private + subclasses
classes no mesmo pacote não acessam
• internal
• Não possui o modificador para package 😢
23. Properties
class Person {
var name : String = ""
get() = field.toUpperCase()
set(value) {
field = "Name: $value"
}
var age : Int = 0
}
24. Companion Object
int x = Foo.Companion.getCONSTANT_1();
int y = Foo.CONSTANT_2;
Person p = Foo.ROOT;
Foo.foo(); ☕
companion object {
val CONSTANT_1 = 1 // private + getter
const val CONSTANT_2 = 2 // public
@JvmField val ROOT = User("root”) // getROOT()
@JvmStatic fun foo() {}
}
25. Classes x Tipos
Class Type
String Yes Yes
String? No Yes
Person Yes Yes
Person? No Yes
String?
String
26. Null Safety
// Compilation error
var person: Person = null
// Now can be null
var personOpt: Person? = null
// Compilation error
println(pessoaOpt.nome)
// It works!
println(pessoaOpt?.nome)
27. Null Safety
// you can avoid the "?." Operator with a "if"
if (pessoaOpt != null) {
println(pessoaOpt.nome)
}
// Smell...
println(pessoaOpt!!.nome)
// Elvis still alive
val name = pessoaOpt?.nome ?: "empty"
28. Late Init
class MainActivity : AppCompatActivity() {
private lateinit var db: BookDatabase
...
Relaxa compilador, eu vou
inicializar esse atributo depois.
Confia em mim! 😎
29. Cast
val text1 = param as String // may throw an exception
val text2 = param as? String // this is may be null
...
if (param is String) {
val text = param // smart cast!!
...
}
30. Null Safety
• Como conseguir um NullPointerException?
• Lançando a exceção explicitamente
• Usando o operador !!
• Acessando um atributo lateinit que não foi
inicializado
• Invocando código Java 😈
31. Extension Functions
fun String.withPlusInTheEnd() : String = this + "+"
"Glauber".withPlusInTheEnd()
fun Activity.showShortToast(text: String) {
Toast.makeText(this, text, Toast.LENGTH_SHORT).show()
}
33. apply, with, let, run
• apply é uma extension function que executa
o bloco de código sobre uma instância e retorna a
própria instância.
• with não é uma extension function e o objeto
deve ser explicitamente passado como parâmetro.
O returno é o resultado do bloco da função.
34. apply, with, let, run
startActivity(Intent(activity, DetailActivity::class.java).apply {
putExtra("nome", "Glauber")
putExtra("idade", 33)
})
with(person) {
name = "Glauber"
age = 33
}
35. apply, with, let, run
• let é uma função de escopo muito usado para lidar
com nullable objects. Ao invés de encadear if-else,
você pode simplesmente combinar o
operador "?." com o let. Teremos então um lambda
onde o argumento é uma versão not-nullable do
objeto original.Por fim, o let retorna o resultado do
bloco.
• run é uma extension function e é algo como uma
junção do let e apply, A única diferença é o retorno: o
apply retorna o próprio objeto, enquanto que
o run retorna o resultado do bloco.
36. apply, with, let, run
val person : Person? =
intent.getSerializableExtra("person") as? Person
person?.let {
listOfPerson.add(person)
listOfPerson.sortBy { it.name }
adapter.notifyDataSetChanged()
}
val x = Person("Nelson", 33).run {
name.length + age
}
println(x) // 39
40. Higher-Order Functions
class PersonAdapter(val people: List<Person>,
val callback: (Person) -> Unit) :
RecyclerView.Adapter<PersonHolder>() {
override fun onBindViewHolder(holder: PersonHolder?, position: Int) {
val person = people[position]
holder?.textView?.apply {
text = person.name
setOnClickListener { callback(person) }
}
}
41. Higher-Order Functions
override fun onCreate(savedInstanceState: Bundle?) {
...
var adapter = PersonAdapter(peopleList, this::onItemClick)
...
}
private fun onItemClick(person : Person) {
showShortToast(person.name)
}
override fun onCreate(savedInstanceState: Bundle?) {
...
var adapter = PersonAdapter(peopleList, { person ->
})
...
}
42. Typealias
typealias PersonCallback = (Person)->Unit
class PersonAdapter(val people: List<Person>,
val callback: PersonCallback)
: RecyclerView.Adapter<PersonHolder>() {
43. Operator overloading
+a a.unaryPlus()
-a a.unaryMinus()
!a a.not()
a++ a.inc()
a— a.dec()
a += b a.plusAssign(b)
a -= b a.minusAssign(b)
a *= b a.timesAssign(b)
a /= b a.divAssign(b)
a %= b a.modAssign(b)
a + b a.plus(b)
a - b a.minus(b)
a * b a.times(b)
a / b a.div(b)
a % b a.rem(b)
a..b a.rangeTo(b)
a in b a.contains(b)
a > b a.compareTo(b) > 0
a < b a.compareTo(b) < 0
a >= b a.compareTo(b) >= 0
44. Operator overloading
operator fun String.times(b: Int): String {
val buffer = StringBuffer()
for (i in 1..b) {
buffer.append(this)
}
return buffer.toString()
}
val newString = "Test" * 4
45. Delegated Properties
class SomeClass {
var p: String by Delegate()
}
// ...
import kotlin.reflect.KProperty
class Delegate {
operator fun getValue(thisRef: Any?, property: KProperty<*>): String {
return "$thisRef, thank you for delegating '${property.name}' to me!"
}
operator fun setValue(thisRef: Any?, property: KProperty<*>, value: String) {
println("$value has been assigned to '${property.name} in $thisRef.'")
}
}
46. Lazy, Observable, Vetoable
val people: MutableList<Person> by lazy { mutableListOf<Person>() }
class User {
var email: String by Delegates.observable("") {
prop, old, new ->
//handle the change from old to new value
}
}
var positiveNumber = Delegates.vetoable(0) {
d, old, new ->
new >= 0
}
47. Mapeando um objeto com
um Map
class User(map: Map<String, Any?>) {
val name: String by map
val age: Int by map
}
val user = User(mapOf(
"name" to "John Doe",
"age" to 25
))
48. Collections 😍
val list = listOf(1, 2, 3, 4, 5)
println(list[1])
val mutList = mutableListOf<Int>()
mutList.add(1)
val array = arrayOf("Nelson", "Glauber")
println(array[0])
val map = mapOf(1 to "Glauber", 2 to "Nelson", Pair(3, "Chico"))
println(map[1])
val mutMap = mutableMapOf<Int, String>()
mutMap.put(1, "João")
50. Collections 😍
• Elements
• contains, elementAt, first, indexOf, last,
lastIndexOf, single, …
• Generation operations
• merge, partition, plus, zip e unzip
• Ordering
• reverse, sort, sortBy, sortDescending e
sortDescendingBy
51. Collections 😍
val pessoas = listOf(
Pessoa("Nelson", 33),
Pessoa("Glauber", 33),
Pessoa("Ana", 27),
Pessoa("João", 12)
)
val p1 = pessoas.sortedBy { it.idade }
p1.forEach { println(it) }
val p2 = pessoas.maxBy { p -> p.idade }
println(p2)
val people = pessoas.groupBy { it.idade }
println("agrupado por idade: $people")
52. Collections 😍
// Return the set of cities the customers are from
fun getCitiesCustomersAreFrom(): Set<City> =
customers.map { customer -> customer.city }.toSet()
// Return a list of the customers who live in the given city
fun getCustomersFrom(city: City): List<Customer> =
customers.filter { customer -> customer.city == city }
53. Singletons com Object
object SilvioSantos {
fun mahOeee() = "Mah Ôeeee!"
fun juizo() = false
}
SilvioSantos.mahOeee()
if (SilvioSantos.juizo()) println("sem graça :(")
else println("Processo :’(")
54. infix
• Notação para chamada de
funções sem a necessidade de
usar “.” ou “( )”
• Devem ser "métodos" de uma
classe ou extension function.
• Só podem possuir um parâmetro
// Define extension to Int
infix fun Int.shl(x: Int): Int {
...
}
/* call extension function using
infix notation */
1 shl 2
// is the same as
1.shl(2)
55. Sealed classes
sealed class Operation {
class Add(val value: Int) : Operation()
class Substract(val value: Int) : Operation()
class Multiply(val value: Int) : Operation()
class Divide(val value: Int) : Operation()
}
fun execute(x: Int, op: Operation) = when (op) {
is Operation.Add -> x + op.value
is Operation.Substract -> x - op.value
is Operation.Multiply -> x * op.value
is Operation.Divide -> x / op.value
}
57. Curiosidades
• Você pode nomear seus imports usando “as"
• Você pode ter funções dentro de funções
• Você pode ter funções soltas em um arquivo, nesse
caso, será gerada uma classe com o nome do
arquivo, isso pode ser alterado usando
@file:JvmName(“SuaClasse”)
import com.mycompany.data.local.entity.Trip
import com.mycompany.model.Trip as TripModel
58. A IDE dá aquela forcinha…
• Aponta os erros e melhorias
• Ctrl-V de código Java faz a conversão automática
para Kotlin
• Ver bytecode do Kotlin e ver o Java
59. Prós
• Linguagem moderna, repleta de recursos e
facilidades não disponíveis no Java
• Suporte nativo do Android Studio.
• É muito fácil converter um código Java para Kotlin.
• Java e Kotlin podem co-existir no mesmo projeto.
• Não há overhead significante de performance do
Kotlin em comparação com o Java.
60. Contras
• A std library do Kotlin adicionará aproximadamente
300KB ao seu APK.
• Autocomplete demora um pouco mais.
• Compilação demora um pouco mais.
61.
62. Learn more…
• Site Oficial (kotlinlang.org)
• Editor on-line (try.kotlinlang.org)
• Kotlin Koans (try.kotlinlang.org/koans)
• Antonio Leiva’s book (antonioleiva.com/google-kotlin)
• Como eu aprendi Kotlin (bit.do/nglauber_kotlin)
• Dominando o Android com Kotlin (em breve) 😉