Kotlin: a better Java Nils Breunese March 2016
Java • Proven technology • Stable • Good performance • Lots of libraries • Good tooling support • But...
Kotlin Imagine a better Java
No Semicolons // Java System.out.println("Hello world!); // Kotlin println("Hello world!")
No Primitives // Java int a = 1; short s = 2; boolean b; // Kotlin var a: Int = 1 var s: Short = 2 var b: Boolean
No 'new' // Java Boa boa = new Boa(); // Kotlin val boa = Boa()
No Checked Exceptions // Java code often looks like this StringBuilder sb = new StringBuilder(); try { sb.append(message); } catch (IOException ignored) { // Must be safe } // Kotlin has no checked exceptions
Type Declaration // Java Int a = 1; String b = "b"; Program p; // Kotlin var a: Int = 1 var b: String = "b" var p: Program
Type Inference // Java Int a = 1; String b = "b"; Program p; // Kotlin var a = 1 var b = "b" var p: Program
Immutable Values // Java final Int a = 1; final String b = "b"; final Program p; // Kotlin val a = 1 val b = "b" val p: Program
String Templates // Java String s = String.format("%s has %d apples", name, count); // Kotlin val s = "$name has $count apples"
Raw Strings // Java doesn't have raw strings String text = "n for (c in "foo"n print(c)n"; // Kotlin val text = """ for (c in "foo") print(c) """
Functions // Java String getName(Person person) { return person.getName(); } // Kotlin fun getName(person: Person): String { return person.name }
Expression Body // Java Int sum(Int a, Int b) { return a + b; } // Kotlin fun sum(a: Int, b: Int): Int { return a + b }
Expression Body // Java Int sum(Int a, Int b) { return a + b; } // Kotlin fun sum(a: Int, b: Int): Int { return a + b } fun sum(a: Int, b: Int) = a + b
Extension Functions // Kotlin fun String.spaceToCamelCase() { ... } "Convert to camelcase".spaceToCamelCase()
If Expression // Java Int max; if (a > b) { max = a } else { max = b }; // OK, Java has a ternary operator Int max = a > b ? a : b; // Kotlin's 'if' is an expression, // so it has a value val max = if (a > b) a else b
When Expression // Java has switch switch(x) { case 1: log.info("x == 1"); break; case 2: log.info("x == 2"); break; default: log.info("x is neither 1 nor 2"); } // Kotlin's when is cleaner and more powerful when (x) { 1 -> log.info("x == 1") 2 -> log.info("x == 2") else -> log.info("x is neither 1 nor 2") }
When Expression when (x) { in 0,1 -> print("x is too low") in 2..10 -> print("x is in range") !in 10..20 -> print("x outside range") parseInt(s) -> print("s encodes x") is Program -> print("It's a program!") else -> print("None of the above") }
Try Expression // In Java 'try' is not an expression Int a = null; try { a = parseInt(input); } catch (NumberFormatException ignored) {} // Kotlin val a: Int? = try { parseInt(input) } catch (e: NumberFormatException) { null }
Nullable Types // Java types can be null Program program = null; ProgramType type = program.getType(); ==> NullPointerException when executed // Kotlin var program: Program = null ==> Compiler error, type not nullable var program: Program? = null val type = program?.type
Not Null Shorthand // Java Program p = mediaService.getProgram(123); String programTypeName = null; if (p != null && p.getType() != null) { programTypeName = p.getType().getName(); } // Kotlin val p = mediaService.getProgram(123) val typeName = p?.type?.name
Not Null Or Else // Java File[] files = new File("test").listFiles(); int count = files != null ? files.size : 0; // Kotlin val files = File("test").listFiles() val count = files?.size ?: 0
Ranges // Java IntStream.rangeClosed(1, 5) .forEach(x -> ...); // Kotlin for (x in 1..5) { ... }
Ranges // Kotlin if (x in 1..y-1) { ... } if (x !in 0..array.lastIndex) { ... }
Collections // Java for (String name : names) { ... } if (names.contains(text)) { ... } // Kotlin for (name in names) { ... } if (text in names) { ... }
Read-Only Collections // Kotlin encourages read-only collections listOf(1, 2, 3, 4) mapOf(1 to "A", 2 to "B") setOf("Hello", "World")
Collections // But it’s easy to create mutable // collections too arrayListOf("Hello", "World") linkedListOf("Hello", "World") hashMapOf(1 to "A", 2 to "B") linkedMapOf(1 to "A", 2 to "B") sortedMapOf(1 to "A", 2 to "B") sortedSetOf(1, 2, 3)
Maps // Java System.out.println(map.get("key")); map.put("key", value); for (Map.Entry<K, V> entry : map.entrySet()) { ... } // Kotlin println(map["key"]) map["key"] = value for ((k, v) in map) { ... }
Lambdas names.stream() .filter(n -> n.startWith("A")) .sorted((n1, n1) -> Integer.compare(n1.length(), n2.length())) .collect(Collectors.toList()); names .filter { n -> n.startsWith("A") } .sortedBy { n -> n.length } .map { n -> n.toUpperCase() }
Lambdas names.stream() .filter(n -> n.startWith("A")) .sorted((n1, n1) -> Integer.compare(n1.length(), n2.length())) .collect(Collectors.toList()); names .filter { it.startsWith("A") } .sortedBy { it.length } .map { it.toUpperCase() }
Classes // Java class Person { String firstName; Person(String firstName) { this.firstName = firstName; } } // Kotlin class with primary constructor class Person(firstName: String)
Classes // Java final class Unextendable { ... } // Kotlin classes are final by default class Unextendable { ... } // Declare as 'open' to allow extension open class Extendable { ... } // Abstract classes are automatically open abstract class Abstract { ... }
Sealed Classes // Kotlin sealed class restricts hierarchy sealed class Expr { class Const(val number: Double) : Expr() class Sum(val e1: Expr, val e2: Expr) : Expr() object NotANumber : Expr() } when(expr) { is Const -> expr.number is Sum -> eval(expr.e1) + eval(expr.e2) NotANumber -> Double.NaN // no 'else' }
DTO's // Java class Broadcaster { final String name; Broadcaster(String n) { name = n; } String getName() { return name; } void setName(String n) { name = n; } int equals() { ... } hashCode() { ... } toString() { ... } copy() { ... } }
DTO's // Kotlin data class Broadcaster(var name: String) // Using 'val' omits the setter data class Broadcaster(val name: String)
Default Arguments // Java doesn't have default arguments void foo(Int a, String b) { if (a == null) { a = 0; } if (b == null) { b = ""; } (...) } // Kotlin fun foo(a: Int = 0, b: String = "") { (...) }
Named Arguments // Kotlin fun reformat( str: String, normalizeCase: Boolean = true, upperCaseFirstLetter: Boolean = true, divideByCamelHumps: Boolean = false, wordSeparator: Char = ' ') { ... } reformat(str, wordSeparator = '_')
Smart Cast // Java Object obj = getObject(); if (obj instanceof String) { return ((String)obj).length() } // Kotlin val obj = getObject() if (obj is String) { return obj.length }
JavaScript Kotlin can also target JavaScript instead of the Java Virtual Machine
Etc., etc. Properties, better generics, delegation, operator overloading, tail recursion, infix functions, destructuring, type-safe builders, with, object expressions, object declarations, companion objects, extension properties, companion object extensions, vararg modifier, ...
Getting started • kotlinlang.org / try.kotlinlang.org • Kotlin Koans • Kotlin Educational Plugin (IDEA 2016.1) • Plugins for Maven and Gradle, Ant tasks (you can mix Java & Kotlin!) • Slack: kotlinslackin.herokuapp.com

