Kotlin: New Hope in a Java 6 Wasteland

Kotlin: New Hope in a Java 6 Wasteland

Java 8 was released last year adding lambdas, streams, and many other language improvements. Java 9 is already in the works, but with over half of Android devices stuck using Java 6 will we ever get to use a modern language?

Introducing Kotlin: a statically typed JVM language backed by JetBrains. With features like lambdas, class extensions, and null-safety, it aims to be concise, expressive, and highly interoperable. In this presentation we will learn how powerful Kotlin can be when added to your Android tool belt.

B6ea8bb06748e123565b6a997febbac8?s=128

Michael Pardo

May 09, 2015
Tweet

Transcript

  1. kotlin: NewHope In a Java 6 Wasteland

  2. 100% interoperable with Java™ Statically typed programming language targeting the

    JVM and JavaScript
  3. concise /kənˈsīs/ adjective giving a lot of information clearly and

    in a few words; brief but comprehensive.
  4. expressive /ikˈspresiv/ adjective effectively conveying thought or feeling.

  5. safe /sāf/ adjective protected from or not exposed to danger

    or risk; not likely to be harmed or lost.
  6. versatile /ˈvərsədl/ adjective able to adapt or be adapted to

    many different functions or activities.
  7. interoperable /ˌin(t)ərˈäp(ə)rəb(ə)l/ adjective (of computer systems or software) able to

    exchange and make use of information.
  8. Why not wait for Java 8?

  9. Java 6 2006

  10. Java 6 2006 Android 1.0 2008

  11. Java 6 2006 Java 7 2011 Android 1.0 2008

  12. Java 6 2006 Java 7 2011 Java 7 Support 2013

    Android 1.0 2008
  13. Java 6 2006 Java 7 2011 Java 8 2014 Java

    7 Support 2013 Android 1.0 2008
  14. Java 6 2006 Java 7 2011 Java 8 2014 Java

    7 Support 2013 Java 8 Support ???? Android 1.0 2008
  15. KitKat Jelly Bean Lollipop Froyo Gingerbread Ice Cream Sandwich

  16. KitKat Jelly Bean Lollipop Froyo Gingerbread Ice Cream Sandwich

  17. Problems with Java

  18. Null references “I call it my billion-dollar mistake… [which] 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.” — Tony Hoare
  19. Raw types List numbers = getNumberList(); int sum = 0;

    for (Object num : numbers) { sum += (Integer) num; // Unchecked cast }
  20. Covariant arrays String[] strings = { "hello" }; Object[] objects

    = strings; objects[0] = 1; // java.lang.ArrayStoreException
  21. SAM types interface Func1<T1, R> { R call(T1 t1); }

    interface Func2<T1, T2, R> { R call(T1 t1, T2 t2); } interface Func3<T1, T2, T3, R> { R call(T1 t1, T2 t2, T3 t3); } // ...
  22. Wildcards “I am completely and totally humbled. Laid low. I

    realize now that I am simply not smart at all. I made the mistake of thinking that I could understand generics. I simply cannot. I just can't. This is really depressing. It is the first time that I've ever not been able to understand something related to computers, in any domain, anywhere, period.” "We simply cannot afford another wildcards” — Joshua Bloch
  23. Checked exceptions “… requiring exception specifications could both enhance developer

    productivity and enhance code quality, but experience with large software projects suggests a different result – decreased productivity and little or no increase in code quality.” — Bruce Eckel
  24. Kotlin to the rescue!

  25. What Kotlin removes • Checked exceptions • Non-class primitive types

    • Static members • Non-private fields • Wildcard types
  26. What Kotlin adds • Lambdas • Data classes • Function

    literals & inline functions • Extension functions • Null-safety • Smart casts • String templates • Properties • Primary constructors • Class delegation • Type inference • Singletons • Declaration-site variance • Range expressions
  27. Dalvik ART Android Java source javac Kotlin source kotlinc bytecode

    JVM Backend JVM Desktop
  28. Hello, Kotlin!

  29. fun main(args: Array<String>): Unit { println("Hello, World!") } > Hello,

    World!
  30. fun main(args: Array<String>): Unit { println("Hello, World!") } Function keyword

  31. fun main(args: Array<String>): Unit { println("Hello, World!") } Function name

  32. fun main(args: Array<String>): Unit { println("Hello, World!") } Argument name

  33. fun main(args: Array<String>): Unit { println("Hello, World!") } Argument type

  34. fun main(args: Array<String>): Unit { println("Hello, World!") } Return type

  35. fun main(args: Array<String>): Unit { println("Hello, World!") }

  36. fun main(args: Array<String>): Unit {. println("Hello, World!") }. Unit inferred

  37. fun main(args: Array<String>) {. println("Hello, World!") }.

  38. fun main(args: Array<String>) {. println("Hello, World!") }.

  39. fun main(args: Array<String>) {. var name = "World" println("Hello, $name!")

    }.
  40. fun main(args: Array<String>) {. var name = "World" println("Hello, $name!")

    }. Variable declaration
  41. fun main(args: Array<String>) {. var name = "World" println("Hello, $name!")

    }. String interpolation
  42. fun main(args: Array<String>) {. var name = "World" if (args.isNotEmpty())

    { name = args[0] } println("Hello, $name!") }.
  43. fun main(args: Array<String>) {. var name = "World" if (args.isNotEmpty())

    { name = args[0] } println("Hello, $name!") }.
  44. fun main(args: Array<String>) {. val name = "World" if (args.isNotEmpty())

    { name = args[0] } println("Hello, $name!") }.
  45. fun main(args: Array<String>) {. val name = "World" if (args.isNotEmpty())

    { name = args[0] } println("Hello, $name!") }. Constant declaration
  46. fun main(args: Array<String>) {. val name = "World" if (args.isNotEmpty())

    { name = args[0] }. println("Hello, $name!") }. Val cannot be reassigned
  47. fun main(args: Array<String>) {. val name = "World" if (args.isNotEmpty())

    { name = args[0] }. println("Hello, $name!") }.
  48. fun main(args: Array<String>) {. val name = if (args.isNotEmpty()) {

    args[0] } else { "World" }. println("Hello, $name!") }.
  49. fun main(args: Array<String>) {. val name = if (args.isNotEmpty()) {

    args[0] } else { "World" }. println("Hello, $name!") }.
  50. fun main(args: Array<String>) {. val name = if (args.isNotEmpty()) {

    args[0] } else { "World" }. println("Hello, $name!") }. Conditional assignment block
  51. fun main(args: Array<String>) { val name = if (args.isNotEmpty()) {

    args[0] } else { "World" }. println("Hello, $name!") }.
  52. fun main(args: Array<String>) { val name = if (args.isNotEmpty()) args[0]

    else "World" println("Hello, $name!") }.
  53. class Person(var name: String) fun main(args: Array<String>) { val name

    = if (args.isNotEmpty()) args[0] else "World" println("Hello, $name!") }.
  54. class Person(var name: String) fun main(args: Array<String>) { val name

    = if (args.isNotEmpty()) args[0] else "World" println("Hello, $name!") } Class keyword
  55. class Person(var name: String) fun main(args: Array<String>) { val name

    = if (args.isNotEmpty()) args[0] else "World" println("Hello, $name!") } Class name
  56. class Person(var name: String) fun main(args: Array<String>) { val name

    = if (args.isNotEmpty()) args[0] else "World" println("Hello, $name!") } Primary constructor
  57. class Person(var name: String) fun main(args: Array<String>) { val name

    = if (args.isNotEmpty()) args[0] else "World" println("Hello, $name!") } Non-final class member
  58. class Person(var name: String) fun main(args: Array<String>) { val name

    = if (args.isNotEmpty()) args[0] else "World" println("Hello, $name!") }
  59. class Person(var name: String) fun main(args: Array<String>) { println("Hello, $name!")

    }
  60. class Person(var name: String) fun main(args: Array<String>) { val person

    = Person("Michael") println("Hello, $name!") }
  61. class Person(var name: String) fun main(args: Array<String>) { val person

    = Person("Michael") println("Hello, $name!") }. Instance declaration
  62. class Person(var name: String) fun main(args: Array<String>) { val person

    = Person("Michael") println("Hello, $name!") }.
  63. class Person(var name: String) fun main(args: Array<String>) { val person

    = Person("Michael") println("Hello, ${person.name}!") }. > Hello, Michael!
  64. enum class Language(val greeting: String) { EN("Hello"), ES("Hola"), FR("Bonjour") }

    class Person(var name: String) fun main(args: Array<String>) { val person = Person("Michael") println("Hello, ${person.name}!") }.
  65. enum class Language(val greeting: String) { EN("Hello"), ES("Hola"), FR("Bonjour") }..

    class Person(var name: String). fun main(args: Array<String>) { val person = Person("Michael") println("Hello, ${person.name}!") }.
  66. enum class Language(val greeting: String) { EN("Hello"), ES("Hola"), FR("Bonjour") }..

    class Person(var name: String, var lang: Language). fun main(args: Array<String>) { val person = Person("Michael") println("Hello, ${person.name}!") }.
  67. enum class Language(val greeting: String) { EN("Hello"), ES("Hola"), FR("Bonjour") }..

    class Person(var name: String, var lang: Language = Language.EN). fun main(args: Array<String>) { val person = Person("Michael") println("Hello, ${person.name}!") }. Default value
  68. enum class Language(val greeting: String) { EN("Hello"), ES("Hola"), FR("Bonjour") }...

    class Person(var name: String, var lang: Language = Language.EN) fun main(args: Array<String>) { val person = Person("Michael") println("Hello, ${person.name}!") }..
  69. enum class Language(val greeting: String) { EN("Hello"), ES("Hola"), FR("Bonjour") }...

    class Person(var name: String, var lang: Language = Language.EN) { fun greet() = println("${lang.greeting}, $name!") }. fun main(args: Array<String>) { val person = Person("Michael") println("Hello, ${person.name}!") }..
  70. enum class Language(val greeting: String) { EN("Hello"), ES("Hola"), FR("Bonjour") }

    class Person(var name: String, var lang: Language = Language.EN) { fun greet() = println("${lang.greeting}, $name!") } fun main(args: Array<String>) { val person = Person("Michael") println("Hello, ${person.name}!") }
  71. enum class Language(val greeting: String) { EN("Hello"), ES("Hola"), FR("Bonjour") }

    class Person(var name: String, var lang: Language = Language.EN) { fun greet() = println("${lang.greeting}, $name!") } fun main(args: Array<String>) { val person = Person("Michael") }
  72. enum class Language(val greeting: String) { EN("Hello"), ES("Hola"), FR("Bonjour") }

    class Person(var name: String, var lang: Language = Language.EN) { fun greet() = println("${lang.greeting}, $name!") } fun main(args: Array<String>) { val person = Person("Michael") person.greet() } > Hello, Michael!
  73. enum class Language(val greeting: String) { EN("Hello"), ES("Hola"), FR("Bonjour") }...

    class Person(var name: String, var lang: Language = Language.EN) { fun greet() = println("${lang.greeting}, $name!") }.. fun main(args: Array<String>) { }.
  74. enum class Language(val greeting: String) { EN("Hello"), ES("Hola"), FR("Bonjour") }...

    class Person(var name: String, var lang: Language = Language.EN) { fun greet() = println("${lang.greeting}, $name!") }.. fun main(args: Array<String>) { val people = listOf( Person("Michael"), Person("Miguel", Language.SP), Person("Michelle", Language.FR) ). }.
  75. enum class Language(val greeting: String) { EN("Hello"), ES("Hola"), FR("Bonjour") }...

    class Person(var name: String, var lang: Language = Language.EN) { fun greet() = println("${lang.greeting}, $name!") }.. fun main(args: Array<String>) { val people = listOf( Person("Michael"), Person("Miguel", Language.SP), Person("Michelle", Language.FR) ). for (person in people) {. person.greet() }. }.
  76. enum class Language(val greeting: String) { EN("Hello"), ES("Hola"), FR("Bonjour") }...

    class Person(var name: String, var lang: Language = Language.EN) { fun greet() = println("${lang.greeting}, $name!") }.. fun main(args: Array<String>) { val people = listOf( Person("Michael"), Person("Miguel", Language.SP), Person("Michelle", Language.FR) ). people.forEach {.person -> person.greet() }. }.
  77. enum class Language(val greeting: String) { EN("Hello"), ES("Hola"), FR("Bonjour") }...

    class Person(var name: String, var lang: Language = Language.EN) { fun greet() = println("${lang.greeting}, $name!") }.. fun main(args: Array<String>) { val people = listOf( Person("Michael"), Person("Miguel", Language.SP), Person("Michelle", Language.FR) ). people.forEach { it.greet() }. }.
  78. enum class Language(val greeting: String) { EN("Hello"), ES("Hola"), FR("Bonjour") }...

    class Person(var name: String, var lang: Language = Language.EN) { fun greet() = println("${lang.greeting}, $name!") }.. fun main(args: Array<String>) { listOf( Person("Michael"), Person("Miguel", Language.SP), Person("Michelle", Language.FR) ).forEach { it.greet() }. }. > Hello, Michael! > Hola, Miguel! > Bonjour, Michelle!
  79. enum class Language(val greeting: String) { EN("Hello"), ES("Hola"), FR("Bonjour") }...

    open class Person(var name: String, var lang: Language = Language.EN) { fun greet() = println("${lang.greeting}, $name!") }.. fun main(args: Array<String>) { listOf( Person("Michael"), Person("Miguel", Language.SP), Person("Michelle", Language.FR) ).forEach { it.greet() }. }. Non-final
  80. enum class Language(val greeting: String) { EN("Hello"), ES("Hola"), FR("Bonjour") }...

    open class Person(var name: String, var lang: Language = Language.EN) { fun greet() = println("${lang.greeting}, $name!") }.. class Hispanophone(name: String) : Person(name, Language.ES) class Francophone(name: String) : Person(name, Language.FR) fun main(args: Array<String>) { listOf( Person("Michael"), Person("Miguel", Language.SP), Person("Michelle", Language.FR) ).forEach { it.greet() } }.
  81. enum class Language(val greeting: String) { EN("Hello"), ES("Hola"), FR("Bonjour") }...

    open class Person(var name: String, var lang: Language = Language.EN) { fun greet() = println("${lang.greeting}, $name!") }.. class Hispanophone(name: String) : Person(name, Language.ES) class Francophone(name: String) : Person(name, Language.FR) fun main(args: Array<String>) { listOf( Person("Michael"), Hispanophone("Miguel"), Francophone("Michelle") ).forEach { it.greet() } }.
  82. enum class Language(val greeting: String) { EN("Hello"), ES("Hola"), FR("Bonjour") }...

    open class Person(var name: String, var lang: Language = Language.EN) { fun greet() = println("${lang.greeting}, $name!") }.. class Hispanophone(name: String) : Person(name, Language.ES) class Francophone(name: String) : Person(name, Language.FR) fun main(args: Array<String>) { listOf( Person("Michael"), Hispanophone("Miguel"), Francophone("Michelle") ).forEach { it.greet() } }.
  83. What Kotlin Adds to Java

  84. Type inference

  85. Type inference String string = "";

  86. Type inference var string: String = ""

  87. Type inference var string = ""

  88. Type inference var string = "" var char = '

    '
  89. Type inference var string = "" var char = '

    ‘ var int = 0
  90. Type inference var string = "" var char = '

    ‘ var int = 0 var long = 0L
  91. Type inference var string = "" var char = '

    ‘ var int = 0 var long = 0L var float = 0F
  92. Type inference var string = "" var char = '

    ‘ var int = 0 var long = 0L var float = 0F var double = 0.0
  93. Type inference var string = "" var char = '

    ' var int = 0 var long = 0L var float = 0F var double = 0.0 var boolean = true
  94. Type inference var string = "" var char = '

    ' var int = 0 var long = 0L var float = 0F var double = 0.0 var boolean = true var foo = MyFooType()
  95. Null-safety

  96. Null-safety String a = null;

  97. Null-safety String a = null; System.out.println(a.length());

  98. Null-safety String a = null; System.out.println(a.length()); NullPointerException

  99. Null-safety val a: String = null

  100. Null-safety val a: String = null Non-null type

  101. Null-safety val a: String? = null

  102. Null-safety val a: String? = null

  103. Null-safety val a: String? = null println(a.length())

  104. Null-safety val a: String? = null println(a.length()) Unsafe call

  105. Null-safety val a: String? = null println(a?.length())

  106. Null-safety val a: String? = null println(a?.length()) > null

  107. Null-safety int length = a != null ? a.length() :

    -1
  108. Null-safety int length = a != null ? a.length() :

    -1 Null check
  109. Null-safety int length = a != null ? a.length() :

    -1 Assignment selector
  110. Null-safety var length = if (a != null) a.length() else

    -1
  111. Null-safety var length = if (a != null) a.length() else

    -1 Null check
  112. Null-safety var length = if (a != null) a.length() else

    -1 Assignment selector
  113. Null-safety var length = a?.length() ?: -1

  114. Null-safety var length = a?.length() ?: -1 Null check

  115. Null-safety var length = a?.length() ?: -1 Assignment selector

  116. Smart casts

  117. Smart casts if (x is String) { print(x.length()) }

  118. Smart casts if (x is String) { print(x.length()) } Type

    check
  119. Smart casts if (x is String) { print(x.length()) } Smart

    cast
  120. Smart casts if (x !is String) { return } print(x.size())

  121. Smart casts if (x !is String) { return } print(x.size())

    Type check
  122. Smart casts if (x !is String) { return } print(x.size())

  123. Smart casts if (x !is String) { return } print(x.size())

    Smart cast
  124. Smart casts if (x !is String || x.size() == 0)

    { return }
  125. Smart casts if (x !is String || x.size() == 0)

    { return } Type check
  126. Smart casts if (x !is String || x.size() == 0)

    { return }
  127. Smart casts if (x !is String || x.size() == 0)

    { return } Smart cast
  128. Smart casts if (x is String && x.size() > 0)

    { print(x.size()) }
  129. Smart casts if (x is String && x.size() > 0)

    { print(x.size()) } Type check
  130. Smart casts if (x is String && x.size() > 0)

    { print(x.size()) }
  131. Smart casts if (x is String && x.size() > 0)

    { print(x.size()) } Smart cast
  132. Smart casts if (x is String && x.size() > 0)

    { print(x.size()) } Smart cast
  133. Smart casts when (x) { is Int -> print(x +

    1) is String -> print(x.size() + 1) is Array<Int> -> print(x.sum()) }
  134. Smart casts when (x) { is Int -> print(x +

    1) is String -> print(x.size() + 1) is Array<Int> -> print(x.sum()) } Type check
  135. Smart casts when (x) { is Int -> print(x +

    1) is String -> print(x.size() + 1) is Array<Int> -> print(x.sum()) } Smart cast
  136. Smart casts when (x) { is Int -> print(x +

    1) is String -> print(x.size() + 1) is Array<Int> -> print(x.sum()) } Type check
  137. Smart casts when (x) { is Int -> print(x +

    1) is String -> print(x.size() + 1) is Array<Int> -> print(x.sum()) } Smart cast
  138. Smart casts when (x) { is Int -> print(x +

    1) is String -> print(x.size() + 1) is Array<Int> -> print(x.sum()) } Type check
  139. Smart casts when (x) { is Int -> print(x +

    1) is String -> print(x.size() + 1) is Array<Int> -> print(x.sum()) } Smart cast
  140. String templates

  141. String templates val apples = 4 println("I have " +

    apples + " apples.") > I have 4 apples.
  142. String templates val apples = 4 println("I have $apples apples.")

    > I have 4 apples. > I have 4 apples.
  143. String templates val apples = 4 val bananas = 3

    println("I have $apples apples and " + (apples + bananas) + " fruits.") > I have 4 apples. > I have 4 apples. > I have 4 apples and 7 fruits.
  144. String templates val apples = 4 val bananas = 3

    println("I have $apples apples and ${apples+bananas} fruits.") > I have 4 apples. > I have 4 apples and 7 fruits. > I have 4 apples and 7 fruits.
  145. Range expressions

  146. Range expressions if (1 <= i && i <= 10)

    { println(i) }
  147. Range expressions if (1 <= i && i <= 10)

    { println(i) }. if (IntRange(1, 10).contains(i)) { println(i) }.
  148. Range expressions if (1 <= i && i <= 10)

    { println(i) }. if (1.rangeTo(10).contains(i)) { println(i) }.
  149. Range expressions if (1 <= i && i <= 10)

    { println(i) }. if (i in 1..10) { println(i) }. Range operator
  150. Range expressions for (i in 1..4) { print(i) }. >

    1234
  151. Range expressions for (i in 1..4 step 2) { print(i)

    }. > 1234 > 13
  152. Range expressions for (i in 4 downTo 1 step 2)

    { print(i) }. > 1234 > 13 > 42
  153. Range expressions for (i in 1.0..2.0) { print("$i ") }.

    > 13 > 42 > 1.0 2.0
  154. Range expressions for (i in 1.0..2.0 step 0.3) { print("$i

    ") }. > 42 > 1.0 2.0 > 1.0 1.3 1.6 1.9
  155. Higher-order functions & lambdas

  156. Higher-order functions & lambdas public interface Function<T, R> { R

    call(T t); }
  157. Higher-order functions & lambdas public interface Function<T, R> { R

    call(T t); } public static <T> List<T> filter(Collection<T> items, Function<T, Boolean> f) { final List<T> filtered = new ArrayList<T>(); for (T item : items) if (f.call(item)) filtered.add(item); return filtered; }
  158. Higher-order functions & lambdas public interface Function<T, R> { R

    call(T t); } public static <T> List<T> filter(Collection<T> items, Function<T, Boolean> f) { final List<T> filtered = new ArrayList<T>(); for (T item : items) if (f.call(item)) filtered.add(item); return filtered; } filter(numbers, new Function<Integer, Boolean>() { @Override public Boolean call(Integer value) { return value % 2 == 0; } });
  159. Higher-order functions & lambdas public interface Function<T, R> { R

    call(T t); } public static <T> List<T> filter(Collection<T> items, Function<T, Boolean> f) { final List<T> filtered = new ArrayList<T>(); for (T item : items) if (f.call(item)) filtered.add(item); return filtered; } filter(numbers, new Function<Integer, Boolean>() { @Override public Boolean call(Integer value) { return value % 2 == 0; } });
  160. Higher-order functions & lambdas public interface Function<T, R> { R

    call(T t); } public static <T> List<T> filter(Collection<T> items, Function<T, Boolean> f) { final List<T> filtered = new ArrayList<T>(); for (T item : items) if (f.call(item)) filtered.add(item); return filtered; } filter(numbers, new Function<Integer, Boolean>() { @Override public Boolean call(Integer value) { return value % 2 == 0; } }); Functional interface
  161. Higher-order functions & lambdas public interface Function<T, R> { R

    call(T t); } public static <T> List<T> filter(Collection<T> items, Function<T, Boolean> f) { final List<T> filtered = new ArrayList<T>(); for (T item : items) if (f.call(item)) filtered.add(item); return filtered; } filter(numbers, new Function<Integer, Boolean>() { @Override public Boolean call(Integer value) { return value % 2 == 0; } }); Interface argument
  162. Higher-order functions & lambdas public interface Function<T, R> { R

    call(T t); } public static <T> List<T> filter(Collection<T> items, Function<T, Boolean> f) { final List<T> filtered = new ArrayList<T>(); for (T item : items) if (f.call(item)) filtered.add(item); return filtered; } filter(numbers, new Function<Integer, Boolean>() { @Override public Boolean call(Integer value) { return value % 2 == 0; } }); Interface function call
  163. Higher-order functions & lambdas public interface Function<T, R> { R

    call(T t); } public static <T> List<T> filter(Collection<T> items, Function<T, Boolean> f) { final List<T> filtered = new ArrayList<T>(); for (T item : items) if (f.call(item)) filtered.add(item); return filtered; } filter(numbers, new Function<Integer, Boolean>() { @Override public Boolean call(Integer value) { return value % 2 == 0; } }); Anonymous implementation
  164. Higher-order functions & lambdas fun <T> filter(items: Collection<T>, f: (T)

    -> Boolean): List<T> { val filtered = arrayListOf<T>() for (item in items) if (f(item)) filtered.add(item) return filtered }
  165. Higher-order functions & lambdas fun <T> filter(items: Collection<T>, f: (T)

    -> Boolean): List<T> { val filtered = arrayListOf<T>() for (item in items) if (f(item)) filtered.add(item) return filtered } filter(numbers, { value -> value % 2 == 0 })
  166. Higher-order functions & lambdas fun <T> filter(items: Collection<T>, f: (T)

    -> Boolean): List<T> { val filtered = arrayListOf<T>() for (item in items) if (f(item)) filtered.add(item) return filtered } filter(numbers, { value -> value % 2 == 0 })
  167. Higher-order functions & lambdas fun <T> filter(items: Collection<T>, f: (T)

    -> Boolean): List<T> { val filtered = arrayListOf<T>() for (item in items) if (f(item)) filtered.add(item) return filtered } filter(numbers, { value -> value % 2 == 0 }) Function type
  168. Higher-order functions & lambdas fun <T> filter(items: Collection<T>, f: (T)

    -> Boolean): List<T> { val filtered = arrayListOf<T>() for (item in items) if (f(item)) filtered.add(item) return filtered } filter(numbers, { value -> value % 2 == 0 }) Function call
  169. Higher-order functions & lambdas fun <T> filter(items: Collection<T>, f: (T)

    -> Boolean): List<T> { val filtered = arrayListOf<T>() for (item in items) if (f(item)) filtered.add(item) return filtered } filter(numbers, { value -> value % 2 == 0 }) Anonymous function
  170. Higher-order functions & lambdas fun <T> filter(items: Collection<T>, f: (T)

    -> Boolean): List<T> { val filtered = arrayListOf<T>() for (item in items) if (f(item)) filtered.add(item) return filtered }. filter(numbers, { value -> value % 2 == 0 } . )
  171. Higher-order functions & lambdas fun <T> filter(items: Collection<T>, f: (T)

    -> Boolean): List<T> { val filtered = arrayListOf<T>() for (item in items) if (f(item)) filtered.add(item) return filtered }. filter(numbers) { value -> value % 2 == 0 } .
  172. Higher-order functions & lambdas fun <T> filter(items: Collection<T>, f: (T)

    -> Boolean): List<T> { val filtered = arrayListOf<T>() for (item in items) if (f(item)) filtered.add(item) return filtered }. filter(numbers) { it % 2 == 0 } .
  173. Higher-order functions & lambdas fun <T> filter(items: Collection<T>, f: (T)

    -> Boolean): List<T> { val filtered = arrayListOf<T>() for (item in items) if (f(item)) filtered.add(item) return filtered }. filter(numbers) { it % 2 == 0 } .
  174. Inline functions

  175. Inline functions fun <T> filter(items: Collection<T>, f: (T) -> Boolean):

    List<T> { val filtered = arrayListOf<T>() for (item in items) if (f(item)) filtered.add(item) return filtered }. filter(numbers) { it % 2 == 0 }
  176. Inline functions inline fun <T> filter(items: Collection<T>, f: (T) ->

    Boolean): List<T> { val filtered = arrayListOf<T>() for (item in items) if (f(item)) filtered.add(item) return filtered }. filter(numbers) { it % 2 == 0 }
  177. Inline functions val filtered = arrayListOf<T>() for (item in items)

    if (it % 2 == 0) filtered.add(item)
  178. Inline functions fun call(f: () -> Unit) { f() }

    call { return }
  179. Inline functions fun call(f: () -> Unit) { f() }

    call { return } Return not allowed
  180. Inline functions fun call(f: () -> Unit) { f() }.

    call { return }.
  181. Inline functions inline fun call(f: () -> Unit) { f()

    }. call { return }.
  182. Inline functions inline fun call(f: () -> Unit) { f()

    }. call { return }. Return allowed
  183. Inline functions inline fun <T : Any> View.findViewParent(): T? {

    var parent = getParent() while (parent != null && parent !is T) { parent = parent.getParent() } return parent as T }
  184. Inline functions inline fun <T : Any> View.findViewParent(): T? {

    var parent = getParent() while (parent != null && parent !is T) { parent = parent.getParent() } return parent as T } Type erasure
  185. Inline functions inline fun <T : Any> View.findViewParent(): T? {

    var parent = getParent() while (parent != null && parent !is T) { parent = parent.getParent() } return parent as T } Unchecked cast
  186. Inline functions inline fun <T : Any> View.findViewParent(): T? {

    var parent = getParent() while (parent != null && parent !is T) { parent = parent.getParent() }. return parent as T }.
  187. Inline functions inline fun <reified T : Any> View.findViewParent(): T?

    { var parent = getParent() while (parent != null && parent !is T) { parent = parent.getParent() }. return parent as T }. Reified type
  188. Inline functions inline fun <reified T : Any> View.findViewParent(): T?

    { var parent = getParent() while (parent != null && parent !is T) { parent = parent.getParent() } return parent as T } Type check allowed
  189. Inline functions inline fun <reified T : Any> View.findViewParent(): T?

    { var parent = getParent() while (parent != null && parent !is T) { parent = parent.getParent() } return parent as T } Type cast allowed
  190. Extension functions

  191. Extension functions public fun isLollipopOrGreater(code: Int): Boolean { return code

    >= Build.VERSION_CODES.LOLLIPOP }.
  192. Extension functions public fun isLollipopOrGreater(code: Int): Boolean { return code

    >= Build.VERSION_CODES.LOLLIPOP }.
  193. Extension functions public fun Int.isLollipopOrGreater(code: Int): Boolean { return code

    >= Build.VERSION_CODES.LOLLIPOP }.
  194. Extension functions public fun Int.isLollipopOrGreater(): Boolean { return code >=

    Build.VERSION_CODES.LOLLIPOP }.
  195. Extension functions public fun Int.isLollipopOrGreater(): Boolean {. return this >=

    Build.VERSION_CODES.LOLLIPOP }..
  196. Extension functions public fun Int.isLollipopOrGreater(): Boolean {. return this >=

    Build.VERSION_CODES.LOLLIPOP }.. if (Build.VERSION.SDK_INT.isLollipopOrGreater) { // ... }.
  197. Extension functions public fun Int.isLollipopOrGreater(): Boolean {. return this >=

    Build.VERSION_CODES.LOLLIPOP }. if (16.isLollipopOrGreater) { // ... }.
  198. Extension functions final Function<Customer, Order> customerMapper = // ... final

    Function<Order, Boolean> orderFilter = // ... final Function<Order, Float> orderSorter = // ... final List<Order> vipOrders = sortBy(filter(map(customers, customerMapper), orderFilter), orderSorter);
  199. Extension functions final Function<Customer, Order> customerMapper = // ... final

    Function<Order, Boolean> orderFilter = // ... final Function<Order, Float> orderSorter = // ... final List<Order> vipOrders = sortBy(filter(map(customers, customerMapper), orderFilter), orderSorter);
  200. Extension functions final Function<Customer, Order> customerMapper = // ... final

    Function<Order, Boolean> orderFilter = // ... final Function<Order, Float> orderSorter = // ... final List<Order> vipOrders = sortBy(filter(map(customers, customerMapper), orderFilter), orderSorter);
  201. Extension functions final Function<Customer, Order> customerMapper = // ... final

    Function<Order, Boolean> orderFilter = // ... final Function<Order, Float> orderSorter = // ... final List<Order> vipOrders = sortBy(filter(map(customers, customerMapper), orderFilter), orderSorter);
  202. Extension functions final Function<Customer, Order> customerMapper = // ... final

    Function<Order, Boolean> orderFilter = // ... final Function<Order, Float> orderSorter = // ... final List<Order> vipOrders = sortBy(filter(map(customers, customerMapper), orderFilter), orderSorter);
  203. Extension functions val vipOrders = customers .map { it.lastOrder }

    .filter { it.total >= 500F } .sortBy { it.total }
  204. Extension functions val vipOrders = customers .map { it.lastOrder }

    .filter { it.total >= 500F } .sortBy { it.total }
  205. Extension functions val vipOrders = customers .map { it.lastOrder }

    .filter { it.total >= 500F } .sortBy { it.total }
  206. Extension functions val vipOrders = customers .map { it.lastOrder }

    .filter { it.total >= 500F } .sortBy { it.total }
  207. Extension functions val vipOrders = customers .map { it.lastOrder }

    .filter { it.total >= 500F } .sortBy { it.total }
  208. Extension functions val vipOrders = customers .map { it.lastOrder }

    .filter { it.total >= 500F } .sortBy { it.total }
  209. Properties

  210. Properties class Customer { private String firstName; private String lastName;

    private String email; public String getFirstName() { return firstName; } public String getLastName() { return lastName; } public String getEmail() { return email; } public void setFirstName(String firstName) { this.firstName = firstName } public void setLastName(String lastName) { this.lastName = lastName } public void setEmail(String email) { this.email = email } }
  211. Properties class Customer { private String firstName; private String lastName;

    private String email; public String getFirstName() { return firstName; } public String getLastName() { return lastName; } public String getEmail() { return email; } public void setFirstName(String firstName) { this.firstName = firstName } public void setLastName(String lastName) { this.lastName = lastName } public void setEmail(String email) { this.email = email } }
  212. Properties class Customer { private String firstName; private String lastName;

    private String email; public String getFirstName() { return firstName; } public String getLastName() { return lastName; } public String getEmail() { return email; } public void setFirstName(String firstName) { this.firstName = firstName } public void setLastName(String lastName) { this.lastName = lastName } public void setEmail(String email) { this.email = email } }
  213. Properties class Customer { private String firstName; private String lastName;

    private String email; public String getFirstName() { return firstName; } public String getLastName() { return lastName; } public String getEmail() { return email; } public void setFirstName(String firstName) { this.firstName = firstName } public void setLastName(String lastName) { this.lastName = lastName } public void setEmail(String email) { this.email = email } }
  214. Properties class Customer { var firstName: String = // ...

    var lastName: String = // ... var email: String = // ... }
  215. Properties class Customer { var firstName: String = // ...

    var lastName: String = // ... var email: String = // ... } val customer = Customer() customer.firstName = "Michael" customer.lastName = "Pardo" customer.email = "michael@michaelpardo.com"
  216. Primary constructors

  217. Primary constructors class Customer {. var firstName: String = //

    ... var lastName: String = // ... var email: String = // ... }.
  218. Primary constructors class Customer(firstName: String, lastName: String, email: String) {.

    var firstName: String = // ... var lastName: String = // ... var email: String = // ... }.
  219. Primary constructors class Customer(firstName: String, lastName: String, email: String) {.

    var firstName: String = firstName var lastName: String = lastName var email: String = email }.
  220. Primary constructors class Customer(firstName: String, lastName: String, email: String) {.

    var firstName: String var lastName: String var email: String init { this.firstName = firstName this.lastName = lastName this.email = email } }.
  221. Primary constructors class Customer(firstName: String, lastName: String, email: String)

  222. Primary constructors class Customer(var firstName: String, var lastName: String, var

    email: String)
  223. Primary constructors class Customer( var firstName: String, var lastName: String,

    var email: String)
  224. Primary constructors class Customer( val firstName: String, val lastName: String,

    val email: String)
  225. Singletons

  226. Singletons public class Singleton { private static volatile Singleton instance;

    private Singleton() { } public static Singleton getInstance() { if (instance == null ) { synchronized (Singleton.class) { if (instance == null) { instance = new Singleton(); } } } return instance; } }
  227. Singletons public class Singleton { private static volatile Singleton instance

    = null; private Singleton() { } public static synchronized Singleton getInstance() { if (instance == null) { instance = new Singleton(); } return instance; } }
  228. Singletons public class Singleton { private static final Singleton INSTANCE

    = new Singleton(); private Singleton() {} public static Singleton getInstance() { return INSTANCE; } }
  229. Singletons public class Singleton { private static final Singleton instance;

    static { try { instance = new Singleton(); } catch (Exception e) { throw new RuntimeException("Darn, an error occurred!", e); } } public static Singleton getInstance() { return instance; } private Singleton() { } }
  230. Singletons public class Singleton { private Singleton() { } private

    static class SingletonHolder { private static final Singleton INSTANCE = new Singleton(); } public static Singleton getInstance() { return SingletonHolder.INSTANCE; } }
  231. Singletons public enum Singleton { INSTANCE; public void execute (String

    arg) { } }
  232. Singletons object Singleton

  233. Singletons object Logger { val tag = "TAG" fun d(message:

    String) { Log.d(tag, message) } }
  234. Companion objects

  235. Companion objects class LaunchActivity extends AppCompatActivity { public static final

    String TAG = LaunchActivity.class.getName(); public static void start(Context context) { context.startActivity(new Intent(context, LaunchActivity.class)); } }
  236. Companion objects class LaunchActivity extends AppCompatActivity { public static final

    String TAG = LaunchActivity.class.getName(); public static void start(Context context) { context.startActivity(new Intent(context, LaunchActivity.class)); } }
  237. Companion objects class LaunchActivity extends AppCompatActivity { public static final

    String TAG = LaunchActivity.class.getName(); public static void start(Context context) { context.startActivity(new Intent(context, LaunchActivity.class)); } }
  238. Companion objects class LaunchActivity extends AppCompatActivity { public static final

    String TAG = LaunchActivity.class.getName(); public static void start(Context context) { context.startActivity(new Intent(context, LaunchActivity.class)); } } Timber.v("Starting activity %s", LaunchActivity.TAG);
  239. Companion objects class LaunchActivity extends AppCompatActivity { public static final

    String TAG = LaunchActivity.class.getName(); public static void start(Context context) { context.startActivity(new Intent(context, LaunchActivity.class)); } } Timber.v("Starting activity %s", LaunchActivity.TAG); LaunchActivity.start(context);
  240. Companion objects class LaunchActivity { companion object { val TAG:

    String = LaunchActivity::class.simpleName fun start(context: Context) { context.startActivity(Intent(context, LaunchActivity::class)) } } }
  241. Companion objects class LaunchActivity { companion object { val TAG:

    String = LaunchActivity::class.simpleName fun start(context: Context) { context.startActivity(Intent(context, LaunchActivity::class)) } } }
  242. Companion objects class LaunchActivity { companion object { val TAG:

    String = LaunchActivity::class.simpleName fun start(context: Context) { context.startActivity(Intent(context, LaunchActivity::class)) } } }
  243. Companion objects class LaunchActivity { companion object { val TAG:

    String = LaunchActivity::class.simpleName fun start(context: Context) { context.startActivity(Intent(context, LaunchActivity::class)) } } }
  244. Companion objects class LaunchActivity { companion object { val TAG:

    String = LaunchActivity::class.simpleName fun start(context: Context) { context.startActivity(Intent(context, LaunchActivity::class)) } } } Timber.v("Starting activity ${LaunchActivity.TAG}")
  245. Companion objects class LaunchActivity { companion object { val TAG:

    String = LaunchActivity::class.simpleName fun start(context: Context) { context.startActivity(Intent(context, LaunchActivity::class)) } } } Timber.v("Starting activity ${LaunchActivity.TAG}") LaunchActivity.start(context)
  246. Class delegation

  247. Class delegation public class MyList<E> implements List<E> { private List<E>

    delegate; public MyList(delegate: List<E>) { this.delegate = delegate; } // ... public E get(int location) { return delegate.get(location) } // ... }
  248. Class delegation public class MyList<E> implements List<E> { private List<E>

    delegate; public MyList(delegate: List<E>) { this.delegate = delegate; } // ... public E get(int location) { return delegate.get(location) } // ... }
  249. Class delegation public class MyList<E> implements List<E> { private List<E>

    delegate; public MyList(delegate: List<E>) { this.delegate = delegate; } // ... public E get(int location) { return delegate.get(location) } // ... }
  250. Class delegation public class MyList<E> implements List<E> { private List<E>

    delegate; public MyList(delegate: List<E>) { this.delegate = delegate; } // ... public E get(int location) { return delegate.get(location) } // ... }
  251. Class delegation public class MyList<E> implements List<E> { private List<E>

    delegate; public MyList(delegate: List<E>) { this.delegate = delegate; } // ... public E get(int location) { return delegate.get(location) } // ... }
  252. Class delegation class MyList<E>(list: List<E>) : List<E> by list

  253. Class delegation class MyList<E>(list: List<E>) : List<E> by list

  254. Class delegation class MyList<E>(list: List<E>) : List<E> by list

  255. Class delegation class MyList<E>(list: List<E>) : List<E> by list

  256. Declaration-site variance

  257. Declaration-site variance String[] strings = { "hello", "world" }; Object[]

    objects = strings;
  258. Declaration-site variance List<String> strings = Arrays.asList("hello", "world"); List<Object> objects =

    strings;
  259. Declaration-site variance List<String> strings = Arrays.asList("hello", "world"); List<Object> objects =

    strings; Error: incompatible types
  260. Declaration-site variance List<String> strings = Arrays.asList("hello", "world"); List<Object> objects =

    strings;
  261. Declaration-site variance List<String> strings = Arrays.asList("hello", "world"); List<? extends Object>

    objects = strings;
  262. Declaration-site variance public interface List<E> extends Collection<E> { public boolean

    addAll(Collection<? extends E> collection); public E get(int location); }
  263. Declaration-site variance public interface List<out E> : Collection<E> { public

    fun get(index: Int): E } public interface MutableList<E> : List<E>, MutableCollection<E> { override fun addAll(c: Collection<E>): Boolean }
  264. Declaration-site variance public interface List<out E> : Collection<E> { public

    fun get(index: Int): E } public interface MutableList<E> : List<E>, MutableCollection<E> { override fun addAll(c: Collection<E>): Boolean }
  265. Declaration-site variance public interface List<out E> : Collection<E> { public

    fun get(index: Int): E } public interface MutableList<E> : List<E>, MutableCollection<E> { override fun addAll(c: Collection<E>): Boolean }
  266. Declaration-site variance val strings: List<String> = listOf("hello", "world") val objects:

    List<Any> = strings
  267. Declaration-site variance val strings: List<String> = arrayListOf("hello", "world") val objects:

    List<Any> = strings
  268. Declaration-site variance val strings: MutableList<String> = arrayListOf("hello", "world") val objects:

    List<Any> = strings
  269. Declaration-site variance val strings: MutableList<String> = arrayListOf("hello", "world") val objects:

    MutableList<Any> = strings
  270. Declaration-site variance val strings: MutableList<String> = arrayListOf("hello", "world") val objects:

    MutableList<Any> = strings Type mismatch
  271. Operator overloading

  272. Operator overloading enum class Coin(val cents: Int) { PENNY(1), NICKEL(5),

    DIME(10), QUARTER(25), }
  273. Operator overloading enum class Coin(val cents: Int) { PENNY(1), NICKEL(5),

    DIME(10), QUARTER(25), }. class Purse(var amount: Float)
  274. Operator overloading enum class Coin(val cents: Int) { PENNY(1), NICKEL(5),

    DIME(10), QUARTER(25), }. class Purse(var amount: Float) { fun plusAssign(coin: Coin): Unit { amount += (coin.cents / 100f) } } Reserved function name
  275. Operator overloading enum class Coin(val cents: Int) { PENNY(1), NICKEL(5),

    DIME(10), QUARTER(25), } class Purse(var amount: Float) { fun plusAssign(coin: Coin): Unit { amount += (coin.cents / 100f) } } var purse = Purse(1.50f)
  276. Operator overloading enum class Coin(val cents: Int) { PENNY(1), NICKEL(5),

    DIME(10), QUARTER(25), } class Purse(var amount: Float) { fun plusAssign(coin: Coin): Unit { amount += (coin.cents / 100f) } } var purse = Purse(1.50f) purse += Coin.QUARTER // 1.75
  277. Operator overloading enum class Coin(val cents: Int) { PENNY(1), NICKEL(5),

    DIME(10), QUARTER(25), } class Purse(var amount: Float) { fun plusAssign(coin: Coin): Unit { amount += (coin.cents / 100f) } } var purse = Purse(1.50f) purse += Coin.QUARTER // 1.75 purse += Coin.DIME // 1.85
  278. Operator overloading enum class Coin(val cents: Int) { PENNY(1), NICKEL(5),

    DIME(10), QUARTER(25), } class Purse(var amount: Float) { fun plusAssign(coin: Coin): Unit { amount += (coin.cents / 100f) } } var purse = Purse(1.50f) purse += Coin.QUARTER // 1.75 purse += Coin.DIME // 1.85 purse += Coin.PENNY // 1.86
  279. Operator overloading a + b a - b a *

    b a / b a % b a == b a != b a +- b a -= b a *= b a /= b a %= b a > b a < b a >= b a <= b a++ a-- a[] a() a..b a in b a !in b
  280. Adding Kotlin to your project

  281. app └── src └── main ├── java └── kotlin

  282. app └── src └── main ├── java └── kotlin

  283. buildscript { repositories { mavenCentral() } dependencies { classpath 'org.jetbrains.kotlin:kotlin-gradle-plugin:<version>'

    } } apply plugin "kotlin-android" sourceSets { main.kotlin.srcDirs += 'src/main/myKotlin' } repositories { mavenCentral() } dependencies { compile 'org.jetbrains.kotlin:kotlin-stdlib:<version>' }
  284. buildscript { repositories { mavenCentral() } dependencies { classpath 'org.jetbrains.kotlin:kotlin-gradle-plugin:<version>'

    } } apply plugin "kotlin-android" sourceSets { main.kotlin.srcDirs += 'src/main/myKotlin' } repositories { mavenCentral() } dependencies { compile 'org.jetbrains.kotlin:kotlin-stdlib:<version>' }
  285. buildscript { repositories { mavenCentral() } dependencies { classpath 'org.jetbrains.kotlin:kotlin-gradle-plugin:<version>'

    } } apply plugin "kotlin-android" sourceSets { main.kotlin.srcDirs += 'src/main/myKotlin' } repositories { mavenCentral() } dependencies { compile 'org.jetbrains.kotlin:kotlin-stdlib:<version>' }
  286. buildscript { repositories { mavenCentral() } dependencies { classpath 'org.jetbrains.kotlin:kotlin-gradle-plugin:<version>'

    } } apply plugin "kotlin-android" sourceSets { main.kotlin.srcDirs += 'src/main/myKotlin' } repositories { mavenCentral() } dependencies { compile 'org.jetbrains.kotlin:kotlin-stdlib:<version>' }
  287. None
  288. Resources • http://kotlinlang.org/docs/reference/ • http://kotlinlang.org/docs/tutorials/koans.html • http://kotlinlang.org/docs/reference/comparison-to-java.html

  289. Questions? @pardom