Post on 14-Apr-2017
Kotlin: a better JavaNils 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) { ... }
Lambdasnames.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() }
Lambdasnames.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