Kotlin: a better Java

  • 1.
    Kotlin: a betterJava Nils Breunese March 2016
  • 2.
    Java • Proven technology •Stable • Good performance • Lots of libraries • Good tooling support • But...
  • 3.
  • 4.
    No Semicolons // Java System.out.println("Helloworld!); // Kotlin println("Hello world!")
  • 5.
    No Primitives // Java inta = 1; short s = 2; boolean b; // Kotlin var a: Int = 1 var s: Short = 2 var b: Boolean
  • 6.
    No 'new' // Java Boaboa = new Boa(); // Kotlin val boa = Boa()
  • 7.
    No Checked Exceptions //Java code often looks like this StringBuilder sb = new StringBuilder(); try { sb.append(message); } catch (IOException ignored) { // Must be safe } // Kotlin has no checked exceptions
  • 8.
    Type Declaration // Java Inta = 1; String b = "b"; Program p; // Kotlin var a: Int = 1 var b: String = "b" var p: Program
  • 9.
    Type Inference // Java Inta = 1; String b = "b"; Program p; // Kotlin var a = 1 var b = "b" var p: Program
  • 10.
    Immutable Values // Java finalInt a = 1; final String b = "b"; final Program p; // Kotlin val a = 1 val b = "b" val p: Program
  • 11.
    String Templates // Java Strings = String.format("%s has %d apples", name, count); // Kotlin val s = "$name has $count apples"
  • 12.
    Raw Strings // Javadoesn't have raw strings String text = "n for (c in "foo"n print(c)n"; // Kotlin val text = """ for (c in "foo") print(c) """
  • 13.
    Functions // Java String getName(Personperson) { return person.getName(); } // Kotlin fun getName(person: Person): String { return person.name }
  • 14.
    Expression Body // Java Intsum(Int a, Int b) { return a + b; } // Kotlin fun sum(a: Int, b: Int): Int { return a + b }
  • 15.
    Expression Body // Java Intsum(Int a, Int b) { return a + b; } // Kotlin fun sum(a: Int, b: Int): Int { return a + b } fun sum(a: Int, b: Int) = a + b
  • 16.
    Extension Functions // Kotlin funString.spaceToCamelCase() { ... } "Convert to camelcase".spaceToCamelCase()
  • 17.
    If Expression // Java Intmax; if (a > b) { max = a } else { max = b }; // OK, Java has a ternary operator Int max = a > b ? a : b; // Kotlin's 'if' is an expression, // so it has a value val max = if (a > b) a else b
  • 18.
    When Expression // Javahas switch switch(x) { case 1: log.info("x == 1"); break; case 2: log.info("x == 2"); break; default: log.info("x is neither 1 nor 2"); } // Kotlin's when is cleaner and more powerful when (x) { 1 -> log.info("x == 1") 2 -> log.info("x == 2") else -> log.info("x is neither 1 nor 2") }
  • 19.
    When Expression when (x){ in 0,1 -> print("x is too low") in 2..10 -> print("x is in range") !in 10..20 -> print("x outside range") parseInt(s) -> print("s encodes x") is Program -> print("It's a program!") else -> print("None of the above") }
  • 20.
    Try Expression // InJava 'try' is not an expression Int a = null; try { a = parseInt(input); } catch (NumberFormatException ignored) {} // Kotlin val a: Int? = try { parseInt(input) } catch (e: NumberFormatException) { null }
  • 21.
    Nullable Types // Javatypes can be null Program program = null; ProgramType type = program.getType(); ==> NullPointerException when executed // Kotlin var program: Program = null ==> Compiler error, type not nullable var program: Program? = null val type = program?.type
  • 22.
    Not Null Shorthand //Java Program p = mediaService.getProgram(123); String programTypeName = null; if (p != null && p.getType() != null) { programTypeName = p.getType().getName(); } // Kotlin val p = mediaService.getProgram(123) val typeName = p?.type?.name
  • 23.
    Not Null OrElse // Java File[] files = new File("test").listFiles(); int count = files != null ? files.size : 0; // Kotlin val files = File("test").listFiles() val count = files?.size ?: 0
  • 24.
    Ranges // Java IntStream.rangeClosed(1, 5) .forEach(x-> ...); // Kotlin for (x in 1..5) { ... }
  • 25.
    Ranges // Kotlin if (xin 1..y-1) { ... } if (x !in 0..array.lastIndex) { ... }
  • 26.
    Collections // Java for (Stringname : names) { ... } if (names.contains(text)) { ... } // Kotlin for (name in names) { ... } if (text in names) { ... }
  • 27.
    Read-Only Collections // Kotlinencourages read-only collections listOf(1, 2, 3, 4) mapOf(1 to "A", 2 to "B") setOf("Hello", "World")
  • 28.
    Collections // But it’seasy to create mutable // collections too arrayListOf("Hello", "World") linkedListOf("Hello", "World") hashMapOf(1 to "A", 2 to "B") linkedMapOf(1 to "A", 2 to "B") sortedMapOf(1 to "A", 2 to "B") sortedSetOf(1, 2, 3)
  • 29.
    Maps // Java System.out.println(map.get("key")); map.put("key", value); for(Map.Entry<K, V> entry : map.entrySet()) { ... } // Kotlin println(map["key"]) map["key"] = value for ((k, v) in map) { ... }
  • 30.
    Lambdas names.stream() .filter(n -> n.startWith("A")) .sorted((n1,n1) -> Integer.compare(n1.length(), n2.length())) .collect(Collectors.toList()); names .filter { n -> n.startsWith("A") } .sortedBy { n -> n.length } .map { n -> n.toUpperCase() }
  • 31.
    Lambdas names.stream() .filter(n -> n.startWith("A")) .sorted((n1,n1) -> Integer.compare(n1.length(), n2.length())) .collect(Collectors.toList()); names .filter { it.startsWith("A") } .sortedBy { it.length } .map { it.toUpperCase() }
  • 32.
    Classes // Java class Person{ String firstName; Person(String firstName) { this.firstName = firstName; } } // Kotlin class with primary constructor class Person(firstName: String)
  • 33.
    Classes // Java final classUnextendable { ... } // Kotlin classes are final by default class Unextendable { ... } // Declare as 'open' to allow extension open class Extendable { ... } // Abstract classes are automatically open abstract class Abstract { ... }
  • 34.
    Sealed Classes // Kotlinsealed class restricts hierarchy sealed class Expr { class Const(val number: Double) : Expr() class Sum(val e1: Expr, val e2: Expr) : Expr() object NotANumber : Expr() } when(expr) { is Const -> expr.number is Sum -> eval(expr.e1) + eval(expr.e2) NotANumber -> Double.NaN // no 'else' }
  • 35.
    DTO's // Java class Broadcaster{ final String name; Broadcaster(String n) { name = n; } String getName() { return name; } void setName(String n) { name = n; } int equals() { ... } hashCode() { ... } toString() { ... } copy() { ... } }
  • 36.
    DTO's // Kotlin data classBroadcaster(var name: String) // Using 'val' omits the setter data class Broadcaster(val name: String)
  • 37.
    Default Arguments // Javadoesn't have default arguments void foo(Int a, String b) { if (a == null) { a = 0; } if (b == null) { b = ""; } (...) } // Kotlin fun foo(a: Int = 0, b: String = "") { (...) }
  • 38.
    Named Arguments // Kotlin funreformat( str: String, normalizeCase: Boolean = true, upperCaseFirstLetter: Boolean = true, divideByCamelHumps: Boolean = false, wordSeparator: Char = ' ') { ... } reformat(str, wordSeparator = '_')
  • 39.
    Smart Cast // Java Objectobj = getObject(); if (obj instanceof String) { return ((String)obj).length() } // Kotlin val obj = getObject() if (obj is String) { return obj.length }
  • 40.
    JavaScript Kotlin can alsotarget JavaScript instead of the Java Virtual Machine
  • 41.
    Etc., etc. Properties, bettergenerics, delegation, operator overloading, tail recursion, infix functions, destructuring, type-safe builders, with, object expressions, object declarations, companion objects, extension properties, companion object extensions, vararg modifier, ...
  • 42.
    Getting started • kotlinlang.org/ try.kotlinlang.org • Kotlin Koans • Kotlin Educational Plugin (IDEA 2016.1) • Plugins for Maven and Gradle, Ant tasks (you can mix Java & Kotlin!) • Slack: kotlinslackin.herokuapp.com