$30 off During Our Annual Pro Sale. View Details »

What's new in Java 19: The end of Kotlin? (KotlinConf 2019)

What's new in Java 19: The end of Kotlin? (KotlinConf 2019)

Kotlin's introduction was a breath of fresh air at a time when the pace of innovation in Java felt glacial. Since that time, development of Java has rapidly increased with an emphasis on fixing the pain points of the language and the efficiency of data representation in the VM. Will Kotlin still have a place in the JVM language ecosystem in a few years?

This talk will compare and contrast how the two languages approach solving the same problems of today's Java. We'll look at data-carrying types, asynchronous programming, nullability, and more. For some of these, we'll also see how one language sometimes influenced the other. Finally, we'll peer a few years into the future to see where both languages are headed and determine whether we still need a Kotlin (spoiler: we probably do!).

Video: https://youtu.be/te3OU9fxC8U

Jake Wharton
PRO

December 06, 2019
Tweet

More Decks by Jake Wharton

Other Decks in Programming

Transcript

  1. What's new in Java 19:
    The end of Kotlin?
    @JakeWharton

    View Slide

  2. January 23, 1996
    Java 1

    View Slide

  3. September 30, 2004
    Java 5

    View Slide

  4. July 28, 2011
    Java 7

    View Slide

  5. March 18, 2014
    Java 8

    View Slide

  6. September 21, 2017
    Java 9

    View Slide

  7. September 21, 2017
    Java 9
    March 20, 2018
    Java 10

    View Slide

  8. March 20, 2018
    Java 10
    September 25, 2018
    Java 11

    View Slide

  9. September 25, 2018
    Java 11
    March 19, 2019
    Java 12

    View Slide

  10. March 19, 2019
    Java 12
    September 17, 2019
    Java 13

    View Slide

  11. March 2020
    Java 14
    September 2020
    Java 15

    View Slide

  12. March 2021
    Java 16
    September 2021
    Java 17

    View Slide

  13. March 2022
    Java 18
    September 2022
    Java 19

    View Slide

  14. 8
    September 2022
    Java 19

    View Slide

  15. 8
    September 2022
    Java 19 YOU
    ARE
    HERE

    View Slide

  16. Variable Type Inference

    View Slide

  17. var count = 1

    View Slide

  18. var count = 1
    var count = 1

    View Slide

  19. var count = 1
    val users = mutableListOf()
    var count = 1

    View Slide

  20. var count = 1
    val users = mutableListOf()
    var count = 1
    final var users = new ArrayList()

    View Slide

  21. var count = 1
    val users = mutableListOf()
    var default: String? = null
    var count = 1
    final var users = new ArrayList()

    View Slide

  22. var count = 1
    val users = mutableListOf()
    var default: String? = null
    var count = 1
    final var users = new ArrayList()
    String default = null

    View Slide

  23. var count = 1
    val users = mutableListOf()
    var default: String? = null
    val tasks: Deque = ArrayDeque()
    var count = 1
    final var users = new ArrayList()
    String default = null

    View Slide

  24. var count = 1
    val users = mutableListOf()
    var default: String? = null
    val tasks: Deque = ArrayDeque()
    var count = 1
    final var users = new ArrayList()
    String default = null
    Deque tasks = new ArrayDeque<>()

    View Slide

  25. val run1: () -> Unit = { /* .. */ }

    View Slide

  26. val run1: () -> Unit = { /* .. */ }
    val run2 = { /* .. */ }

    View Slide

  27. val run1: () -> Unit = { /* .. */ }
    val run2 = { /* .. */ }
    Runnable run1 = () -> { /* .. */ };

    View Slide

  28. val run1: () -> Unit = { /* .. */ }
    val run2 = { /* .. */ }
    Runnable run1 = () -> { /* .. */ };
    var run2 = () -> { /* .. */ };

    View Slide

  29. val run1: () -> Unit = { /* .. */ }
    val run2 = { /* .. */ }
    Runnable run1 = () -> { /* .. */ };
    var run2 = new Runnable() {
    @Override public void run() {
    /* .. */
    }
    };

    View Slide

  30. var count = 1
    val users = mutableListOf()
    var default: String? = null
    val tasks: Deque = ArrayDeque()
    val run1: () -> Unit = { /* .. */ }
    val run2 = { /* .. */ }
    var count = 1
    final var users = new ArrayList()
    String default = null
    Deque tasks = new ArrayDeque<>()
    Runnable run1 = () -> { /* .. */ };
    var run2 = new Runnable() {
    @Override public void run() { /* .. */ }
    };

    View Slide

  31. Local Functions

    View Slide

  32. fun Graph.any(predicate: (Node) -> Boolean): Boolean {
    val seen = HashSet()
    fun Node.hasMatch(): Boolean {
    if (!seen.add(this)) return false // already seen
    if (predicate(this)) return true // match!
    return nodes.any { it.hasMatch() }
    }
    return root.hasMatch()
    }

    View Slide

  33. fun Graph.any(predicate: (Node) -> Boolean): Boolean {
    val seen = HashSet()
    fun Node.hasMatch(): Boolean {
    if (!seen.add(this)) return false // already seen
    if (predicate(this)) return true // match!
    return nodes.any { it.hasMatch() }
    }
    return root.hasMatch()
    }

    View Slide

  34. fun Graph.any(predicate: (Node) -> Boolean): Boolean {
    val seen = HashSet()
    fun Node.hasMatch(): Boolean {
    if (!seen.add(this)) return false // already seen
    if (predicate(this)) return true // match!
    return nodes.any { it.hasMatch() }
    }
    return root.hasMatch()
    }

    View Slide

  35. fun Graph.any(predicate: (Node) -> Boolean): Boolean {
    val seen = HashSet()
    fun Node.hasMatch(): Boolean {
    if (!seen.add(this)) return false // already seen
    if (predicate(this)) return true // match!
    return nodes.any { it.hasMatch() }
    }
    return root.hasMatch()
    }

    View Slide

  36. fun Graph.any(predicate: (Node) -> Boolean): Boolean {
    val seen = HashSet()
    fun Node.hasMatch(): Boolean {
    if (!seen.add(this)) return false // already seen
    if (predicate(this)) return true // match!
    return nodes.any { it.hasMatch() }
    }
    return root.hasMatch()
    }

    View Slide

  37. fun Graph.any(predicate: (Node) -> Boolean): Boolean {
    val seen = HashSet()
    fun Node.hasMatch(): Boolean {
    if (!seen.add(this)) return false // already seen
    if (predicate(this)) return true // match!
    return nodes.any { it.hasMatch() }
    }
    return root.hasMatch()
    }
    public static boolean any(Predicate predicate) {
    var seen = new HashSet();
    boolean hasMatch(Node node) {
    if (!seen.add(node)) return false; // already seen
    if (predicate.test(node)) return true; // match!
    return node.getNodes().stream().anyMatch(n -> hasMatch(n));
    }
    return hasMatch(getRoot());
    }

    View Slide

  38. public static boolean any(Predicate predicate) {
    var seen = new HashSet();
    boolean hasMatch(Node node) {
    if (!seen.add(node)) return false; // already seen
    if (predicate.test(node)) return true; // match!
    return node.getNodes().stream().anyMatch(n -> hasMatch(n));
    }
    return hasMatch(getRoot());
    }

    View Slide

  39. public static boolean any(
    Graph, java.util.function.Predicate);
    Code:
    0: new #7 // class java/util/HashSet
    3: dup
    4: invokespecial #9 // Method java/util/HashSet."":()V
    7: astore_2
    8: aload_2
    9: aload_1
    10: aload_0
    11: invokevirtual #10 // Method getRoot:()Lcom/example/Node;
    14: invokestatic #16 // Method local$any$0(...)Z
    17: ireturn
    private static boolean local$any$0(
    java.util.HashSet, java.util.function.Predicate, Node);
    Code:
    ...

    View Slide

  40. public static boolean any(
    Graph, java.util.function.Predicate);
    Code:
    0: new #7 // class java/util/HashSet
    3: dup
    4: invokespecial #9 // Method java/util/HashSet."":()V
    7: astore_2
    8: aload_2
    9: aload_1
    10: aload_0
    11: invokevirtual #10 // Method getRoot:()Lcom/example/Node;
    14: invokestatic #16 // Method local$any$0(...)Z
    17: ireturn
    private static boolean local$any$0(
    java.util.HashSet, java.util.function.Predicate, Node);
    Code:
    ...

    View Slide

  41. public static boolean any(
    Graph, java.util.function.Predicate);
    Code:
    0: new #7 // class java/util/HashSet
    3: dup
    4: invokespecial #9 // Method java/util/HashSet."":()V
    7: astore_2
    8: aload_2
    9: aload_1
    10: aload_0
    11: invokevirtual #10 // Method getRoot:()Lcom/example/Node;
    14: invokestatic #16 // Method local$any$0(...)Z
    17: ireturn
    private static boolean local$any$0(
    java.util.HashSet, java.util.function.Predicate, Node);
    Code:
    ...

    View Slide

  42. public static boolean any(Predicate predicate) {
    var seen = new HashSet();
    boolean hasMatch(Node node) {
    if (!seen.add(node)) return false; // already seen
    if (predicate.test(node)) return true; // match!
    return node.getNodes().stream().anyMatch(n -> hasMatch(n));
    }
    return hasMatch(getRoot());
    }

    View Slide

  43. fun Graph.any(predicate: (Node) -> Boolean): Boolean {
    val seen = HashSet()
    fun Node.hasMatch(): Boolean {
    if (!seen.add(this)) return false // already seen
    if (predicate(this)) return true // match!
    return nodes.any { it.hasMatch() }
    }
    return root.hasMatch()
    }

    View Slide

  44. public static boolean any(
    Graph, kotlin.jvm.functions.Function1);
    Code:
    0: new #20 // class java/util/HashSet
    3: dup
    4: invokespecial #24 // Method java/util/HashSet."":()V
    7: astore_2
    8: new #26 // class GraphKt$any$1
    11: dup
    12: aload_2
    13: aload_1
    14: invokespecial #29 // Method GraphKt$any$1."":
    (Ljava/util/HashSet;
    Lkotlin/jvm/functions/Function1;)V
    17: astore_3
    18: aload_3
    19: aload_0
    20: invokeinterface #35, 1 // InterfaceMethod Graph.getRoot:()LNode;
    25: invokevirtual #39 // Method GraphKt$any$1.invoke:(LNode;)Z
    28: ireturn

    View Slide

  45. public static boolean any(
    Graph, kotlin.jvm.functions.Function1);
    Code:
    0: new #20 // class java/util/HashSet
    3: dup
    4: invokespecial #24 // Method java/util/HashSet."":()V
    7: astore_2
    8: new #26 // class GraphKt$any$1
    11: dup
    12: aload_2
    13: aload_1
    14: invokespecial #29 // Method GraphKt$any$1."":
    (Ljava/util/HashSet;
    Lkotlin/jvm/functions/Function1;)V
    17: astore_3
    18: aload_3
    19: aload_0
    20: invokeinterface #35, 1 // InterfaceMethod Graph.getRoot:()LNode;
    25: invokevirtual #39 // Method GraphKt$any$1.invoke:(LNode;)Z
    28: ireturn

    View Slide

  46. public static boolean any(
    Graph, kotlin.jvm.functions.Function1);
    Code:
    0: new #20 // class java/util/HashSet
    3: dup
    4: invokespecial #24 // Method java/util/HashSet."":()V
    7: astore_2
    8: new #26 // class GraphKt$any$1
    11: dup
    12: aload_2
    13: aload_1
    14: invokespecial #29 // Method GraphKt$any$1."":
    (Ljava/util/HashSet;
    Lkotlin/jvm/functions/Function1;)V
    17: astore_3
    18: aload_3
    19: aload_0
    20: invokeinterface #35, 1 // InterfaceMethod Graph.getRoot:()LNode;
    25: invokevirtual #39 // Method GraphKt$any$1.invoke:(LNode;)Z
    28: ireturn

    View Slide

  47. public static boolean any(
    Graph, kotlin.jvm.functions.Function1);
    Code:
    0: new #20 // class java/util/HashSet
    3: dup
    4: invokespecial #24 // Method java/util/HashSet."":()V
    7: astore_2
    8: new #26 // class GraphKt$any$1
    11: dup
    12: aload_2
    13: aload_1
    14: invokespecial #29 // Method GraphKt$any$1."":
    (Ljava/util/HashSet;
    Lkotlin/jvm/functions/Function1;)V
    17: astore_3
    18: aload_3
    19: aload_0
    20: invokeinterface #35, 1 // InterfaceMethod Graph.getRoot:()LNode;
    25: invokevirtual #39 // Method GraphKt$any$1.invoke:(LNode;)Z
    28: ireturn

    View Slide

  48. final class GraphKt$any$1
    extends kotlin.jvm.internal.Lambda
    implements kotlin.jvm.functions.Function1 {
    final java.util.HashSet $seen;
    final kotlin.jvm.functions.Function1 $predicate;
    GraphKt$any$1(java.util.HashSet, kotlin.jvm.functions.Function1);
    Code:
    ...
    public final boolean invoke(Node);
    Code:
    ...
    }

    View Slide

  49. final class GraphKt$any$1
    extends kotlin.jvm.internal.Lambda
    implements kotlin.jvm.functions.Function1 {
    final java.util.HashSet $seen;
    final kotlin.jvm.functions.Function1 $predicate;
    GraphKt$any$1(java.util.HashSet, kotlin.jvm.functions.Function1);
    Code:
    ...
    public final boolean invoke(Node);
    Code:
    ...
    }

    View Slide

  50. final class GraphKt$any$1
    extends kotlin.jvm.internal.Lambda
    implements kotlin.jvm.functions.Function1 {
    final java.util.HashSet $seen;
    final kotlin.jvm.functions.Function1 $predicate;
    GraphKt$any$1(java.util.HashSet, kotlin.jvm.functions.Function1);
    Code:
    ...
    public final boolean invoke(Node);
    Code:
    ...
    }

    View Slide

  51. final class GraphKt$any$1
    extends kotlin.jvm.internal.Lambda
    implements kotlin.jvm.functions.Function1 {
    final java.util.HashSet $seen;
    final kotlin.jvm.functions.Function1 $predicate;
    GraphKt$any$1(java.util.HashSet, kotlin.jvm.functions.Function1);
    Code:
    ...
    public final boolean invoke(Node);
    Code:
    ...
    }

    View Slide

  52. final class GraphKt$any$1
    extends kotlin.jvm.internal.Lambda
    implements kotlin.jvm.functions.Function1 {
    final java.util.HashSet $seen;
    final kotlin.jvm.functions.Function1 $predicate;
    GraphKt$any$1(java.util.HashSet, kotlin.jvm.functions.Function1);
    Code:
    ...
    public final boolean invoke(Node);
    Code:
    ...
    }

    View Slide

  53. fun Graph.any(predicate: (Node) -> Boolean): Boolean {
    val seen = HashSet()
    fun Node.hasMatch(): Boolean {
    if (!seen.add(this)) return false // already seen
    if (predicate(this)) return true // match!
    return nodes.any { it.hasMatch() }
    }
    return root.hasMatch()
    }

    View Slide

  54. fun Graph.any(predicate: (Node) -> Boolean): Boolean {
    val seen = HashSet()
    fun Node.hasMatch(): Boolean {
    if (!seen.add(this)) return false // already seen
    if (predicate(this)) return true // match!
    return nodes.any { it.hasMatch() }
    }
    return root.hasMatch()
    }
    "Optimize generation of local functions"
    youtrack.jetbrains.com/issue/KT-6336

    View Slide

  55. fun Graph.any(predicate: (Node) -> Boolean): Boolean {
    val seen = HashSet()
    fun Node.hasMatch(): Boolean {
    if (!seen.add(this)) return false // already seen
    if (predicate(this)) return true // match!
    return nodes.any { it.hasMatch() }
    }
    return root.hasMatch()
    }
    "Consider more aggresively removing classes from Kotlin local functions"
    issuetracker.google.com/issues/145231155

    View Slide

  56. fun Graph.any(predicate: (Node) -> Boolean): Boolean {
    val seen = HashSet()
    fun Node.hasMatch(): Boolean {
    if (!seen.add(this)) return false // already seen
    if (predicate(this)) return true // match!
    return nodes.any { it.hasMatch() }
    }
    return root.hasMatch()
    }
    public static boolean any(Predicate predicate) {
    var seen = new HashSet();
    boolean hasMatch(Node node) {
    if (!seen.add(node)) return false; // already seen
    if (predicate.test(node)) return true; // match!
    return node.getNodes().stream().anyMatch(n -> hasMatch(n));
    }
    return hasMatch(getRoot());
    }

    View Slide

  57. Multiline Strings

    View Slide

  58. fun main() {
    println("""
    SELECT *
    FROM users
    WHERE name LIKE 'Jake %'
    """)
    }

    View Slide

  59. fun main() {
    println("""
    SELECT *
    FROM users
    WHERE name LIKE 'Jake %'
    """)
    }
    ····SELECT *
    ····FROM users
    ····WHERE name LIKE 'Jake %'
    ··

    View Slide

  60. fun main() {
    println("""
    |SELECT *
    |FROM users
    |WHERE name LIKE 'Jake %'
    |""".trimMargin())
    }
    SELECT *
    FROM users
    WHERE name LIKE 'Jake %'

    View Slide

  61. fun main() {
    println("""
    !!!SELECT *
    !!!FROM users
    !!!WHERE name LIKE 'Jake %'
    !!!""".trimMargin(marginPrefix = "!!!"))
    }
    SELECT *
    FROM users
    WHERE name LIKE 'Jake %'

    View Slide

  62. fun main() {
    println("""
    SELECT *
    FROM users
    WHERE name LIKE 'Jake %'
    """.trimIndent())
    }
    SELECT *
    FROM users
    WHERE name LIKE 'Jake %'
    Margin m
    a
    r
    g
    i
    n
    P
    r
    e
    f
    i
    x = "
    !
    !
    !
    "

    View Slide

  63. fun main() {
    println("""
    SELECT *
    FROM users
    WHERE name LIKE 'Jake %'
    """.trimIndent())
    }
    public static void main(String[] args) {
    System.out.println("""
    SELECT *
    FROM users
    WHERE name LIKE 'Jake %'
    """);
    }

    View Slide

  64. public static void main(String[] args) {
    System.out.println("""
    SELECT *
    FROM users
    WHERE name LIKE 'Jake %'
    """);
    }

    View Slide

  65. public static void main(String[] args) {
    System.out.println("""
    SELECT *
    FROM users
    WHERE name LIKE 'Jake %'
    """);
    }
    SELECT *
    FROM users
    WHERE name LIKE 'Jake %'

    View Slide

  66. public static void main(String[] args) {
    System.out.println("""
    SELECT *
    FROM users
    WHERE name LIKE 'Jake %'
    """);
    }
    SELECT *
    FROM users
    WHERE name LIKE 'Jake %'

    View Slide

  67. public static void main(String[] args) {
    System.out.println("""
    SELECT * \
    FROM users \
    WHERE name LIKE 'Jake %'
    """);
    }
    SELECT * FROM users WHERE name LIKE 'Jake %'

    View Slide

  68. assertThat(table.toString()).isEqualTo("""
    |┌─┬─┐ ╷
    |│ │ │ │
    |├─┤ ╵ │
    |│ │ │
    |└─┼───┘
    | │
    |╶─┴─╴
    |""".trimMargin())

    View Slide

  69. assertThat(table.toString()).isEqualTo("""
    ··|┌─┬─┐·╷
    ··|│·│·│·│
    ··|├─┤·╵·│
    ··|│·│···│
    ··|└─┼───┘
    ··|··│····
    ··|╶─┴─╴··
    ··|""".trimMargin())

    View Slide

  70. assertThat(table.toString()).isEqualTo("""
    ··|┌─┬─┐·╷
    ··|│·│·│·│
    ··|├─┤·╵·│
    ··|│·│···│
    ··|└─┼───┘
    ··|··│····
    ··|╶─┴─╴··
    ··|""".trimMargin())
    assertThat(table.toString()).isEqualTo("""
    ····┌─┬─┐·╷
    ····│·│·│·│
    ····├─┤·╵·│
    ····│·│···│
    ····└─┼───┘
    ······│····
    ····╶─┴─╴··
    ····""");

    View Slide

  71. assertThat(table.toString()).isEqualTo("""
    ··|┌─┬─┐·╷
    ··|│·│·│·│
    ··|├─┤·╵·│
    ··|│·│···│
    ··|└─┼───┘
    ··|··│····
    ··|╶─┴─╴··
    ··|""".trimMargin())
    assertThat(table.toString()).isEqualTo("""
    ····┌─┬─┐·╷
    ····│·│·│·│
    ····├─┤·╵·│
    ····│·│···│
    ····└─┼───┘
    ······│····
    ····╶─┴─╴··
    ····""");

    View Slide

  72. assertThat(table.toString()).isEqualTo("""
    ··|┌─┬─┐·╷
    ··|│·│·│·│
    ··|├─┤·╵·│
    ··|│·│···│
    ··|└─┼───┘
    ··|··│····
    ··|╶─┴─╴··
    ··|""".trimMargin())
    assertThat(table.toString()).isEqualTo("""
    ····┌─┬─┐·╷
    ····│·│·│·│
    ····├─┤·╵·│
    ····│·│···│
    ····└─┼───┘
    ······│···\s
    ····╶─┴─╴·\s
    ····""");

    View Slide

  73. println("""
    Hey $name!
    Hola $name!
    Hello $name!
    """.trimIndent())

    View Slide

  74. public static final void sayHi(java.lang.String);
    Code:
    0: new #17 // class java/lang/StringBuilder
    3: dup
    4: invokespecial #21 // Method java/lang/StringBuilder."":()V
    7: ldc #23 // String \n Hey
    9: invokevirtual #27 // Method java/lang/StringBuilder.append:(…)…;
    12: aload_0
    13: invokevirtual #27 // Method java/lang/StringBuilder.append:(…)…;
    16: ldc #29 // String !\n Hola
    18: invokevirtual #27 // Method java/lang/StringBuilder.append:(…)…;
    21: aload_0
    22: invokevirtual #27 // Method java/lang/StringBuilder.append:(…)…;
    25: ldc #31 // String !\n Hello
    27: invokevirtual #27 // Method java/lang/StringBuilder.append:(…)…;
    30: aload_0
    31: invokevirtual #27 // Method java/lang/StringBuilder.append:(…)…;
    34: ldc #33 // String !\n
    36: invokevirtual #27 // Method java/lang/StringBuilder.append:(…)…;
    39: invokevirtual #37 // Method java/lang/StringBuilder.toString:()Ljava/lang/String;
    42: invokestatic #43 // Method kotlin/text/StringsKt.trimIndent:(Ljava/lang/String;)…;
    45: astore_1
    46: getstatic #49 // Field java/lang/System.out:Ljava/io/PrintStream;
    49: aload_1
    50: invokevirtual #55 // Method java/io/PrintStream.println:(Ljava/lang/Object;)V
    53: return

    View Slide

  75. public static final void sayHi(java.lang.String);
    Code:
    0: new #17 // class java/lang/StringBuilder
    3: dup
    4: invokespecial #21 // Method java/lang/StringBuilder."":()V
    7: ldc #23 // String \n Hey
    9: invokevirtual #27 // Method java/lang/StringBuilder.append:(…)…;
    12: aload_0
    13: invokevirtual #27 // Method java/lang/StringBuilder.append:(…)…;
    16: ldc #29 // String !\n Hola
    18: invokevirtual #27 // Method java/lang/StringBuilder.append:(…)…;
    21: aload_0
    22: invokevirtual #27 // Method java/lang/StringBuilder.append:(…)…;
    25: ldc #31 // String !\n Hello
    27: invokevirtual #27 // Method java/lang/StringBuilder.append:(…)…;
    30: aload_0
    31: invokevirtual #27 // Method java/lang/StringBuilder.append:(…)…;
    34: ldc #33 // String !\n
    36: invokevirtual #27 // Method java/lang/StringBuilder.append:(…)…;
    39: invokevirtual #37 // Method java/lang/StringBuilder.toString:()Ljava/lang/String;
    42: invokestatic #43 // Method kotlin/text/StringsKt.trimIndent:(Ljava/lang/String;)…;
    45: astore_1
    46: getstatic #49 // Field java/lang/System.out:Ljava/io/PrintStream;
    49: aload_1
    50: invokevirtual #55 // Method java/io/PrintStream.println:(Ljava/lang/Object;)V
    53: return

    View Slide

  76. public static final void sayHi(java.lang.String);
    Code:
    0: new #17 // class java/lang/StringBuilder
    3: dup
    4: invokespecial #21 // Method java/lang/StringBuilder."":()V
    7: ldc #23 // String \n Hey
    9: invokevirtual #27 // Method java/lang/StringBuilder.append:(…)…;
    12: aload_0
    13: invokevirtual #27 // Method java/lang/StringBuilder.append:(…)…;
    16: ldc #29 // String !\n Hola
    18: invokevirtual #27 // Method java/lang/StringBuilder.append:(…)…;
    21: aload_0
    22: invokevirtual #27 // Method java/lang/StringBuilder.append:(…)…;
    25: ldc #31 // String !\n Hello
    27: invokevirtual #27 // Method java/lang/StringBuilder.append:(…)…;
    30: aload_0
    31: invokevirtual #27 // Method java/lang/StringBuilder.append:(…)…;
    34: ldc #33 // String !\n
    36: invokevirtual #27 // Method java/lang/StringBuilder.append:(…)…;
    39: invokevirtual #37 // Method java/lang/StringBuilder.toString:()Ljava/lang/String;
    42: invokestatic #43 // Method kotlin/text/StringsKt.trimIndent:(Ljava/lang/String;)…;
    45: astore_1
    46: getstatic #49 // Field java/lang/System.out:Ljava/io/PrintStream;
    49: aload_1
    50: invokevirtual #55 // Method java/io/PrintStream.println:(Ljava/lang/Object;)V
    53: return

    View Slide

  77. println("""
    Hey $name!
    Hola $name!
    Hello $name!
    """.trimIndent())

    View Slide

  78. println("""
    Hey $name!
    Hola $name!
    Hello $name!
    """.trimIndent())
    System.out.println(""
    + "Hey " + name + "!\n"
    + " Hola " + name + "!\n"
    + " Hello " + name + "!");

    View Slide

  79. System.out.println(""
    + "Hey " + name + "!\n"
    + " Hola " + name + "!\n"
    + " Hello " + name + "!");

    View Slide

  80. public static void sayHi(java.lang.String);
    Code:
    0: getstatic #2 // Field java/lang/System.out:…
    3: aload_0
    4: aload_0
    5: aload_0
    6: invokedynamic #3, 0 // InvokeDynamic #0:makeConcatWithConstants:
    (Ljava/lang/String;
    Ljava/lang/String;
    Ljava/lang/String;)Ljava/lang/String;
    11: invokevirtual #4 // Method java/io/PrintStream.println:(…)V
    14: return

    View Slide

  81. public static void sayHi(java.lang.String);
    Code:
    0: getstatic #2 // Field java/lang/System.out:…
    3: aload_0
    4: aload_0
    5: aload_0
    6: invokedynamic #3, 0 // InvokeDynamic #0:makeConcatWithConstants:
    (Ljava/lang/String;
    Ljava/lang/String;
    Ljava/lang/String;)Ljava/lang/String;
    11: invokevirtual #4 // Method java/io/PrintStream.println:(…)V
    14: return

    View Slide

  82. public static void sayHi(java.lang.String);
    Code:
    0: getstatic #2 // Field java/lang/System.out:…
    3: aload_0
    4: aload_0
    5: aload_0
    6: invokedynamic #3, 0 // InvokeDynamic #0:makeConcatWithConstants:
    (Ljava/lang/String;
    Ljava/lang/String;
    Ljava/lang/String;)Ljava/lang/String;
    11: invokevirtual #4 // Method java/io/PrintStream.println:(…)V
    14: return
    BootstrapMethods:
    0: #19 REF_invokeStatic
    java/lang/invoke/StringConcatFactory.makeConcatWithConstants:
    (Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;
    Ljava/lang/invoke/MethodType;Ljava/lang/String;
    [Ljava/lang/Object;)Ljava/lang/invoke/CallSite;
    Method arguments:
    #20 Hey \u0001!\n Hola \u0001!\n Hello \u0001!

    View Slide

  83. public static void sayHi(java.lang.String);
    Code:
    0: getstatic #2 // Field java/lang/System.out:…
    3: aload_0
    4: aload_0
    5: aload_0
    6: invokedynamic #3, 0 // InvokeDynamic #0:makeConcatWithConstants:
    (Ljava/lang/String;
    Ljava/lang/String;
    Ljava/lang/String;)Ljava/lang/String;
    11: invokevirtual #4 // Method java/io/PrintStream.println:(…)V
    14: return
    BootstrapMethods:
    0: #19 REF_invokeStatic
    java/lang/invoke/StringConcatFactory.makeConcatWithConstants:
    (Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;
    Ljava/lang/invoke/MethodType;Ljava/lang/String;
    [Ljava/lang/Object;)Ljava/lang/invoke/CallSite;
    Method arguments:
    #20 Hey \u0001!\n Hola \u0001!\n Hello \u0001!

    View Slide

  84. System.out.println(""
    + "Hey " + name + "!\n"
    + " Hola " + name + "!\n"
    + " Hello " + name + "!");

    View Slide

  85. System.out.println("""
    Hey %s!
    Hola %s!
    Hello %s!
    """.formatted(name, name, name));

    View Slide

  86. public static void sayHi(java.lang.String);
    Code:
    0: getstatic #9 // Field java/lang/System.out:…
    3: aload_0
    4: aload_0
    5: aload_0
    6: invokedynamic #15, 0 // InvokeDynamic #0:format:
    (Ljava/lang/String;
    Ljava/lang/String;
    Ljava/lang/String;)Ljava/lang/String;
    11: invokevirtual #19 // Method java/io/PrintStream.println:(…)V
    14: return

    View Slide

  87. public static void sayHi(java.lang.String);
    Code:
    0: getstatic #9 // Field java/lang/System.out:…
    3: aload_0
    4: aload_0
    5: aload_0
    6: invokedynamic #15, 0 // InvokeDynamic #0:format:
    (Ljava/lang/String;
    Ljava/lang/String;
    Ljava/lang/String;)Ljava/lang/String;
    11: invokevirtual #19 // Method java/io/PrintStream.println:(…)V
    14: return

    View Slide

  88. public static void sayHi(java.lang.String);
    Code:
    0: getstatic #9 // Field java/lang/System.out:…
    3: aload_0
    4: aload_0
    5: aload_0
    6: invokedynamic #15, 0 // InvokeDynamic #0:format:
    (Ljava/lang/String;
    Ljava/lang/String;
    Ljava/lang/String;)Ljava/lang/String;
    11: invokevirtual #19 // Method java/io/PrintStream.println:(…)V
    14: return
    BootstrapMethods:
    0: #34 REF_invokeStatic java/util/Formatter.formatterBootstrap:
    (Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;
    Ljava/lang/invoke/MethodType;Ljava/lang/String;II)…
    Method arguments:
    #41 Hey %s!\n Hola %s!\n Hello %s!
    #43 1
    #44 0

    View Slide

  89. public static void sayHi(java.lang.String);
    Code:
    0: getstatic #9 // Field java/lang/System.out:…
    3: aload_0
    4: aload_0
    5: aload_0
    6: invokedynamic #15, 0 // InvokeDynamic #0:format:
    (Ljava/lang/String;
    Ljava/lang/String;
    Ljava/lang/String;)Ljava/lang/String;
    11: invokevirtual #19 // Method java/io/PrintStream.println:(…)V
    14: return
    BootstrapMethods:
    0: #34 REF_invokeStatic java/util/Formatter.formatterBootstrap:
    (Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;
    Ljava/lang/invoke/MethodType;Ljava/lang/String;II)…
    Method arguments:
    #41 Hey %s!\n Hola %s!\n Hello %s!
    #43 1
    #44 0

    View Slide

  90. System.out.println("""
    Hey %s!
    Hola %s!
    Hello %s!
    """.formatted(name, name, name));

    View Slide

  91. println("""
    Hey $name!
    Hola $name!
    Hello $name!
    """.trimIndent())
    System.out.println("""
    Hey %s!
    Hola %s!
    Hello %s!
    """.formatted(name, name, name));

    View Slide

  92. println("""
    Hey $name!
    Hola $name!
    Hello $name!
    """.trimIndent())
    System.out.println("""
    Hey %s!
    Hola %s!
    Hello %s!
    """.formatted(name, name, name));
    "Indify String Concatenation (StringConcatFactory)"
    youtrack.jetbrains.com/issue/KT-21147

    View Slide

  93. Value-Based Classes

    View Slide

  94. data class Person(val name: String, val age: Int)

    View Slide

  95. data class Person(val name: String, val age: Int)
    record Person(String name, int age) { }

    View Slide

  96. public final class Person {
    private final java.lang.String name;
    private final int age;
    public Person(java.lang.String, int);
    public java.lang.String getName();
    public int getAge();
    public java.lang.String toString();
    public int hashCode();
    public boolean equals(java.lang.Object);
    // copy and component methods omitted…
    }
    public final class Person extends java.lang.Record {
    private final java.lang.String name;
    private final int age;
    public Person(java.lang.String, int);
    public java.lang.String name();
    public int age();
    public java.lang.String toString();
    public int hashCode();
    public boolean equals(java.lang.Object);
    }

    View Slide

  97. public final class Person {
    private final java.lang.String name;
    private final int age;
    public Person(java.lang.String, int);
    public java.lang.String getName();
    public int getAge();
    public java.lang.String toString();
    public int hashCode();
    public boolean equals(java.lang.Object);
    // copy and component methods omitted…
    }
    public final class Person extends java.lang.Record {
    private final java.lang.String name;
    private final int age;
    public Person(java.lang.String, int);
    public java.lang.String name();
    public int age();
    public java.lang.String toString();
    public int hashCode();
    public boolean equals(java.lang.Object);
    }

    View Slide

  98. public final class Person {
    private final java.lang.String name;
    private final int age;
    public Person(java.lang.String, int);
    public java.lang.String getName();
    public int getAge();
    public java.lang.String toString();
    public int hashCode();
    public boolean equals(java.lang.Object);
    // copy and component methods omitted…
    }
    public final class Person extends java.lang.Record {
    private final java.lang.String name;
    private final int age;
    public Person(java.lang.String, int);
    public java.lang.String name();
    public int age();
    public java.lang.String toString();
    public int hashCode();
    public boolean equals(java.lang.Object);
    }

    View Slide

  99. public final class Person {
    private final java.lang.String name;
    private final int age;
    public Person(java.lang.String, int);
    public java.lang.String getName();
    public int getAge();
    public java.lang.String toString();
    public int hashCode();
    public boolean equals(java.lang.Object);
    // copy and component methods omitted…
    }
    public final class Person extends java.lang.Record {
    private final java.lang.String name;
    private final int age;
    public Person(java.lang.String, int);
    public java.lang.String name();
    public int age();
    public java.lang.String toString();
    public int hashCode();
    public boolean equals(java.lang.Object);
    }

    View Slide

  100. public final class Person {
    private final java.lang.String name;
    private final int age;
    public Person(java.lang.String, int);
    public java.lang.String getName();
    public int getAge();
    public java.lang.String toString();
    public int hashCode();
    public boolean equals(java.lang.Object);
    // copy and component methods omitted…
    }
    public final class Person extends java.lang.Record {
    private final java.lang.String name;
    private final int age;
    public Person(java.lang.String, int);
    public java.lang.String name();
    public int age();
    public java.lang.String toString();
    public int hashCode();
    public boolean equals(java.lang.Object);
    }

    View Slide

  101. public java.lang.String getName();
    public int getAge();
    public java.lang.String toString();
    Code:
    0: new #44 // class java/lang/StringBuilder
    3: dup
    4: invokespecial #45 // Method java/lang/StringBuilder."":()V
    7: ldc #47 // String Person(name=
    9: invokevirtual #51 // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
    12: aload_0
    13: getfield #11 // Field name:Ljava/lang/String;
    16: invokevirtual #51 // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
    19: ldc #53 // String , age=
    21: invokevirtual #51 // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
    24: aload_0
    25: getfield #19 // Field age:I
    28: invokevirtual #56 // Method java/lang/StringBuilder.append:(I)Ljava/lang/StringBuilder;
    31: ldc #58 // String )
    33: invokevirtual #51 // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
    36: invokevirtual #60 // Method java/lang/StringBuilder.toString:()Ljava/lang/String;
    39: areturn
    public int hashCode();
    public boolean equals(java.lang.Object);
    // copy and component methods omitted…
    }
    public final class Person extends java.lang.Record {
    private final java.lang.String name;
    private final int age;
    public Person(java.lang.String, int);
    public java.lang.String name();
    public int age();
    public java.lang.String toString();
    public int hashCode();
    public boolean equals(java.lang.Object);
    }

    View Slide

  102. public final class Person extends java.lang.Record {
    private final java.lang.String name;
    private final int age;
    public Person(java.lang.String, int);
    public java.lang.String name();
    public int age();
    public java.lang.String toString();
    Code:
    0: aload_0
    1: invokedynamic #19, 0 // InvokeDynamic #0:toString:(LPerson;)Ljava/lang/String;
    6: areturn
    public int hashCode();
    public boolean equals(java.lang.Object);
    public java.lang.String getName();
    public int getAge();
    public java.lang.String toString();
    Code:
    0: new #44 // class java/lang/StringBuilder
    3: dup
    4: invokespecial #45 // Method java/lang/StringBuilder."":()V
    7: ldc #47 // String Person(name=
    9: invokevirtual #51 // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
    12: aload_0
    13: getfield #11 // Field name:Ljava/lang/String;
    16: invokevirtual #51 // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
    19: ldc #53 // String , age=
    21: invokevirtual #51 // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
    24: aload_0
    25: getfield #19 // Field age:I
    28: invokevirtual #56 // Method java/lang/StringBuilder.append:(I)Ljava/lang/StringBuilder;
    31: ldc #58 // String )
    33: invokevirtual #51 // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
    36: invokevirtual #60 // Method java/lang/StringBuilder.toString:()Ljava/lang/String;
    39: areturn
    public int hashCode();

    View Slide

  103. public final class Person extends java.lang.Record {
    private final java.lang.String name;
    private final int age;
    public Person(java.lang.String, int);
    public java.lang.String name();
    public int age();
    public java.lang.String toString();
    Code:
    0: aload_0
    1: invokedynamic #19, 0 // InvokeDynamic #0:toString:(LPerson;)Ljava/lang/String;
    6: areturn
    public int hashCode();
    public boolean equals(java.lang.Object);
    }

    View Slide

  104. public final class Person extends java.lang.Record {
    private final java.lang.String name;
    private final int age;
    public Person(java.lang.String, int);
    public java.lang.String name();
    public int age();
    public java.lang.String toString();
    Code:
    0: aload_0
    1: invokedynamic #19, 0 // InvokeDynamic #0:toString:(LPerson;)Ljava/lang/String;
    6: areturn
    public int hashCode();
    public boolean equals(java.lang.Object);
    }
    BootstrapMethods:
    0: #42 REF_invokeStatic java/lang/runtime/ObjectMethods.bootstrap:
    (Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;
    Ljava/lang/invoke/TypeDescriptor;Ljava/lang/Class;Ljava/lang/String;
    [Ljava/lang/invoke/MethodHandle;)Ljava/lang/Object;
    Method arguments:
    #8 Person
    #49 name;age
    #51 REF_getField Person.name:Ljava/lang/String;
    #52 REF_getField Person.age:I
    Code:
    0: aload_0
    1: invokedynamic #23, 0 // InvokeDynamic #0:hashCode:(LPerson;)I
    6: areturn

    View Slide

  105. public final class Person extends java.lang.Record {
    private final java.lang.String name;
    private final int age;
    public Person(java.lang.String, int);
    public java.lang.String name();
    public int age();
    public java.lang.String toString();
    Code:
    0: aload_0
    1: invokedynamic #19, 0 // InvokeDynamic #0:toString:(LPerson;)Ljava/lang/String;
    6: areturn
    public int hashCode();
    public boolean equals(java.lang.Object);
    }
    BootstrapMethods:
    0: #42 REF_invokeStatic java/lang/runtime/ObjectMethods.bootstrap:
    (Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;
    Ljava/lang/invoke/TypeDescriptor;Ljava/lang/Class;Ljava/lang/String;
    [Ljava/lang/invoke/MethodHandle;)Ljava/lang/Object;
    Method arguments:
    #8 Person
    #49 name;age
    #51 REF_getField Person.name:Ljava/lang/String;
    #52 REF_getField Person.age:I
    Code:
    0: aload_0
    1: invokedynamic #23, 0 // InvokeDynamic #0:hashCode:(LPerson;)I
    6: areturn

    View Slide

  106. public final class Person extends java.lang.Record {
    private final java.lang.String name;
    private final int age;
    public Person(java.lang.String, int);
    public java.lang.String name();
    public int age();
    public java.lang.String toString();
    public int hashCode();
    Code:
    0: aload_0
    1: invokedynamic #23, 0 // InvokeDynamic #0:hashCode:(LPerson;)I
    6: areturn
    public boolean equals(java.lang.Object);
    }
    BootstrapMethods:
    0: #42 REF_invokeStatic java/lang/runtime/ObjectMethods.bootstrap:
    (Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;
    Ljava/lang/invoke/TypeDescriptor;Ljava/lang/Class;Ljava/lang/String;
    [Ljava/lang/invoke/MethodHandle;)Ljava/lang/Object;
    Method arguments:
    #8 Person
    #49 name;age
    #51 REF_getField Person.name:Ljava/lang/String;
    #52 REF_getField Person.age:I
    Code:
    0: aload_0
    1: invokedynamic #19, 0 // InvokeDynamic #0:toString:(LPerson;)Ljava/lang/String;
    6: areturn

    View Slide

  107. public final class Person extends java.lang.Record {
    private final java.lang.String name;
    private final int age;
    public Person(java.lang.String, int);
    public java.lang.String name();
    public int age();
    public java.lang.String toString();
    public int hashCode();
    public boolean equals(java.lang.Object);
    Code:
    0: aload_0
    1: invokedynamic #27, 0 // InvokeDynamic #0:equals:(LPerson;Ljava/lang/Object;)Z
    6: areturn
    }
    BootstrapMethods:
    0: #42 REF_invokeStatic java/lang/runtime/ObjectMethods.bootstrap:
    (Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;
    Ljava/lang/invoke/TypeDescriptor;Ljava/lang/Class;Ljava/lang/String;
    [Ljava/lang/invoke/MethodHandle;)Ljava/lang/Object;
    Method arguments:
    #8 Person
    #49 name;age
    #51 REF_getField Person.name:Ljava/lang/String;
    #52 REF_getField Person.age:I
    Code:
    0: aload_0
    1: invokedynamic #23, 0 // InvokeDynamic #0:hashCode:(LPerson;)I
    6: areturn
    Code:
    0: aload_0
    1: invokedynamic #27, 0 /q InvokeDynamic #0:equals:(LPerson;Ljava/lang/Object;)Z
    6: areturn

    View Slide

  108. public final class Person {
    private final java.lang.String name;
    private final int age;
    public Person(java.lang.String, int);
    public java.lang.String getName();
    public int getAge();
    public java.lang.String toString();
    public int hashCode();
    public boolean equals(java.lang.Object);
    // copy and component methods omitted…
    }
    public final class Person extends java.lang.Record {
    private final java.lang.String name;
    private final int age;
    public Person(java.lang.String, int);
    public java.lang.String name();
    public int age();
    public java.lang.String toString();
    public int hashCode();
    public boolean equals(java.lang.Object);
    }
    Code:
    0: aload_0
    1: invokedynamic #27, 0 // InvokeDynamic #0:equals:(LPerson;Ljava/lang/Object;)Z
    6: areturn

    View Slide

  109. data class Person(val name: String, val age: Int)
    record Person(String name, int age) { }

    View Slide

  110. data class Person(val name: String, val age: Int)
    record Person(String name, int age) { }
    "Use StringConcatFactory for data class toString when targeting JVM 9+ "
    youtrack.jetbrains.com/issue/KT-35176

    View Slide

  111. Sealed Hierarchies

    View Slide

  112. data class Person(val name: String, val age: Int)

    View Slide

  113. sealed class Developer
    data class Person(val name: String, val age: Int) : Developer()
    data class Business(val name: String) : Developer()

    View Slide

  114. sealed class Developer
    data class Person(val name: String, val age: Int) : Developer()
    data class Business(val name: String) : Developer()
    record Person(String name, int age) { }

    View Slide

  115. sealed class Developer
    data class Person(val name: String, val age: Int) : Developer()
    data class Business(val name: String) : Developer()
    sealed class Developer { }
    record Person(String name, int age) extends Developer { }
    record Business(String name) extends Developer { }

    View Slide

  116. sealed class Developer
    data class Person(val name: String, val age: Int) : Developer()
    data class Business(val name: String) : Developer()
    class
    extends
    extends
    sealed interface Developer { }
    record Person(String name, int age) implements Developer { }
    record Business(String name) implements Developer { }

    View Slide

  117. sealed class Developer {
    abstract val name: String
    }
    data class Person(override val name: String, val age: Int) : Developer()
    data class Business(override val name: String) : Developer()
    sealed interface Developer { }
    record Person(String name, int age) implements Developer { }
    record Business(String name) implements Developer { }

    View Slide

  118. sealed class Developer {
    abstract val name: String
    }
    data class Person(override val name: String, val age: Int) : Developer()
    data class Business(override val name: String) : Developer()
    sealed interface Developer {
    String name();
    }
    record Person(@Override String name, int age) implements Developer { }
    record Business(@Override String name) implements Developer { }

    View Slide

  119. public abstract class Developer {
    public abstract java.lang.String getName();
    private Developer();
    public synthetic Developer(kotlin.jvm.internal.DefaultConstructorMarker);
    }
    public interface Developer {
    public abstract java.lang.String name();
    }
    PermittedSubtypes:
    Person
    Business

    View Slide

  120. public abstract class Developer {
    public abstract java.lang.String getName();
    private Developer();
    public synthetic Developer(kotlin.jvm.internal.DefaultConstructorMarker);
    }
    public interface Developer {
    public abstract java.lang.String name();
    }
    PermittedSubtypes:
    Person
    Business

    View Slide

  121. public abstract class Developer {
    public abstract java.lang.String getName();
    private Developer();
    public synthetic Developer(kotlin.jvm.internal.DefaultConstructorMarker);
    }
    public interface Developer {
    public abstract java.lang.String name();
    }
    PermittedSubtypes:
    Person
    Business

    View Slide

  122. sealed class Developer {
    abstract val name: String
    }
    data class Person(override val name: String, val age: Int) : Developer()
    data class Business(override val name: String) : Developer()
    sealed interface Developer {
    String name();
    }
    record Person(@Override String name, int age) implements Developer { }
    record Business(@Override String name) implements Developer { }

    View Slide

  123. Type Matching

    View Slide

  124. val o: Any = 1

    View Slide

  125. val o: Any = 1
    if (o is Int) {
    }

    View Slide

  126. val o: Any = 1
    if (o is Int) {
    println(o + 1)
    }

    View Slide

  127. val o: Any = 1
    if (o is Int) {
    println(o + 1)
    }
    Object o = 1;
    if (o instanceof Integer i) {
    System.out.println(i + 1);
    }

    View Slide

  128. Object o = 1;
    if (o instanceof Integer i) {
    System.out.println(i + 1);
    }

    View Slide

  129. Object o = 1;
    if (o instanceof Integer) {
    Integer i = (Integer) o;
    System.out.println(i + 1);
    }

    View Slide

  130. Object o = 1;
    if (o instanceof Integer) {
    Integer i = (Integer) o;
    System.out.println(i + 1);
    }
    static void record(Object o) {
    objects.add(o);
    }
    static void record(Number n) {
    sum += n.intValue();
    }

    View Slide

  131. Object o = 1;
    if (o instanceof Integer) {
    Integer i = (Integer) o;
    System.out.println(i + 1);
    record(o);
    }
    static void record(Object o) {
    objects.add(o);
    }
    static void record(Number n) {
    sum += n.intValue();
    }

    View Slide

  132. Object o = 1;
    if (o instanceof Integer) {
    System.out.println(o + 1);
    record(o);
    }
    static void record(Object o) {
    objects.add(o);
    }
    static void record(Number n) {
    sum += n.intValue();
    }

    View Slide

  133. Object o = 1;
    if (o instanceof Integer) {
    System.out.println(o + 1);
    record(o);
    }
    static void record(Object o) {
    objects.add(o);
    }
    static void record(Number n) {
    sum += n.intValue();
    }

    View Slide

  134. Object o = 1;
    if (o instanceof Integer) {
    System.out.println(o + 1);
    record(o);
    }
    static void record(Object o) {
    objects.add(o);
    }
    static void record(Number n) {
    sum += n.intValue();
    }

    View Slide

  135. Object o = 1;
    if (o instanceof Integer i) {
    System.out.println(i + 1);
    record(o);
    }
    static void record(Object o) {
    objects.add(o);
    }
    static void record(Number n) {
    sum += n.intValue();
    }

    View Slide

  136. val o: Any = 1
    if (o is Int) {
    println(o + 1)
    }
    Object o = 1;
    if (o instanceof Integer i) {
    System.out.println(i + 1);
    }
    record(o);
    static void record(Object o) {
    objects.add(o);
    }
    static void record(Number n) {
    sum += n.intValue();

    View Slide

  137. Destructuring

    View Slide

  138. data class Person(val name: String, val age: Int)

    View Slide

  139. data class Person(val name: String, val age: Int)
    val alice = Person("Alice", 12)

    View Slide

  140. data class Person(val name: String, val age: Int)
    val alice = Person("Alice", 12)
    val (name, age) = alice

    View Slide

  141. data class Person(val name: String, val age: Int)
    val alice = Person("Alice", 12)
    val (name, age) = alice
    val people = listOf(alice)
    for ((name, age) in people) {
    // ..
    }

    View Slide

  142. data class Person(val name: String, val age: Int)
    val alice = Person("Alice", 12)
    val (name, age) = alice
    val people = listOf(alice)
    for ((name, age) in people) {
    // ..
    }
    val display = people.map { (name, age) -> "$name is $age years old" }

    View Slide

  143. data class Person(val name: String, val age: Int)
    val alice = Person("Alice", 12)
    val (name, age) = alice

    View Slide

  144. data class Person(val name: String, val age: Int)
    val alice = Person("Alice", 12)
    val (name, age) = alice

    View Slide


  145. 10: aload_0
    11: invokevirtual #12 // Method Person.component1:()Ljava/lang/String;
    14: astore_1
    15: aload_0
    16: invokevirtual #16 // Method Person.component2:()I
    19: istore_2

    View Slide

  146. public final class Person {
    private final java.lang.String name;
    private final int age;
    public Person(java.lang.String, int);
    public java.lang.String getName();
    public int getAge();
    public java.lang.String toString();
    public int hashCode();
    public boolean equals(java.lang.Object);
    // copy and component methods omitted…
    }

    View Slide

  147. public final class Person {
    private final java.lang.String name;
    private final int age;
    public Person(java.lang.String, int);
    public java.lang.String getName();
    public int getAge();
    public java.lang.String toString();
    public int hashCode();
    public boolean equals(java.lang.Object);
    // copy methods omitted…
    public java.lang.String component1();
    public int component2();
    }
    a
    n
    d c
    o
    m
    p
    o
    n
    e
    n
    t

    View Slide

  148. data class Person(val name: String, val age: Int)
    val alice = Person("Alice", 12)
    val (name, age) = alice

    View Slide

  149. data class Person(
    val name: String,
    val nickname: String,
    val age: Int
    )
    val alice = Person("Alice", "Ali", 12)
    val (name, age) = alice

    View Slide

  150. public final class Person {
    private final java.lang.String name;
    private final int age;
    public Person(java.lang.String, int);
    public java.lang.String getName();
    public int getAge();
    public java.lang.String toString();
    public int hashCode();
    public boolean equals(java.lang.Object);
    // copy methods omitted…
    public java.lang.String component1();
    public int component2();
    }

    View Slide

  151. public final class Person {
    private final java.lang.String name;
    + private final java.lang.String nickname;
    private final int age;
    - public Person(java.lang.String, int);
    + public Person(java.lang.String, java.lang.String, int);
    public java.lang.String getName();
    + public java.lang.String getNickname();
    public int getAge();
    public java.lang.String toString();
    public int hashCode();
    public boolean equals(java.lang.Object);
    // copy methods omitted…
    public java.lang.String component1();
    - public int component2();
    + public java.lang.String component2();
    + public int component3();
    }

    View Slide

  152. public final class Person {
    private final java.lang.String name;
    + private final java.lang.String nickname;
    private final int age;
    - public Person(java.lang.String, int);
    + public Person(java.lang.String, java.lang.String, int);
    public java.lang.String getName();
    + public java.lang.String getNickname();
    public int getAge();
    public java.lang.String toString();
    public int hashCode();
    public boolean equals(java.lang.Object);
    // copy methods omitted…
    public java.lang.String component1();
    - public int component2();
    + public java.lang.String component2();
    + public int component3();
    }

    View Slide

  153. data class Person(val name: String, val age: Int)
    val alice = Person("Alice", 12)
    val (name, age) = alice

    View Slide

  154. data class Person(val name: String, val age: Int)
    val alice = Person("Alice", 12)
    val (name, age) = alice
    record Person(String name, int age) { }
    var alice = new Person("Alice", 12);

    View Slide

  155. data class Person(val name: String, val age: Int)
    val alice = Person("Alice", 12)
    val (name, age) = alice
    record Person(String name, int age) { }
    Object alice = new Person("Alice", 12);

    View Slide

  156. data class Person(val name: String, val age: Int)
    val alice = Person("Alice", 12)
    val (name, age) = alice
    record Person(String name, int age) { }
    Object alice = new Person("Alice", 12);
    if (alice instanceof Person alicePerson) {
    // ...
    }

    View Slide

  157. data class Person(val name: String, val age: Int)
    val alice = Person("Alice", 12)
    val (name, age) = alice
    record Person(String name, int age) { }
    Object alice = new Person("Alice", 12);
    if (alice instanceof Person(var name, var age)) {
    // ...
    }
    alicePerson

    View Slide

  158. data class Person(val name: String, val age: Int)
    val alice: Any = Person("Alice", 12)
    if (alice is Person) {
    val (name, age) = alice
    // ...
    }
    record Person(String name, int age) { }
    Object alice = new Person("Alice", 12);
    if (alice instanceof Person(var name, var age)) {
    // ...
    }

    View Slide

  159. record Person(String name, int age) { }
    Object alice = new Person("Alice", 12);
    if (alice instanceof Person(var name, var age)) {
    // ...
    }

    View Slide

  160. public final class Person extends java.lang.Record {
    private final java.lang.String name;
    private final int age;
    public Person(java.lang.String, int);
    public java.lang.String name();
    public int age();
    public java.lang.String toString();
    public int hashCode();
    public boolean equals(java.lang.Object);
    }

    View Slide

  161. public final class Person extends java.lang.Record {
    private final java.lang.String name;
    private final int age;
    public Person(java.lang.String, int);
    public java.lang.String name();
    public int age();
    public java.lang.String toString();
    public int hashCode();
    public boolean equals(java.lang.Object);
    public static java.lang.runtime.PatternHandle
    %pattern%Person%(Ljava|lang|String?I)();
    }

    View Slide

  162. public final class Person extends java.lang.Record {
    private final java.lang.String name;
    private final int age;
    public Person(java.lang.String, int);
    public java.lang.String name();
    public int age();
    public java.lang.String toString();
    public int hashCode();
    public boolean equals(java.lang.Object);
    public static java.lang.runtime.PatternHandle
    %pattern%Person%(Ljava|lang|String?I)();
    }

    View Slide

  163. record Person(String name, int age) { }
    Object alice = new Person("Alice", 12);
    if (alice instanceof Person(var name, var age)) {
    // ...
    }

    View Slide

  164. record Person(String name, String nickname, int age) { }
    Object alice = new Person("Alice", "Ali", 12);
    if (alice instanceof Person(var name, var age)) {
    // ...
    }

    View Slide

  165. public final class Person extends java.lang.Record {
    private final java.lang.String name;
    private final int age;
    public Person(java.lang.String, int);
    public java.lang.String name();
    public int age();
    public java.lang.String toString();
    public int hashCode();
    public boolean equals(java.lang.Object);
    public static java.lang.runtime.PatternHandle
    %pattern%Person%(Ljava|lang|String?I)();
    }

    View Slide

  166. public final class Person extends java.lang.Record {
    private final java.lang.String name;
    + private final java.lang.String nickname;
    private final int age;
    - public Person(java.lang.String, int);
    + public Person(java.lang.String, java.lang.String, int);
    public java.lang.String name();
    + public java.lang.String nickname();
    public int age();
    public java.lang.String toString();
    public int hashCode();
    public boolean equals(java.lang.Object);
    - public static java.lang.runtime.PatternHandle
    %pattern%Person%(Ljava|lang|String?I)();
    + public static java.lang.runtime.PatternHandle
    %pattern%Person%(Ljava|lang|String?Ljava|lang|String?I)();
    }

    View Slide

  167. public final class Person extends java.lang.Record {
    private final java.lang.String name;
    + private final java.lang.String nickname;
    private final int age;
    - public Person(java.lang.String, int);
    + public Person(java.lang.String, java.lang.String, int);
    public java.lang.String name();
    + public java.lang.String nickname();
    public int age();
    public java.lang.String toString();
    public int hashCode();
    public boolean equals(java.lang.Object);
    - public static java.lang.runtime.PatternHandle
    %pattern%Person%(Ljava|lang|String?I)();
    + public static java.lang.runtime.PatternHandle
    %pattern%Person%(Ljava|lang|String?Ljava|lang|String?I)();
    }

    View Slide

  168. record Person(String name, String nickname, int age) { }

    View Slide

  169. record Person(String name, String nickname, int age) {
    Person(String name, int age) {
    this(name, null, age);
    }
    }

    View Slide

  170. record Person(String name, String nickname, int age) {
    Person(String name, int age) {
    this(name, null, age);
    }
    // WARNING: 100% made-up syntax by me!
    destructor Person(String, int) {
    return p -> deconstruct(Person::name, Person::age);
    }
    }

    View Slide

  171. public final class Person extends java.lang.Record {
    private final java.lang.String name;
    + private final java.lang.String nickname;
    private final int age;
    - public Person(java.lang.String, int);
    + public Person(java.lang.String, java.lang.String, int);
    public java.lang.String name();
    + public java.lang.String nickname();
    public int age();
    public java.lang.String toString();
    public int hashCode();
    public boolean equals(java.lang.Object);
    - public static java.lang.runtime.PatternHandle
    %pattern%Person%(Ljava|lang|String?I)();
    + public static java.lang.runtime.PatternHandle
    %pattern%Person%(Ljava|lang|String?Ljava|lang|String?I)();
    }

    View Slide

  172. public final class Person extends java.lang.Record {
    private final java.lang.String name;
    + private final java.lang.String nickname;
    private final int age;
    public Person(java.lang.String, int);
    + public Person(java.lang.String, java.lang.String, int);
    public java.lang.String name();
    + public java.lang.String nickname();
    public int age();
    public java.lang.String toString();
    public int hashCode();
    public boolean equals(java.lang.Object);
    public static java.lang.runtime.PatternHandle
    %pattern%Person%(Ljava|lang|String?I)();
    + public static java.lang.runtime.PatternHandle
    %pattern%Person%(Ljava|lang|String?Ljava|lang|String?I)();
    }

    View Slide

  173. public final class Person extends java.lang.Record {
    private final java.lang.String name;
    + private final java.lang.String nickname;
    private final int age;
    public Person(java.lang.String, int);
    + public Person(java.lang.String, java.lang.String, int);
    public java.lang.String name();
    + public java.lang.String nickname();
    public int age();
    public java.lang.String toString();
    data class Person(val name: String, val age: Int)
    val alice: Any = Person("Alice", 12)
    if (alice is Person) {
    val (name, age) = alice
    // ...
    }
    record Person(String name, int age) { }
    Object alice = new Person("Alice", 12);
    if (alice instanceof Person(var name, var age)) {
    // ...
    }

    View Slide

  174. public final class Person extends java.lang.Record {
    private final java.lang.String name;
    + private final java.lang.String nickname;
    private final int age;
    public Person(java.lang.String, int);
    + public Person(java.lang.String, java.lang.String, int);
    public java.lang.String name();
    + public java.lang.String nickname();
    public int age();
    public java.lang.String toString();
    sealed class Developer
    data class Person(val name: String, val age: Int): Developer()
    data class Business(val name: String): Developer()
    val alice: Any = Person("Alice", 12)
    if (alice is Person) {
    val (name, age) = alice
    // ...
    }
    sealed interface Developer { }
    record Person(String name, int age) implements Developer { }
    record Business(String name) implements Developer { }
    Object alice = new Person("Alice", 12);
    if (alice instanceof Person(var name, var age)) {
    // ...
    }

    View Slide

  175. sealed interface Developer { }
    record Person(String name, int age) implements Developer { }
    record Business(String name) implements Developer { }
    Object alice = new Person("Alice", 12);
    if (alice instanceof Person(var name, var age)) {
    // ...
    }
    sealed class Developer
    data class Person(val name: String, val age: Int): Developer()
    data class Business(val name: String): Developer()
    val alice: Any = Person("Alice", 12)
    if (alice is Person) {
    val (name, age) = alice
    // ...
    }
    public final class Person extends java.lang.Record {
    private final java.lang.String name;
    + private final java.lang.String nickname;
    private final int age;
    public Person(java.lang.String, int);
    + public Person(java.lang.String, java.lang.String, int);
    public java.lang.String name();
    + public java.lang.String nickname();
    public int age();
    public java.lang.String toString();

    View Slide

  176. sealed class Developer
    data class Person(val name: String, val age: Int): Developer()
    data class Business(val name: String): Developer()
    val alice: Developer = Person("Alice", 12)
    if (alice is Person) {
    val (name, age) = alice
    // ...
    }
    sealed interface Developer { }
    record Person(String name, int age) implements Developer { }
    record Business(String name) implements Developer { }
    Developer alice = new Person("Alice", 12);
    if (alice instanceof Person(var name, var age)) {
    // ...
    }
    Object
    public final class Person extends java.lang.Record {
    private final java.lang.String name;
    + private final java.lang.String nickname;
    private final int age;
    public Person(java.lang.String, int);
    + public Person(java.lang.String, java.lang.String, int);
    public java.lang.String name();
    + public java.lang.String nickname();
    public int age();
    public java.lang.String toString();

    View Slide

  177. public final class Person extends java.lang.Record {
    private final java.lang.String name;
    + private final java.lang.String nickname;
    private final int age;
    public Person(java.lang.String, int);
    + public Person(java.lang.String, java.lang.String, int);
    public java.lang.String name();
    + public java.lang.String nickname();
    public int age();
    public java.lang.String toString();
    sealed class Developer
    data class Person(val name: String, val age: Int): Developer()
    data class Business(val name: String): Developer()
    val alice: Developer = Person("Alice", 12)
    if (alice is Person) {
    val (name, age) = alice
    // ...
    }
    sealed interface Developer { }
    record Person(String name, int age) implements Developer { }
    record Business(String name) implements Developer { }
    Developer alice = new Person("Alice", 12);
    if (alice instanceof Person(var name, var age)) {
    // ...
    }
    Object

    View Slide

  178. sealed class Developer
    data class Person(val name: String, val age: Int): Developer()
    data class Business(val name: String): Developer()
    val alice: Developer = Person("Alice", 12)
    if (alice is Person) {
    val (name, age) = alice
    // ...
    }

    View Slide

  179. sealed class Developer
    data class Person(val name: String, val age: Int): Developer()
    data class Business(val name: String): Developer()
    val alice: Developer = Person("Alice", 12)
    when (alice) {
    is Person -> {
    val (name, age) = alice
    // ...
    }
    is Business -> {
    // ...
    }
    }
    if

    View Slide

  180. public final class Person extends java.lang.Record {
    private final java.lang.String name;
    + private final java.lang.String nickname;
    private final int age;
    public Person(java.lang.String, int);
    + public Person(java.lang.String, java.lang.String, int);
    public java.lang.String name();
    + public java.lang.String nickname();
    public int age();
    public java.lang.String toString();
    public int hashCode();
    public boolean equals(java.lang.Object);
    public static java.lang.runtime.PatternHandle
    %pattern%Person%(Ljava|lang|String?I)();
    + public static java.lang.runtime.PatternHandle
    %pattern%Person%(Ljava|lang|String?Ljava|lang|String?I)();
    }
    sealed interface Developer { }
    record Person(String name, int age) implements Developer { }
    record Business(String name) implements Developer { }
    Developer alice = new Person("Alice", 12);
    if (alice instanceof Person(var name, var age)) {
    // ...
    }

    View Slide

  181. public final class Person extends java.lang.Record {
    private final java.lang.String name;
    + private final java.lang.String nickname;
    private final int age;
    public Person(java.lang.String, int);
    + public Person(java.lang.String, java.lang.String, int);
    public java.lang.String name();
    + public java.lang.String nickname();
    public int age();
    public java.lang.String toString();
    public int hashCode();
    public boolean equals(java.lang.Object);
    public static java.lang.runtime.PatternHandle
    %pattern%Person%(Ljava|lang|String?I)();
    + public static java.lang.runtime.PatternHandle
    %pattern%Person%(Ljava|lang|String?Ljava|lang|String?I)();
    }
    sealed interface Developer { }
    record Person(String name, int age) implements Developer { }
    record Business(String name) implements Developer { }
    Developer alice = new Person("Alice", 12);
    switch (alice) {
    case Person(var name, var age) -> // ...
    case Business b -> // ...
    }
    if i
    n
    s
    t
    a
    n
    c
    e
    o
    f

    View Slide

  182. public final class Person extends java.lang.Record {
    private final java.lang.String name;
    + private final java.lang.String nickname;
    private final int age;
    public Person(java.lang.String, int);
    + public Person(java.lang.String, java.lang.String, int);
    public java.lang.String name();
    + public java.lang.String nickname();
    public int age();
    public java.lang.String toString();
    public int hashCode();
    public boolean equals(java.lang.Object);
    public static java.lang.runtime.PatternHandle
    %pattern%Person%(Ljava|lang|String?I)();
    + public static java.lang.runtime.PatternHandle
    %pattern%Person%(Ljava|lang|String?Ljava|lang|String?I)();
    }
    sealed interface Developer { }
    record Person(String name, int age) implements Developer { }
    record Business(String name) implements Developer { }
    Developer alice = new Person("Alice", 12);
    switch (alice) {
    case Person(var name, var age) -> // ...
    case Business b -> // ...
    }

    View Slide

  183. public final class Person extends java.lang.Record {
    private final java.lang.String name;
    + private final java.lang.String nickname;
    private final int age;
    public Person(java.lang.String, int);
    + public Person(java.lang.String, java.lang.String, int);
    public java.lang.String name();
    + public java.lang.String nickname();
    public int age();
    public java.lang.String toString();
    public int hashCode();
    public boolean equals(java.lang.Object);
    public static java.lang.runtime.PatternHandle
    %pattern%Person%(Ljava|lang|String?I)();
    + public static java.lang.runtime.PatternHandle
    %pattern%Person%(Ljava|lang|String?Ljava|lang|String?I)();
    }
    sealed interface Developer { }
    record Person(String name, int age) implements Developer { }
    record Business(String name) implements Developer { }
    Developer alice = new Person("Alice", 12);
    switch (alice) {
    case Person(var name, var age) -> // ...
    case Business b -> // ...
    }

    View Slide

  184. public final class Person extends java.lang.Record {
    private final java.lang.String name;
    + private final java.lang.String nickname;
    private final int age;
    public Person(java.lang.String, int);
    + public Person(java.lang.String, java.lang.String, int);
    public java.lang.String name();
    + public java.lang.String nickname();
    public int age();
    public java.lang.String toString();
    public int hashCode();
    public boolean equals(java.lang.Object);
    public static java.lang.runtime.PatternHandle
    %pattern%Person%(Ljava|lang|String?I)();
    + public static java.lang.runtime.PatternHandle
    %pattern%Person%(Ljava|lang|String?Ljava|lang|String?I)();
    }
    sealed interface Developer { }
    record Person(String name, int age) implements Developer { }
    record Business(String name) implements Developer { }
    Developer alice = new Person("Alice", 12);
    switch (alice) {
    case Person(var name, var age) -> // ...
    case Business b -> // ...
    }

    View Slide

  185. public final class Person extends java.lang.Record {
    private final java.lang.String name;
    + private final java.lang.String nickname;
    private final int age;
    public Person(java.lang.String, int);
    + public Person(java.lang.String, java.lang.String, int);
    public java.lang.String name();
    + public java.lang.String nickname();
    public int age();
    public java.lang.String toString();
    public int hashCode();
    public boolean equals(java.lang.Object);
    public static java.lang.runtime.PatternHandle
    %pattern%Person%(Ljava|lang|String?I)();
    + public static java.lang.runtime.PatternHandle
    %pattern%Person%(Ljava|lang|String?Ljava|lang|String?I)();
    }
    sealed interface Developer { }
    record Person(String name, int age) implements Developer { }
    record Business(String name) implements Developer { }
    Developer alice = new Person("Alice", 12);
    switch (alice) {
    case Person(var name, var age) -> // ...
    case Business b -> // ...
    }

    View Slide

  186. public final class Person extends java.lang.Record {
    private final java.lang.String name;
    + private final java.lang.String nickname;
    private final int age;
    public Person(java.lang.String, int);
    + public Person(java.lang.String, java.lang.String, int);
    public java.lang.String name();
    + public java.lang.String nickname();
    public int age();
    public java.lang.String toString();
    public int hashCode();
    public boolean equals(java.lang.Object);
    public static java.lang.runtime.PatternHandle
    %pattern%Person%(Ljava|lang|String?I)();
    + public static java.lang.runtime.PatternHandle
    %pattern%Person%(Ljava|lang|String?Ljava|lang|String?I)();
    }
    sealed interface Developer { }
    record Person(String name, int age) implements Developer { }
    record Business(String name) implements Developer { }
    Developer alice = new Person("Alice", 12);
    switch (alice) {
    case Person(var name, var age) -> // ...
    case Business b -> // ...
    }

    View Slide

  187. public final class Person extends java.lang.Record {
    private final java.lang.String name;
    + private final java.lang.String nickname;
    private final int age;
    public Person(java.lang.String, int);
    + public Person(java.lang.String, java.lang.String, int);
    public java.lang.String name();
    + public java.lang.String nickname();
    public int age();
    val alice: Developer = Person("Alice", 12)
    when (alice) {
    is Person -> {
    val (name, age) = alice
    // ...
    }
    is Business -> // ...
    }
    Developer alice = new Person("Alice", 12);
    switch (alice) {
    case Person(var name, var age) -> // ...
    case Business b -> // ...
    }
    sealed interface Developer { }
    record Person(String name, int age) implements Developer { }
    record Business(String name) implements Developer { }

    View Slide

  188. sealed class Developer
    data class Person(val name: String, val age: Int) : Developer()
    data class Business(val name: String) : Developer()
    sealed interface Developer { }
    record Person(String name, int age) implements Developer { }
    record Business(String name) implements Developer { }

    View Slide

  189. sealed class Developer
    data class Person(val name: String, val age: Int) : Developer()
    data class Business(val name: String) : Developer()
    sealed class Download
    data class App(val name: String, val developer: Developer) : Download()
    data class Movie(val title: String, val director: Person) : Download()
    sealed interface Developer { }
    record Person(String name, int age) implements Developer { }
    record Business(String name) implements Developer { }
    sealed interface Download { }
    record App(String name, Developer developer) implements Download { }
    record Movie(String title, Person director) implements Download { }

    View Slide

  190. sealed class Developer
    data class Person(val name: String, val age: Int) : Developer()
    data class Business(val name: String) : Developer()
    sealed class Download
    data class App(val name: String, val developer: Developer) : Download()
    data class Movie(val title: String, val director: Person) : Download()
    val download: Download = //...

    View Slide

  191. sealed class Developer
    data class Person(val name: String, val age: Int) : Developer()
    data class Business(val name: String) : Developer()
    sealed class Download
    data class App(val name: String, val developer: Developer) : Download()
    data class Movie(val title: String, val director: Person) : Download()
    val download: Download = //...
    val result = if (download is App) {
    }

    View Slide

  192. sealed class Developer
    data class Person(val name: String, val age: Int) : Developer()
    data class Business(val name: String) : Developer()
    sealed class Download
    data class App(val name: String, val developer: Developer) : Download()
    data class Movie(val title: String, val director: Person) : Download()
    val download: Download = //...
    val result = if (download is App &&
    download.developer is Person) {
    }

    View Slide

  193. sealed class Developer
    data class Person(val name: String, val age: Int) : Developer()
    data class Business(val name: String) : Developer()
    sealed class Download
    data class App(val name: String, val developer: Developer) : Download()
    data class Movie(val title: String, val director: Person) : Download()
    val download: Download = //...
    val result = if (download is App &&
    download.developer is Person &&
    download.developer.name == "Alice") {
    }

    View Slide

  194. sealed class Developer
    data class Person(val name: String, val age: Int) : Developer()
    data class Business(val name: String) : Developer()
    sealed class Download
    data class App(val name: String, val developer: Developer) : Download()
    data class Movie(val title: String, val director: Person) : Download()
    val download: Download = //...
    val result = if (download is App &&
    download.developer is Person &&
    download.developer.name == "Alice") {
    "Alice's app ${download.name}"
    }

    View Slide

  195. sealed class Developer
    data class Person(val name: String, val age: Int) : Developer()
    data class Business(val name: String) : Developer()
    sealed class Download
    data class App(val name: String, val developer: Developer) : Download()
    data class Movie(val title: String, val director: Person) : Download()
    val download: Download = //...
    val result = if (download is App &&
    download.developer is Person &&
    download.developer.name == "Alice") {
    "Alice's app ${download.name}"
    } else if (download is Movie) {
    }

    View Slide

  196. sealed class Developer
    data class Person(val name: String, val age: Int) : Developer()
    data class Business(val name: String) : Developer()
    sealed class Download
    data class App(val name: String, val developer: Developer) : Download()
    data class Movie(val title: String, val director: Person) : Download()
    val download: Download = //...
    val result = if (download is App &&
    download.developer is Person &&
    download.developer.name == "Alice") {
    "Alice's app ${download.name}"
    } else if (download is Movie && download.director.name == "Alice") {
    }

    View Slide

  197. sealed class Developer
    data class Person(val name: String, val age: Int) : Developer()
    data class Business(val name: String) : Developer()
    sealed class Download
    data class App(val name: String, val developer: Developer) : Download()
    data class Movie(val title: String, val director: Person) : Download()
    val download: Download = //...
    val result = if (download is App &&
    download.developer is Person &&
    download.developer.name == "Alice") {
    "Alice's app ${download.name}"
    } else if (download is Movie && download.director.name == "Alice") {
    "Alice's movie ${download.title}"
    }

    View Slide

  198. sealed class Developer
    data class Person(val name: String, val age: Int) : Developer()
    data class Business(val name: String) : Developer()
    sealed class Download
    data class App(val name: String, val developer: Developer) : Download()
    data class Movie(val title: String, val director: Person) : Download()
    val download: Download = //...
    val result = if (download is App &&
    download.developer is Person &&
    download.developer.name == "Alice") {
    "Alice's app ${download.name}"
    } else if (download is Movie && download.director.name == "Alice") {
    "Alice's movie ${download.title}"
    } else {
    "Not by Alice"
    }

    View Slide

  199. sealed class Developer
    data class Person(val name: String, val age: Int) : Developer()
    data class Business(val name: String) : Developer()
    sealed class Download
    data class App(val name: String, val developer: Developer) : Download()
    data class Movie(val title: String, val director: Person) : Download()
    data class TvShow(val title: String, val showRunner: Person) : Download()
    val download: Download = //...
    val result = if (download is App &&
    download.developer is Person &&
    download.developer.name == "Alice") {
    "Alice's app ${download.name}"
    } else if (download is Movie && download.director.name == "Alice") {
    "Alice's movie ${download.title}"
    } else {
    "Not by Alice"
    }

    View Slide

  200. sealed class Developer
    data class Person(val name: String, val age: Int) : Developer()
    data class Business(val name: String) : Developer()
    sealed class Download
    data class App(val name: String, val developer: Developer) : Download()
    data class Movie(val title: String, val director: Person) : Download()
    val download: Download = //...

    View Slide

  201. sealed class Developer
    data class Person(val name: String, val age: Int) : Developer()
    data class Business(val name: String) : Developer()
    sealed class Download
    data class App(val name: String, val developer: Developer) : Download()
    data class Movie(val title: String, val director: Person) : Download()
    val download: Download = //...
    val result = when (download) {
    is App ->
    is Movie ->
    }

    View Slide

  202. sealed class Developer
    data class Person(val name: String, val age: Int) : Developer()
    data class Business(val name: String) : Developer()
    sealed class Download
    data class App(val name: String, val developer: Developer) : Download()
    data class Movie(val title: String, val director: Person) : Download()
    val download: Download = //...
    val result = when (download) {
    is App ->
    if (download.developer is Person && download.developer.name == "Alice") {
    "Alice's app ${download.name}"
    } else {
    "Not by Alice"
    }
    is Movie ->
    }

    View Slide

  203. data class Business(val name: String) : Developer()
    sealed class Download
    data class App(val name: String, val developer: Developer) : Download()
    data class Movie(val title: String, val director: Person) : Download()
    val download: Download = //...
    val result = when (download) {
    is App ->
    if (download.developer is Person && download.developer.name == "Alice") {
    "Alice's app ${download.name}"
    } else {
    "Not by Alice"
    }
    is Movie ->
    if (download.director.name == "Alice") {
    "Alice's movie ${download.title}"
    } else {
    "Not by Alice"
    }
    }

    View Slide

  204. data class Movie(val title: String, val director: Person) : Download()
    val download: Download = //...
    val result = when (download) {
    is App ->
    when (download.developer) {
    is Person ->
    if (download.developer.name == "Alice") {
    "Alice's app ${download.name}"
    } else {
    "Not by Alice"
    }
    else -> "Not by Alice"
    }
    is Movie ->
    if (download.director.name == "Alice") {
    "Alice's movie ${download.title}"
    } else {
    "Not by Alice"
    }
    }

    View Slide

  205. val result = when (download) {
    is App -> {
    val (name, developer) = download
    when (developer) {
    is Person ->
    if (developer.name == "Alice") {
    "Alice's app $name"
    } else {
    "Not by Alice"
    }
    else -> "Not by Alice"
    }
    }
    is Movie -> {
    val (title, directory) = download
    if (director.name == "Alice") {
    "Alice's movie $title"
    } else {
    "Not by Alice"
    }
    }
    }
    download
    download
    download

    View Slide

  206. sealed interface Developer { }
    record Person(String name, int age) implements Developer { }
    record Business(String name) implements Developer { }
    sealed interface Download { }
    record App(String name, Developer developer) implements Download { }
    record Movie(String title, Person director) implements Download { }

    View Slide

  207. sealed interface Developer { }
    record Person(String name, int age) implements Developer { }
    record Business(String name) implements Developer { }
    sealed interface Download { }
    record App(String name, Developer developer) implements Download { }
    record Movie(String title, Person director) implements Download { }
    Download download = //...

    View Slide

  208. sealed interface Developer { }
    record Person(String name, int age) implements Developer { }
    record Business(String name) implements Developer { }
    sealed interface Download { }
    record App(String name, Developer developer) implements Download { }
    record Movie(String title, Person director) implements Download { }
    Download download = //...
    var result = switch (download) {
    case App ->
    case Movie ->
    };

    View Slide

  209. sealed interface Developer { }
    record Person(String name, int age) implements Developer { }
    record Business(String name) implements Developer { }
    sealed interface Download { }
    record App(String name, Developer developer) implements Download { }
    record Movie(String title, Person director) implements Download { }
    Download download = //...
    var result = switch (download) {
    case App ->
    case Movie ->
    };

    View Slide

  210. sealed interface Developer { }
    record Person(String name, int age) implements Developer { }
    record Business(String name) implements Developer { }
    sealed interface Download { }
    record App(String name, Developer developer) implements Download { }
    record Movie(String title, Person director) implements Download { }
    Download download = //...
    var result = switch (download) {
    case App ->
    case Movie ->
    };

    View Slide

  211. sealed interface Developer { }
    record Person(String name, int age) implements Developer { }
    record Business(String name) implements Developer { }
    sealed interface Download { }
    record App(String name, Developer developer) implements Download { }
    record Movie(String title, Person director) implements Download { }
    Download download = //...
    var result = switch (download) {
    case App(var name, var developer) ->
    case Movie ->
    };

    View Slide

  212. sealed interface Developer { }
    record Person(String name, int age) implements Developer { }
    record Business(String name) implements Developer { }
    sealed interface Download { }
    record App(String name, Developer developer) implements Download { }
    record Movie(String title, Person director) implements Download { }
    Download download = //...
    var result = switch (download) {
    case App(var name, var developer) ->
    case Movie ->
    };

    View Slide

  213. sealed interface Developer { }
    record Person(String name, int age) implements Developer { }
    record Business(String name) implements Developer { }
    sealed interface Download { }
    record App(String name, Developer developer) implements Download { }
    record Movie(String title, Person director) implements Download { }
    Download download = //...
    var result = switch (download) {
    case App(var name, Person("Alice", _)) ->
    case Movie ->
    };
    var developer

    View Slide

  214. sealed interface Developer { }
    record Person(String name, int age) implements Developer { }
    record Business(String name) implements Developer { }
    sealed interface Download { }
    record App(String name, Developer developer) implements Download { }
    record Movie(String title, Person director) implements Download { }
    Download download = //...
    var result = switch (download) {
    case App(var name, Person("Alice", _)) ->
    case Movie ->
    };
    var developer

    View Slide

  215. sealed interface Developer { }
    record Person(String name, int age) implements Developer { }
    record Business(String name) implements Developer { }
    sealed interface Download { }
    record App(String name, Developer developer) implements Download { }
    record Movie(String title, Person director) implements Download { }
    Download download = //...
    var result = switch (download) {
    case App(var name, Person("Alice", _)) -> "Alice's app " + name
    case Movie ->
    };

    View Slide

  216. sealed interface Developer { }
    record Person(String name, int age) implements Developer { }
    record Business(String name) implements Developer { }
    sealed interface Download { }
    record App(String name, Developer developer) implements Download { }
    record Movie(String title, Person director) implements Download { }
    Download download = //...
    var result = switch (download) {
    case App(var name, Person("Alice", _)) -> "Alice's app " + name
    case Movie(var title, Person("Alice", _)) ->
    };

    View Slide

  217. sealed interface Developer { }
    record Person(String name, int age) implements Developer { }
    record Business(String name) implements Developer { }
    sealed interface Download { }
    record App(String name, Developer developer) implements Download { }
    record Movie(String title, Person director) implements Download { }
    Download download = //...
    var result = switch (download) {
    case App(var name, Person("Alice", _)) -> "Alice's app " + name
    case Movie(var title, Person("Alice", _)) -> "Alice's movie " + title
    };

    View Slide

  218. sealed interface Developer { }
    record Person(String name, int age) implements Developer { }
    record Business(String name) implements Developer { }
    sealed interface Download { }
    record App(String name, Developer developer) implements Download { }
    record Movie(String title, Person director) implements Download { }
    Download download = //...
    var result = switch (download) {
    case App(var name, Person("Alice", _)) -> "Alice's app " + name
    case Movie(var title, Person("Alice", _)) -> "Alice's movie " + title
    case App(_), Movie(_) -> "Not by Alice"
    };

    View Slide

  219. val download: Download = //...
    val result = when (download) {
    is App -> {
    val (name, developer) = download
    when (developer) {
    is Person ->
    if (developer.name == "Alice") {
    "Alice's app $name"
    } else {
    "Not by Alice"
    }
    else -> "Not by Alice"
    }
    }
    is Movie -> {
    val (title, directory) = download
    if (director.name == "Alice") {
    "Alice's movie $title"
    } else {
    "Not by Alice"
    }
    }
    }
    Download download = //...
    var result = switch (download) {
    case App(var name, Person("Alice", _)) -> "Alice's app " + name
    case Movie(var title, Person("Alice", _)) -> "Alice's movie " + title
    case App(_), Movie(_) -> "Not by Alice"
    };
    sealed interface Developer { }
    record Person(String name, int age) implements Developer { }
    record Business(String name) implements Developer { }
    sealed interface Download { }
    record App(String name, Developer developer) implements Download { }
    record Movie(String title, Person director) implements Download { }

    View Slide

  220. Coroutines

    View Slide

  221. suspend fun main() = coroutineScope {
    for (count in 10 downTo 0) {
    launch {
    delay(100.milliseconds * count)
    println(count)
    }
    }
    }

    View Slide

  222. suspend fun main() = coroutineScope {
    for (count in 10 downTo 0) {
    launch {
    delay(100.milliseconds * count)
    println(count)
    }
    }
    }










    0
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10

    View Slide

  223. suspend fun main() = coroutineScope {
    for (count in 10 downTo 0) {
    launch {
    delay(100.milliseconds * count)
    println(count)
    }
    }
    }

    View Slide

  224. suspend fun main() = coroutineScope {
    for (count in 10 downTo 0) {
    launch {
    delay(100.milliseconds * count)
    println(count)
    }
    }
    }

    View Slide

  225. suspend fun main() = coroutineScope {
    for (count in 10 downTo 0) {
    launch {
    delay(100.milliseconds * count)
    println(count)
    }
    }
    }

    View Slide

  226. suspend fun main() = coroutineScope {
    for (count in 10 downTo 0) {
    launch {
    delay(100.milliseconds * count)
    println(count)
    }
    }
    }
    public static void main(String... args) {
    Executor e = Executors.newWorkStealingPool();
    for (int count = 10; count >= 0; count--) {
    final var finalCount = count;
    e.execute(() -> {
    Thread.sleep(100 * finalCount);
    System.out.println(finalCount);
    });
    }
    }

    View Slide

  227. suspend fun main() = coroutineScope {
    for (count in 10 downTo 0) {
    launch {
    delay(100.milliseconds * count)
    println(count)
    }
    }
    }
    public static void main(String... args) {
    Executor e = Executors.newWorkStealingPool();
    for (int count = 10; count >= 0; count--) {
    final var finalCount = count;
    e.execute(() -> {
    Thread.sleep(100 * finalCount);
    System.out.println(finalCount);
    });
    }
    }

    View Slide

  228. suspend fun main() = coroutineScope {
    for (count in 10 downTo 0) {
    launch {
    delay(100.milliseconds * count)
    println(count)
    }
    }
    }
    public static void main(String... args) {
    Executor e = Executors.newWorkStealingPool();
    for (int count = 10; count >= 0; count--) {
    final var finalCount = count;
    e.execute(() -> {
    Thread.sleep(100 * finalCount);
    System.out.println(finalCount);
    });
    }
    }

    View Slide

  229. The end of Kotlin?

    View Slide

  230. var count = 1
    final var users = new ArrayList()
    The end of Kotlin?
    Java 10: Variable Type Inference

    View Slide

  231. public static boolean any(Predicate predicate) {
    var seen = new HashSet();
    boolean hasMatch(Node node) {
    if (!seen.add(node)) return false; // already seen
    if (predicate.test(node)) return true; // match!
    return node.getNodes().stream().anyMatch(n -> hasMatch(n));
    }
    return hasMatch(getRoot());
    }
    Java 16/17: Local Methods

    View Slide

  232. public static void main(String[] args) {
    System.out.println("""
    SELECT *
    FROM users
    WHERE name LIKE 'Jake %'
    """);
    }
    Java 15: Multiline Strings

    View Slide

  233. record Person(String name, int age) { }
    Java 15/16: Records

    View Slide

  234. sealed interface Developer { }
    record Person(String name, int age) implements Developer { }
    record Business(String name) implements Developer { }
    Java 15/16: Sealed Hierarchies

    View Slide

  235. Object o = 1;
    if (o instanceof Integer i) {
    System.out.println(i + 1);
    }
    Java 15/16: Type Matching

    View Slide

  236. Download download = //...
    var result = switch (download) {
    case App(var name, Person("Alice", _)) -> "Alice's app " + name
    case Movie(var title, Person("Alice", _)) -> "Alice's movie " + title
    case App(_), Movie(_) -> "Not by Alice"
    };
    Java 16/17: Pattern Matching

    View Slide

  237. Download download = //...
    var result = switch (download) {
    case App(var name, Person("Alice", _)) -> "Alice's app " + name
    case Movie(var title, Person("Alice", _)) -> "Alice's movie " + title
    case App(_), Movie(_) -> "Not by Alice"
    };
    Java 14: Expression Switch

    View Slide

  238. public static void main(String... args) {
    Executor e = Executors.newWorkStealingPool();
    for (int count = 10; count >= 0; count--) {
    final var finalCount = count;
    e.execute(() -> {
    Thread.sleep(100 * finalCount);
    System.out.println(finalCount);
    });
    }
    }
    Java 16/17: Virtual Threads

    View Slide

  239. The end of Kotlin?
    New Java APIs and new VM improvements also help Kotlin

    View Slide

  240. The end of Kotlin?
    New Java APIs and new VM improvements also help Kotlin
    API, bytecode, and VM changes for new Java language features are
    also available for use by kotlinc

    View Slide

  241. The end of Kotlin?
    New Java APIs and new VM improvements also help Kotlin
    API, bytecode, and VM changes for new Java language features are
    also available for use by kotlinc
    No plans to tackle nullability in Java!

    View Slide

  242. The end of Kotlin?
    New Java APIs and new VM improvements also help Kotlin
    API, bytecode, and VM changes for new Java language features are
    also available for use by kotlinc
    No plans to tackle nullability in Java!
    Java in 3 years will also be competing with Kotlin in 3 years,

    not the Kotlin of today

    View Slide

  243. The end of Kotlin?
    New Java APIs and new VM improvements also help Kotlin
    API, bytecode, and VM changes for new Java language features are
    also available for use by kotlinc
    No plans to tackle nullability in Java!
    Java in 3 years will also be competing with Kotlin in 3 years,

    not the Kotlin of today
    Kotlin has an IDE to potentially evolve in ways that Java cannot

    View Slide

  244. The end of Kotlin?
    New Java APIs and new VM improvements also help Kotlin
    API, bytecode, and VM changes for new Java language features are
    also available for use by kotlinc
    No plans to tackle nullability in Java!
    Java in 3 years will also be competing with Kotlin in 3 years,

    not the Kotlin of today
    Kotlin has an IDE to potentially evolve in ways that Java cannot
    Kotlin has first-class multiplatform

    View Slide

  245. What's new in Java 19:
    The end of Kotlin?
    @JakeWharton
    [ Nope! ]

    View Slide