Upgrade to Pro — share decks privately, control downloads, hide ads and more …

Java Cram Session: Get caught up on the latest Java changes

Todd Ginsberg
September 30, 2020

Java Cram Session: Get caught up on the latest Java changes

Java is moving a lot faster than it used to, and it can be hard for busy developers to keep up with all of the new features. But don’t worry! Come to this talk and we’ll go over everything you need to know to catch up with the latest Java developments. This talk will focus on when and how to use the new language changes starting with Java 9. After this talk, you’ll be ready to code with the latest and greatest Java features like a pro.

Todd Ginsberg

September 30, 2020
Tweet

More Decks by Todd Ginsberg

Other Decks in Technology

Transcript

  1. Todd Ginsberg
    Principal Developer
    Netspend
    @toddginsberg
    Java Cram Session
    https://jconf.dev

    View Slide

  2. @ToddGinsberg
    Who Is This Talk For?
    ● Java developers still on Java 8

    View Slide

  3. @ToddGinsberg
    Who Is This Talk For?
    ● Java developers still on Java 8
    ● Are overwhelmed by all of the changes

    View Slide

  4. @ToddGinsberg
    What Are We Covering?
    ● New Java syntax

    View Slide

  5. @ToddGinsberg
    What Are We Covering?
    ● New Java syntax
    ● Interesting new libraries

    View Slide

  6. @ToddGinsberg
    What Are We Covering?
    ● New Java syntax
    ● Interesting new libraries
    ● Interesting new methods

    View Slide

  7. @ToddGinsberg
    What Are We Covering?
    ● New Java syntax
    ● Interesting new libraries
    ● Interesting new methods
    ● Strategies for upgrading and keeping up

    View Slide

  8. @ToddGinsberg
    What Aren’t We Covering?
    ● Bytecode-level changes

    View Slide

  9. @ToddGinsberg
    What Aren’t We Covering?
    ● Bytecode-level changes
    ● Most deprecations

    View Slide

  10. @ToddGinsberg
    What Aren’t We Covering?
    ● Bytecode-level changes
    ● Most deprecations
    ● New libraries and methods that you
    may not need right away

    View Slide

  11. @ToddGinsberg
    What Aren’t We Covering?
    ● Bytecode-level changes
    ● Most deprecations
    ● New libraries and methods that you
    may not need right away
    ● Licensing and Paid Support

    View Slide

  12. The State
    Of Things

    View Slide

  13. @ToddGinsberg
    Current State
    Java 14

    View Slide

  14. @ToddGinsberg
    Current State
    Java 14
    Java 15
    No Longer Supported
    Latest and Greatest

    View Slide

  15. @ToddGinsberg
    Current State
    Java 14
    Java 15
    Java 16
    No Longer Supported
    Latest and Greatest
    Coming March 2021

    View Slide

  16. @ToddGinsberg
    No More Major Releases
    ● Six month Feature Releases only

    View Slide

  17. @ToddGinsberg
    No More Major Releases
    ● Six month Feature Releases only
    ● Miss the train? Wait for the next one

    View Slide

  18. @ToddGinsberg
    No More Major Releases
    ● Six month Feature Releases only
    ● Miss the train? Wait for the next one
    ● Allows for preview features

    View Slide

  19. @ToddGinsberg
    No More Major Releases
    ● Six month Feature Releases only
    ● Miss the train? Wait for the next one
    ● Allows for preview features
    ● Two quarterly patch releases

    View Slide

  20. @ToddGinsberg
    No More Major Releases
    ● Six month Feature Releases only
    ● Miss the train? Wait for the next one
    ● Allows for preview features
    ● Two quarterly patch releases
    ● Upgrading is easier

    View Slide

  21. @ToddGinsberg
    Long Term Support
    Java 11
    Java 17
    Still Receiving Patches
    Next LTS

    View Slide

  22. Upgrade
    Strategies

    View Slide

  23. @ToddGinsberg
    Java Upgrade Strategies
    A Update to LTS (11) and stay there until the next LTS (17)

    View Slide

  24. @ToddGinsberg
    Java Upgrade Strategies
    A Update to LTS (11) and stay there until the next LTS (17)
    B Update to the latest release as soon as it comes out

    View Slide

  25. @ToddGinsberg
    Java Upgrade Strategies
    A Update to LTS (11) and stay there until the next LTS (17)
    B Update to the latest release as soon as it comes out
    C Stay on Java 8 forever and let your skills atrophy

    View Slide

  26. @ToddGinsberg
    Java Upgrade Strategies
    A Update to LTS (11) and stay there until the next LTS (17)
    B Update to the latest release as soon as it comes out

    View Slide

  27. @ToddGinsberg
    The Rest of the Talk
    1 Changes up until Java 11

    View Slide

  28. @ToddGinsberg
    The Rest of the Talk
    1 Changes up until Java 11
    2 Changes after Java 11

    View Slide

  29. Welcome To
    Java 11

    View Slide

  30. @ToddGinsberg
    JPMS (Modules): The Basics
    ● Create a module system…

    View Slide

  31. @ToddGinsberg
    JPMS (Modules): The Basics
    ● Create a module system…
    ● And then modularize the JDK itself…

    View Slide

  32. @ToddGinsberg
    JPMS (Modules): The Basics
    ● Create a module system…
    ● And then modularize the JDK itself…
    ● And provide tooling so we can create our own
    modules...

    View Slide

  33. @ToddGinsberg
    JPMS (Modules): The Basics
    ● Create a module system…
    ● And then modularize the JDK itself…
    ● And provide tooling so we can create our own
    modules...
    ● And our own subset runtimes

    View Slide

  34. @ToddGinsberg
    JPMS (Modules): Recommendation
    ● Don’t worry about it for now

    View Slide

  35. @ToddGinsberg
    JPMS (Modules): Recommendation
    ● Don’t worry about it for now
    ● Take advantage of the fact that it made the JVM
    more organized

    View Slide

  36. @ToddGinsberg
    JPMS (Modules): Recommendation
    ● Don’t worry about it for now
    ● Take advantage of the fact that it made the JVM
    more organized
    ● Wait and see what your dependencies do

    View Slide

  37. @ToddGinsberg
    Where Did The JRE Go?
    ● Java does not ship with a JRE any more

    View Slide

  38. @ToddGinsberg
    Where Did The JRE Go?
    ● Java does not ship with a JRE any more
    ● Because the JVM is modular, we can create
    our own task-focused JVMs!

    View Slide

  39. @ToddGinsberg
    Where Did The JRE Go?
    ● Java does not ship with a JRE any more
    ● Because the JVM is modular, we can create
    our own task-focused JVMs!
    ● Even if we don’t use modules!

    View Slide

  40. @ToddGinsberg
    jlink + jdeps == Focused JDK
    MyApp.jar
    AppDependency1.jar
    AppDependency2.jar

    View Slide

  41. @ToddGinsberg
    jlink + jdeps == Focused JDK
    MyApp.jar
    AppDependency1.jar
    AppDependency2.jar
    jdeps

    View Slide

  42. @ToddGinsberg
    jlink + jdeps == Focused JDK
    MyApp.jar
    AppDependency1.jar
    AppDependency2.jar
    jdeps
    List
    of
    Modules

    View Slide

  43. @ToddGinsberg
    jlink + jdeps == Focused JDK
    MyApp.jar
    AppDependency1.jar
    AppDependency2.jar
    jdeps
    List
    of
    Modules
    jlink

    View Slide

  44. @ToddGinsberg
    jlink + jdeps == Focused JDK
    MyApp.jar
    AppDependency1.jar
    AppDependency2.jar
    jdeps
    List
    of
    Modules
    jlink
    JVM

    View Slide

  45. @ToddGinsberg
    Where Did JavaFX Go?
    ● Removed from the JVM!

    View Slide

  46. @ToddGinsberg
    Where Did JavaFX Go?
    ● Removed from the JVM!
    ● Still maintained, don’t panic!
    https://openjfx.io/

    View Slide

  47. @ToddGinsberg
    Say Goodbye To...

    View Slide

  48. @ToddGinsberg
    Say Goodbye To...
    ● Applets

    View Slide

  49. @ToddGinsberg
    Say Goodbye To...
    ● Applets
    ● Web Start / JNLP

    View Slide

  50. @ToddGinsberg
    New! Compact Strings
    ● Java char takes up two bytes
    ● All Strings are char x2 bytes in Java 8

    View Slide

  51. @ToddGinsberg
    New! Compact Strings
    ● Java char takes up two bytes
    ● All Strings are char x2 bytes in Java 8
    0 1 2 3 4 5 6 7
    T
    “Todd” ==
    o d d

    View Slide

  52. @ToddGinsberg
    New! Compact Strings
    ● Java char takes up two bytes
    ● All Strings are char x2 bytes in Java 8
    0 1 2 3 4 5 6 7
    T
    “Todd” ==
    o d d
    0 1 2 3
    T o d d

    View Slide

  53. @ToddGinsberg
    New Garbage Collector Options
    ● G1GC is the new default

    View Slide

  54. @ToddGinsberg
    New Garbage Collector Options
    ● G1GC is the new default
    ● CMS is now deprecated

    View Slide

  55. @ToddGinsberg
    New Garbage Collector Options
    ● G1GC is the new default
    ● CMS is now deprecated
    ● Epsilon (for testing)

    View Slide

  56. @ToddGinsberg
    New Garbage Collector Options
    ● G1GC is the new default
    ● CMS is now deprecated
    ● Epsilon (for testing)
    ● ZGC is experimental

    View Slide

  57. @ToddGinsberg
    Multi-Version Jars

    View Slide

  58. @ToddGinsberg
    JShell - A Java REPL

    View Slide

  59. @ToddGinsberg
    Run Single Files Directly

    View Slide

  60. @ToddGinsberg
    Syntax - Removal of Single Underscore
    _

    View Slide

  61. @ToddGinsberg
    Syntax - Removal of Single Underscore
    ಠ_ಠ

    View Slide

  62. @ToddGinsberg
    Syntax - Local var
    public void doSomething() {
    String food = "French Fries";
    int quantity = 2;
    }

    View Slide

  63. @ToddGinsberg
    Syntax - Local var
    public void doSomething() {
    var food = "French Fries";
    var quantity = 2;
    }

    View Slide

  64. @ToddGinsberg
    Syntax - Local var
    public void doSomething() {
    var food = "French Fries";
    var quantity = 2;
    }

    View Slide

  65. @ToddGinsberg
    Syntax - Local var
    public void doSomething() {
    List items = new ArrayList<>();
    }

    View Slide

  66. @ToddGinsberg
    Syntax - Local var
    public void doSomething() {
    var items = new ArrayList();
    }

    View Slide

  67. @ToddGinsberg
    Syntax - Local var
    public void doSomething() {
    var items = new ArrayList();
    for(var item : items) {
    // ...
    }
    }

    View Slide

  68. @ToddGinsberg
    Syntax - Local var
    public void doSomething() {
    try(var connection = getConnection()) {
    // ...
    }
    }

    View Slide

  69. @ToddGinsberg
    Syntax - Local var
    public void doSomething() {
    // Yes
    var connection = getConnection();
    var now = LocalTime.now();
    }

    View Slide

  70. @ToddGinsberg
    Syntax - Private Interface Methods
    interface Something {
    private void somePrivateMethod() {
    // ...
    }
    }

    View Slide

  71. @ToddGinsberg
    Syntax - Private Interface Methods
    interface Something {
    private static void somePrivateMethod() {
    // ...
    }
    }

    View Slide

  72. @ToddGinsberg
    Library - Unmodifiable Collection Shortcuts
    List list = List.of("A", "B", "C");

    View Slide

  73. @ToddGinsberg
    Library - Unmodifiable Collection Shortcuts
    List list = List.of("A", "B", "C");
    Set set = Set.of("A", "B", "C");

    View Slide

  74. @ToddGinsberg
    Library - Unmodifiable Collection Shortcuts
    List list = List.of("A", "B", "C");
    Set set = Set.of("A", "B", "C");
    Map map = Map.of("A", 1, "B", 2);

    View Slide

  75. @ToddGinsberg
    Library - Unmodifiable Collection Shortcuts
    var list = List.of("A", "B", "C");
    var set = Set.of("A", "B", "C");
    var map = Map.of("A", 1, "B", 2);

    View Slide

  76. @ToddGinsberg
    Library - Stream Enhancements
    numbers // [0,1,2,3,2,1,0]
    .stream()
    .takeWhile(it -> it < 3) // [0,1,2]

    View Slide

  77. @ToddGinsberg
    Library - Stream Enhancements
    numbers // [0,1,2,3,2,1,0]
    .stream()
    .dropWhile(it -> it < 3) // [3,2,1,0]

    View Slide

  78. @ToddGinsberg
    Library - Stream Enhancements
    numbers
    .stream()
    .dropWhile(it -> it < 3)
    .collect(Collectors.toUnmodifiableList());

    View Slide

  79. @ToddGinsberg
    Library - Stream Enhancements
    numbers
    .stream()
    .dropWhile(it -> it < 3)
    .collect(Collectors.toUnmodifiableSet());

    View Slide

  80. @ToddGinsberg
    Library - String Enhancements
    String sample = "1\n2\n3";

    View Slide

  81. @ToddGinsberg
    Library - String Enhancements
    String sample = "1\n2\n3";
    sample
    .lines() // Stream [1, 2, 3]

    View Slide

  82. @ToddGinsberg
    Library - String Enhancements
    String sample = "1\n2\n3";
    sample
    .lines() // Stream [1, 2, 3]
    .forEach(System.out::println);

    View Slide

  83. @ToddGinsberg
    Library - String Enhancements
    String sample = " sample ";

    View Slide

  84. @ToddGinsberg
    Library - String Enhancements
    String sample = " sample ";
    sample.strip() // "sample"

    View Slide

  85. @ToddGinsberg
    Library - String Enhancements
    String sample = " sample ";
    sample.strip() // "sample"
    sample.stripLeading() // "sample "

    View Slide

  86. @ToddGinsberg
    Library - String Enhancements
    String sample = " sample ";
    sample.strip() // "sample"
    sample.stripLeading() // "sample "
    sample.stripTrailing() // " sample"

    View Slide

  87. @ToddGinsberg
    Library - String Enhancements
    someString.isBlank()

    View Slide

  88. @ToddGinsberg
    Library - String Enhancements
    String yell = "Kh" + "a".repeat(5) + "n!";
    // "Khaaaaan!"

    View Slide

  89. @ToddGinsberg
    Library - Collection.toArray(IntFunction)
    // In Collection.java:
    default T[] toArray(IntFunction generator)

    View Slide

  90. @ToddGinsberg
    Library - Collection.toArray(IntFunction)
    // In Collection.java:
    default T[] toArray(IntFunction generator)
    String[] strings = List
    .of("A", "B", "C")
    .toArray(String[]::new)

    View Slide

  91. @ToddGinsberg
    Library - Enhanced Deprecation
    @Deprecated

    View Slide

  92. @ToddGinsberg
    Library - Enhanced Deprecation
    @Deprecated(since = "9", forRemoval = true)

    View Slide

  93. @ToddGinsberg
    Library - HttpClient
    var client = HttpClient.newBuilder()
    .connectTimeout(Duration.ofSeconds(15))
    .version(HttpClient.Version.HTTP_1_1)
    .build();

    View Slide

  94. @ToddGinsberg
    Library - HttpClient
    var request = HttpRequest.newBuilder()
    .GET()
    .uri(URI.create("https://frinkiac.com/api/random"))
    .build();

    View Slide

  95. @ToddGinsberg
    Library - HttpClient
    String quote = client
    .send(request, HttpResponse.BodyHandlers.ofString())
    .body();

    View Slide

  96. Welcome To
    Java 15

    View Slide

  97. @ToddGinsberg
    Say Goodbye To...

    View Slide

  98. @ToddGinsberg
    Say Goodbye To...
    ● Nashorn Javascript Engine (and tools)

    View Slide

  99. @ToddGinsberg
    Say Goodbye To...
    ● Nashorn Javascript Engine (and tools)
    ● CMS GC

    View Slide

  100. @ToddGinsberg
    New Garbage Collector Options
    ● ZGC
    ● Shenandoah

    View Slide

  101. @ToddGinsberg
    Better NullPointerException Messages
    customer.getAddress().getStreet().toUpperCase();

    View Slide

  102. @ToddGinsberg
    Better NullPointerException Messages
    customer.getAddress().getStreet().toUpperCase();
    Exception in thread "main" java.lang.NullPointerException
    at Yikes.main(Yikes.java:42)

    View Slide

  103. @ToddGinsberg
    Better NullPointerException Messages
    customer.getAddress().getStreet().toUpperCase();
    -XX:+ShowCodeDetailsInExceptionMessages

    View Slide

  104. @ToddGinsberg
    Better NullPointerException Messages
    customer.getAddress().getStreet().toUpperCase();
    Exception in thread "main" java.lang.NullPointerException:
    Cannot invoke "String.toUpperCase()" because the return
    value of "Address.getStreet()" is null
    at Yikes.main(Yikes.java:42)

    View Slide

  105. @ToddGinsberg
    Better NullPointerException Messages
    customer.getAddress().getStreet().toUpperCase();
    Exception in thread "main" java.lang.NullPointerException:
    Cannot invoke "String.toUpperCase()" because the return
    value of "Address.getStreet()" is null
    at Yikes.main(Yikes.java:42)

    View Slide

  106. @ToddGinsberg
    Syntax - Text Blocks
    String json =
    "{\n" +
    " \"food\": \"French Fries\",\n" +
    " \"quantity\": 2\n" +
    "}";

    View Slide

  107. @ToddGinsberg
    Syntax - Text Blocks
    String json = """
    {
    "food": "French Fries",
    "quantity: 2
    }
    """;

    View Slide

  108. @ToddGinsberg
    Syntax - Switch Expressions
    String food = null;
    switch (id) {
    case 1: {
    food = "French Fries";
    break;
    }
    case 2: {
    food = "Doughnuts";
    break;
    }
    default: {
    food = "Pizza";
    }
    }

    View Slide

  109. @ToddGinsberg
    Syntax - Switch Expressions
    String food = switch (id) {
    case 1 -> "French Fries";
    case 2 -> "Doughnuts";
    default -> "Pizza";
    };

    View Slide

  110. @ToddGinsberg
    Syntax - Switch Expressions
    String food = switch (id) {
    case 1: {
    // Some other work here
    yield "French Fries";
    }
    case 2: yield "Doughnuts";
    default: yield "Pizza";
    };

    View Slide

  111. @ToddGinsberg
    Good News - Enum Limits Increased!

    View Slide

  112. @ToddGinsberg
    Good News - Enum Limits Increased!
    ~2740

    View Slide

  113. @ToddGinsberg
    Good News - Enum Limits Increased!
    ~2740
    ~4100

    View Slide

  114. Here Be
    Dragons

    View Slide

  115. @ToddGinsberg
    Syntax - instanceof Pattern Matching (Preview)
    if(someObject instanceof String) {
    String someString = (String)someObject;
    doSomethingWithString(someString);
    }

    View Slide

  116. @ToddGinsberg
    Syntax - instanceof Pattern Matching (Preview)
    if(someObject instanceof String someString) {
    doSomethingWithString(someString);
    }

    View Slide

  117. @ToddGinsberg
    Records (Preview)
    If we wanted an immutable 2-D Point we would need to:

    View Slide

  118. @ToddGinsberg
    Records (Preview)
    If we wanted an immutable 2-D Point we would need to:
    ● Define a class

    View Slide

  119. @ToddGinsberg
    Records (Preview)
    If we wanted an immutable 2-D Point we would need to:
    ● Define a class
    ● With two fields called x and y

    View Slide

  120. @ToddGinsberg
    Records (Preview)
    If we wanted an immutable 2-D Point we would need to:
    ● Define a class
    ● With two fields called x and y
    ● And an all-arguments constructor

    View Slide

  121. @ToddGinsberg
    Records (Preview)
    If we wanted an immutable 2-D Point we would need to:
    ● Define a class
    ● With two fields called x and y
    ● And an all-arguments constructor
    ● And getters

    View Slide

  122. @ToddGinsberg
    Records (Preview)
    If we wanted an immutable 2-D Point we would need to:
    ● Define a class
    ● With two fields called x and y
    ● And an all-arguments constructor
    ● And getters
    ● And equals()

    View Slide

  123. @ToddGinsberg
    Records (Preview)
    If we wanted an immutable 2-D Point we would need to:
    ● Define a class
    ● With two fields called x and y
    ● And an all-arguments constructor
    ● And getters
    ● And equals()
    ● And hashcode()

    View Slide

  124. @ToddGinsberg
    Records (Preview)
    If we wanted an immutable 2-D Point we would need to:
    ● Define a class
    ● With two fields called x and y
    ● And an all-arguments constructor
    ● And getters
    ● And equals()
    ● And hashcode()
    ● And toString()

    View Slide

  125. @ToddGinsberg
    Records (Preview)
    This pattern is VERY common!

    View Slide

  126. @ToddGinsberg
    Records (Preview)
    This pattern is VERY common!
    record Point(int x, int y) {}

    View Slide

  127. @ToddGinsberg
    Records (Preview)
    This pattern is VERY common!
    record Point(int x, int y) {}
    var point = new Point(1, 2);

    View Slide

  128. @ToddGinsberg
    Records (Preview)
    This pattern is VERY common!
    record Point(int x, int y) {}
    var point = new Point(1, 2);
    System.out.println("X: " + point.x());
    System.out.println("Y: " + point.y());

    View Slide

  129. @ToddGinsberg
    Records (Preview)
    This pattern is VERY common!
    record Point(int x, int y) {}
    var point = new Point(1, 2);
    System.out.println("X: " + point.x());
    System.out.println("Y: " + point.y());

    View Slide

  130. @ToddGinsberg
    Records (Preview)
    record Point(int x, int y) {
    public Point {
    if(x < 0) throw new IllegalArgumentException();
    if(y < 0) throw new IllegalArgumentException();
    }
    }

    View Slide

  131. @ToddGinsberg
    Records (Preview)
    record Point(int x, int y) {
    public Point {
    if(x < 0) throw new IllegalArgumentException();
    if(y < 0) throw new IllegalArgumentException();
    }
    public Point(Point3D other) {
    this(other.x(), other.y());
    }
    }

    View Slide

  132. @ToddGinsberg
    Records (Preview)
    ● Records extend java.lang.Record

    View Slide

  133. @ToddGinsberg
    Records (Preview)
    ● Records extend java.lang.Record
    ● Records are final

    View Slide

  134. @ToddGinsberg
    Records (Preview)
    ● Records extend java.lang.Record
    ● Records are final
    ● Record fields are final

    View Slide

  135. @ToddGinsberg
    Records (Preview)
    ● Records extend java.lang.Record
    ● Records are final
    ● Record fields are final
    ● Cannot define any more fields

    View Slide

  136. @ToddGinsberg
    Syntax - Sealed Classes (Preview)
    sealed interface Message permits Start, Stop, Timeout {}

    View Slide

  137. @ToddGinsberg
    Syntax - Sealed Classes (Preview)
    sealed interface Message permits Start, Stop, Timeout {}

    View Slide

  138. @ToddGinsberg
    Syntax - Sealed Classes (Preview)
    sealed interface Message permits Start, Stop, Timeout {}
    record Start(String serverName) implements Message {}
    record Stop(String reason) implements Message {}
    record Timeout(Duration fromNow) implements Message {}

    View Slide

  139. @ToddGinsberg
    Syntax - Sealed Classes (Preview)
    sealed interface Message permits Start, Stop, Timeout {}
    record Start(String serverName) implements Message {}
    record Stop(String reason) implements Message {}
    record Timeout(Duration fromNow) implements Message {}
    // ERROR!
    class Restart implements Message {}

    View Slide

  140. @ToddGinsberg
    Syntax - Sealed Classes (Preview)
    sealed interface Message permits Start, Stop, Timeout {}
    record Start(String serverName) implements Message {}
    record Stop(String reason) implements Message {}
    record Timeout(Duration fromNow) implements Message {}
    // ERROR!
    class Restart implements Message {}

    View Slide

  141. @ToddGinsberg
    Syntax - Sealed Classes (Preview)
    // Coming in the future!
    String logMessage = switch(someMessage) {
    Start -> "Starting server: " + someMessage.serverName();
    Stop -> "Stopping because: " + someMessage.reason();
    Timeout -> "Timeout is now: " + someMessage.fromNow();
    };

    View Slide

  142. In
    Conclusion...

    View Slide

  143. @ToddGinsberg
    Upgrading Past Java 8
    ● You have one more “Big Bang”

    View Slide

  144. @ToddGinsberg
    Upgrading Past Java 8
    ● You have one more “Big Bang”
    ● And then it won’t be that bad

    View Slide

  145. @ToddGinsberg
    Upgrading Past Java 8
    ● You have one more “Big Bang”
    ● And then it won’t be that bad
    ● Because you’ll have new toys to play with

    View Slide

  146. @ToddGinsberg
    Upgrading Past Java 8
    ● You have one more “Big Bang”
    ● And then it won’t be that bad
    ● Because you’ll have new toys to play with
    ● And performance improvements every
    six months!

    View Slide

  147. @ToddGinsberg
    [email protected]
    https://todd.ginsberg.com
    Thank You!
    Anonymous Feedback!

    View Slide

  148. Todd Ginsberg
    Principal Developer
    Netspend
    @toddginsberg
    Java Cram Session
    https://jconf.dev

    View Slide