Successfully reported this slideshow.
We use your LinkedIn profile and activity data to personalize ads and to show you more relevant ads. You can change your ad preferences anytime.

Java Full Throttle

931 views

Published on

Avec la version 9 sortie en septembre 2017, Java appuie sur la pédale ! Le rythme des livraisons passe à une version majeure tous les 6 mois. Java 10 est sorti en mars, prochaine version en septembre. Java 10 apporte le 'var' et l'inférence de type pour les variables locales. D'autres nouveautés sont en préparation : les constantes dynamiques, les classes de données, un nouveau switch à base de lambda, des interfaces fermées, de nouvelles choses du coté des génériques et bien plus encore.

Cela viendra-t-il en 11, 12, 15 ? Ne spéculons pas, mais quand ces nouveautés seront prêtes, elles sortiront en quelques mois. On se propose de présenter ces nouveautés, celles qui sont presque prêtes, celles qui seront prêtes bientôt, et celles qui ne seront pas prêtes avant un moment. Quels seront les impacts sur le langage, sur la JVM et donc sur les performances ? Que cela va-t-il nous apporter au quotidien, en tant que développeurs ? Quels seront les nouveaux patterns ? Voici le programme de cette présentation, avec des slides, du code, de la joie et de la bonne humeur !

Published in: Education
  • Login to see the comments

Java Full Throttle

  1. 1. 1
  2. 2. 2 Rémi ForaxRémi Forax StarringStarring José PaumardJosé Paumard
  3. 3. 3 Don’t believe a word of what we are saying! Don’t believe a word of what we are saying!
  4. 4. 4 Java Champion OpenJDK amber & valhalla ex: jigsaw, lambda, invokedynamic Rémi in a few wordsRémi in a few words
  5. 5. 5 José in a few more wordsJosé in a few more words @JosePaumard https://github.com/JosePaumard/ https://josepaumard.github.io/ https://www.youtube.com/user/JosePaumard
  6. 6. 6 Questions? #J11FT
  7. 7. 7 Public Poll! You can get Kahoot! to participate in the poll, just before the coffee break
  8. 8. 8 Introduction: What is Java up to? What is going on behind the curtain? How is Java organized: the release train etc… What is underway for the language and the VM?
  9. 9. 9 How is Java organized?
  10. 10. 10 OpenJDK Enhancement Proposal JEP 1: Roadmap Process JEP 11: Incubator Modules (Java 9) JEP 12: Preview Language and VM feature (Java 11) JEP 248: Make G1 the default GC (Java 9) JEP 286: Local-Variable Type Inference (Java 10) JEP 291: Deprecate CMS (Java 9) JEP 326: Raw String Literals (Java 11) ...
  11. 11. 12 jdk Amber var condy expr switch record Valhalla nest mate value type preview jdk 9 release jdk 10 release jdk 12 jdk 11 release
  12. 12. 13 Time-Based Release Versioning A release every 6 months March 2014: Java 8 LTS Sept 2017: Java 9 March 2018: Java 10 Sept 2018: Java 11 LTS March 2019: Java 12 Sept 2019: Java 13 ... March 2021: Java 16 Sept 2021: Java 17 LTS –
  13. 13. 14 Java Community Process JSR 365: Contexts and Dependency Injection 2.0 JSR 376: Java Platform Module System (several JEPs) Umbrella JSR 383: Java SE 10 Umbrella JSR 384: Java SE 11 Time based release → Inversion of Control!
  14. 14. 15 How is it Distributed? Java SE are distributions that pass the TCK AdoptOpenJDK Azul Zulu / Azul Zing + C4 (GC) + Falcon (JIT) IBM J9 OpenJ9 (VM + JIT + GCs) OpenJDK Oracle + Mission Control, + Flight Recorder (open sourced!) RedHat + Shenandoah (GC)
  15. 15. 17 Java 10
  16. 16. 18 Local Variable Type Inference
  17. 17. 19 Demo!
  18. 18. 20 Local Variable Type Inference Let the compiler infers the type of local variables var list = List.of("hello", "devoxx"); var max = list.stream().max(String::compareTo); max.ifPresent(System.out::println); Fields and methods can not use var class Foo { var foo; // fails int foo(var a); // fails }
  19. 19. 21 Var & Inference Works with for(:) and try(=) for (var element: list) { ... } try (var lines = Files.lines(path)) { ... } Works beautifully with anonymous classes var counter = new Object() { int value; }; list.forEach(e -> counter.value++);
  20. 20. 22 Var & Inference (2) Inference fails for var a; // fails var a = null; // fails var lambda = x -> x; // fails var methodref = Integer::sum; // fails var array = { 1, 2, 3 }; // fails Work surprisingly if return type is needed var empty = List.of(); // List<Object>
  21. 21. 23 When to use var? Guidelines Choose variable names that provide useful information. Consider var when the initializer provides sufficient information to the reader. Don't worry too much about "programming to the interface" with local variables. http://openjdk.java.net/projects/amber/LVTIstyle.html
  22. 22. 24 var local type var inference 10
  23. 23. 25 Evil Plan
  24. 24. 26 Java 11 Var as Lambda Parameters Nestmates Condy Raw string
  25. 25. 27 Var as Lambda Parameters
  26. 26. 28 var as Type in Lambda Parameters Lambda parameters can use var IntBinaryOperator fun = (var x, var y) -> x + y; Allow modifiers and annotations IntBinaryOperator fun = (final var x, final var y) -> x + y; BinaryOperator<Integer> fun = (@NonNull var x, @NonNull var y) -> x + y;
  27. 27. 30 NestMates
  28. 28. 31 Can You Spot the Problem? The compiler does stupid things behind your back interface Foo { public int value(); private static int helperValue() { return 42; } public static Foo create() { return new Foo() { public int value() { return helperValue(); } }; } }
  29. 29. 32 The Accessor is Public! The inner class needs to access Foo.helperValue() public interface Foo { public abstract int value(); private static int helperValue(); Code: 0: bipush 42 2: ireturn public static int access$000(); Code: 0: invokestatic InterfaceMethod helperValue:()I 3: ireturn }
  30. 30. 33 Can You Spot The Problem (2)? And what about using reflection? public class Foo { private int value; public class Bar { public int getValue() { return Foo.class.getDeclaredField("value") .getInt(); } } }
  31. 31. 34
  32. 32. 35 NestMates Sync the JVMS and the JLS view on private Creates two new class attributes NestMembers (in enclosing class) List all internal classes NestHost (in internal classes) Name the enclosing class  private access check by the VM Is it the same class ? Is the class listed as a nest members of the nest host ?
  33. 33. 36 Class Loading Order? May the VM load more classes than before? class Foo { private static int value; static class Bar { int m() { return value; } int m2() { return 42; } } } No, the access resolution is lazy but IllegalAccessError may appear later
  34. 34. 37 Constant Dynamic
  35. 35. 38 Constant Dynamic The VM only allow primitives, String, etc. as constant pool constants  add arbitrary constant in the constant pool Constant pool constant (use ldc to load) CONSTANT_InvokeDynamic_info { u1 tag; u2 bootstrap_method_attr_index; u2 name_and_type_index; } Bootstrap method (called once) Object bsm(Lookup lookup, String name, Class<?> type, ...) { ... }
  36. 36. 39 Example in Java (maybe) Alleviate the burden of the static block if the initialization is idempotent class Foo { private static final lazy boolean DEBUG = Boolean.valueOf(System.getenv("DEBUG")); void bar() { if (DEBUG) { ... } } }
  37. 37. 40 Example in Java (maybe) No static block needed, lazy initiailization done by the VM class Foo { 10: condy constantMetaFactory.bsm $init_DEBUG$ private static boolean $init_DEBUG$() { return Boolean.valueOf(System.getenv("DEBUG")); } void bar() { ldc 10 ifeq ... } }
  38. 38. 41 Constant Lambda All Lambdas are initialized with indy class Foo { IntSupplier provider() { return () -> 42; } } class Foo { 10: indy LambdaMetaFactory.lambda $lambda$ IntSupplier() IntSupplier provider() { indy 10 } private static int $lambda$() { return 42; } }
  39. 39. 42 Constant Lambda with condy Constant Lambdas should be initialized with condy class Foo { IntSupplier provider() { return () -> 42; } } class Foo { 10: condy lambdaMetaFactory.condy $lambda$ IntSupplier IntSupplier provider() { ldc 10 } private static int $lambda$() { return 42; } }
  40. 40. 43 Constant Dynamic vs Invokedynamic Differences between condy and indy Constant Dynamic InvokeDynamic can represent only constant any expression creation lazy created (ldc) lazy created (invokedynamic) interpreter constant non-constant c1 constant non-constant c2 constant constant graal constant constant
  41. 41. 44 Lambda Creation Java 8 All lambdas creation use invokedynamic Constant lambdas are constant at JIT time Java 11 Introduction of constant dynamic in the VM Java 12? Constant lambdas use constant dynamic Need re-compilation :( Constant lambdas are constant at interpreter time
  42. 42. 45 Constant Dynamic and Annotation Annotation values are constants in the constant pool Condy allows to define any constants ! Proposal: allow any class instance as an annotation value Problem: any use cases?
  43. 43. 46 Raw String
  44. 44. 47 DEMO!
  45. 45. 48 Java String Issues No way to create a non-despecialized string var pattern = Pattern.compile(""); Not easy to create a multi-lines string var s = "this is a longn" + "multi-linesn" + "of text"; Not easy to embed code var s = "<a href="javascript: alert(‘hello’)">";
  46. 46. 49 Raw String Add non-despecialized string and multi-lines string Starts by n-backticks (`) and ends by n-backticks var pattern = Pattern.compile(``); var s = `this is a long multi-lines of text`; var s = ```<a href="javascript: alert(‘hello’)">```;
  47. 47. 50 Raw String API strip(): same as trim(), works with UTF-8 spaces! stripIndent(): removes indenting spaces stripLeading(), stripTrailing(): removes leading and trailing spaces stripMarkers(): removes what is outside the markers lines(): streams the lines of the multiline
  48. 48. 51 WARNING! Because you can embed Java code in raw String var text = `` var s = `this is a long multi-lines of text`; ``; it means that `` is not the empty String but the start of a raw String
  49. 49. 52 var local type var inference 10 11 var as lambda parameters raw string nestmatescondy inner classes private in VM
  50. 50. 53 Even More Evil Plan For World Domination!
  51. 51. 54 Java 12+ Switch Record
  52. 52. 55
  53. 53. 56 Limitation of Switch Switch doesn’t work well when the result is an expression Car car; switch(text) { case "upgrade": case "awesome": car = new Mustang(); break; case "regular": car = new Clio(); break; default: throw new WTFException(); }
  54. 54. 57 Switch Expression Use break expression to specify the result of a case var car = switch(text) { case "upgrade": case "awesome": break new Mustang(); case "regular": System.out.println("I am a Clio!"); break new Clio(); default: throw new WTFException(); };
  55. 55. 58 Others Limitations Try to get rid of fall-through It makes the code unreadable, easy to introduce regression when refactoring Try have a story for null better than throw NPE Nice to have: a shorter syntax for single expression?
  56. 56. 59 Avoid Fall-through Allow comma separated cases var car = switch(text) { case "upgrade", "awesome": break new Mustang(); case "regular": System.out.println("I am a Clio!"); break new Clio(); default: throw new WTFException(); };
  57. 57. 60 Allow case null NPE unless there is a case null var car = switch(text) { case "upgrade", "awesome": break new Mustang(); case "regular": System.out.println("I am a Clio!"); break new Clio(); case null, default: throw new WTFException(); }; Allow to mix case: and default:?
  58. 58. 61 Retrofit the Statement Switch Comma separated cases and case null are also available on the statement switch Car car; switch(text) { case "upgrade", "awesome": car = new Mustang(); break; case "regular": car = new Clio(); break; case null, default: throw new WTFException(); }
  59. 59. 62 Single Expression Syntax Use -> instead of : break var car = switch(text) { case "upgrade", "awesome" -> new Mustang(); case "regular": System.out.println("I am a Clio!"); break new Clio(); case null, default -> throw new WTFException(); }; “->” also work for throw?
  60. 60. 63 Problem of -> as shorter syntax -> used here is not the same as the -> used in lambdas and the syntax -> { } does not work with case: Alternative syntax var car = switch(text) { case "upgrade", "awesome": new Mustang(); case "regular": new Clio(); case null, default: throw new WTFException(); };
  61. 61. 64 I suggest you do this poll at Devoxx. Make sure to wear flame-proof pants! Brian Goetz
  62. 62. 65 Poll! 1. no shorter syntax, break expr is short enough 2. “->” as shorter syntax case "regular" -> new Clio(); case "regular": break new Clio();
  63. 63. 66 Poll! 1. no shorter syntax, break expr is short enough 2. “->” as shorter syntax 3. “:” as shorter syntax case "regular" -> new Clio(); case "regular": break new Clio(); case "regular": new Clio();
  64. 64. 67 Coffee (or whatever) Break! Coffee (or whatever) Break!
  65. 65. 68 Java 12+ Switch Record
  66. 66. 69 Bytecode Translation for Switch
  67. 67. 70 Current Translation Strategy of Switch on String in pseudo bytecode aload 0 invokevirtual String.hashCode ()I lookupswitch label -231171556 // "upgrade".hashCode() test.equals("upgrade")? 0: -1 label 1086463900 // "regular".hashCode() test.equals("regular")? 1: -1 tableswitch label 0 … // new Mustang label 1 … // new Clio istore 1 var car = switch(text) { case "upgrade": new Mustang(); case "regular": new Clio(); };
  68. 68. 71 Current Translation Strategy of Switch What if the compiler world and the VM world are not aligned anymore? For String: The solution could be to specify that String.hashCode() can not be changed For Enum: It should state that you can only add enum values at the end of the list
  69. 69. 72 New Translation to Bytecode invokedynamic is used to associate an int to each case in pseudo-bytecode invokedynamic (String)I SwitchMetaFactory.string ["upgrade", "awesome", "regular"], [0, 0, 1] tableswitch label 0: … // new Mustang label 1: … // new Clio astore 1 var car = switch(text) { case "upgrade": new Mustang(); case "regular": new Clio(); };
  70. 70. 73 Performance?? Test avec JMH old switch new switch cascade if equals small (4 cases) 23.9 +/- 0.2 ns/op 11.6 +/- 0.1 ns/op 16.4 +/- 0.1 ns/op big (10 cases) 135.4 +/- 4.0 ns/op 86.2 +/- 1.5 ns/op 25.1 +/- 0.4 ns/op
  71. 71. 74 New Translation to Bytecode Switch on enums, String, double, float, long use indy The bytecode becomes independent from the compiler world Usually better performance Less bytecodes Dynamic strategies adaptation But it needs to recompile the old code... And it puts more pressure on the JIT It may take longer to reach steady state
  72. 72. 75 Extending Switch to Accept Types (Toward Pattern Matching)
  73. 73. 76 Extending Switch to Accept Types Computing something on a hierarchy you do not control int computeTax(Vehicle v) { if (v instanceof Bike) { return 10; } else if (v instanceof Car) { return 42 + ((Car) v).passengers() * 10; } else if (v instanceof Bus) { return ((Bus) v).weight() * ((Bus) v).wheels(); } else { throw new WTFException("unknown vehicle kind"); } }
  74. 74. 77 Extending Switch to Accept Types One can use a Visitor (if there is a method accept) int computeTax(Vehicle v) { return v.accept(VISITOR); } private static final Visitor VISITOR = new Visitor() { public int visitBike(Bike bike) { return 10; } public int visitCar(Car car) { return 42 + car.passengers() * 10; } public int visitBus(Bus bus) { return bus.weight() * bus.wheels(); } };
  75. 75. 78 Extending Switch to Accept Types Computing something on a hierarchy you do not control int computeTax(Vehicle v) { return switch(v) { case Bike: 10; case Car: 42 + ((Car) v).passengers() * 10; case Bus: ((Bus) v).weight() * ((Bus) v.wheels(); default: throw new WTFException("unknown ..."); }; }
  76. 76. 79 Translation to Bytecode Same Translation as with Strings aload 0 invokedynamic (Vehicle)I SwitchMetaFactory.types [Bike.class, Car.class, Bus.class], [0, 1, 2] tableswitch label 0: bipush 10 label 1: bipush 42 aload 0 checkcast Car invokevirtual Car passagers ()I iadd label 2: … // ((Bus) v).weight() * ((Bus) v).wheels() ireturn
  77. 77. 80 Performance?? Test with JMH instanceof type switch lot of cases lot of classes 395 +/- 21.2 ns/op 55 +/- 2.1 ns/op small n cases lot of classes 35 +/- 1.6 ns/op 51 +/- 0.7 ns/op small n cases small n classes 7 +/- 0.1 ns/op 6 +/- 0.1 ns/op
  78. 78. 81 Extending Switch to Accept Types Naming the type avoid the cast int computeTax(Vehicle v) { return switch(v) { case Bike: 10; case Car car: 42 + car.passengers() * 10; case Bus bus: bus.weight() * bus.wheels(); default: throw new WTFException("unknown ..."); }; }
  79. 79. 82 Bringing Back the Encapsulation Allows destructured switch on type int computeTax(Vehicle v) { return switch(v) { case Bike: 10; case Car(int passengers): 42 + passengers * 10; case Bus(int weight, int wheels): weight * wheels; ... }; } We need the inverse operation of a constructor
  80. 80. 83 De-constructor A de-constructor describes how to get a tuple of values from an object class Bus { Bus(int weight, int wheels) { … } (int, int) deconstructor() { return …; } } But returning several values in not easy in Java (yet!)
  81. 81. 84 A Path to a Solution The problem can be solved for classes with a primary constructor record Bus(int weight, int wheels) { int weight; // compiler generated int wheels; // compiler generated public static Extractor extractor() { // compiler generated return Extractor.of(bus -> bus.weight, bus -> bus.wheels); } } The Extractor is then a list of getters
  82. 82. 85 Switch on Records record Bike implements Vehicle record Car(int passengers) implements Vehicle record Bus(int weight, int wheels) A record provides an extractor that returns its component values int computeTax(Vehicle v) { return switch(v) { case Bike: 10; case Car(var passengers): 42 + passengers * 10; case Bus(var weight, var wheels): weight * bus.wheels; default: throw new WTFException("unknown vehicle kind"); }; }
  83. 83. 86 Switch on Records - Translation The getter from the extractor are defined as Constant Dynamic 0: ConstantDynamic MethodHandle SwitchMetafactory.getter [Car.class, 0]; 1: ConstantDynamic MethodHandle SwitchMetafactory.getter [Bus.class, 0]; 2: ConstantDynamic MethodHandle SwitchMetafactory.getter [Bus.class, 1]; int computeTax(Vehicle v) { aload 0 invokedynamic (Vehicle)I SwitchMetaFactory.types [Bike.class, Car.class, Bus.class] [0, 1, 2] tableswitch label 0: bipush 10 label 1: bipush 42 aload 0 invokedynamic (Vehicle)I SwitchMetafactory.extract [item 0] iadd label 2: … ireturn 1
  84. 84. 87 Record
  85. 85. 88 Record A plain simple data object record Point(final int x, final int y) is translated to public final class Point { final int x; final int y; public Point(int x, int y) { this.x = x; this.y = y; } public int x() { return x; } public int y() { return y; } // + equals / hashCode / toString / extractor }
  86. 86. 89 Record Record can have supplementary methods but no supplementary fields record Point(final int x, final int y) record Circle(final Point center, final int radius) { public double surface() { return Math.PI * radius * radius; } }
  87. 87. 90 Record and Precondition Relax java rule: you can have preconditions before the calls to the super / default constructor record Circle(final Point center, final int radius) { public Circle(Point center, int radius) { Preconditions.requiresNonNull(center); Preconditions.requiresPositive(radius); default(center, radius); } } java.util.Preconditions contains usual precondition tests
  88. 88. 91 Setters are not Generated! Because the compiler doesn’t know about preconditions record Circle(final Point center, final int radius) { public Circle(Point center, int radius) { requiresNonNull(center); requiresPositive(radius); default(center, radius); } public void center(Point center) { this.center = requiresNonNull(center); } public void radius(int radius) { this.radius = requiresPositive(radius); } }
  89. 89. 92 Translating Records to Bytecode
  90. 90. 93 equals / hashCode / toString / extractor The code is not generated by the compiler Use invokedynamic + constant dynamic /*record*/ final class Bus { 10: constant dynamic Extractor RecordMetafactory.extractor [Bus::weight, Bus::wheels] final int weight; final int wheels; public String toString() { return invokedynamic RecordMetafactory.toString [constant item 10] } }
  91. 91. 94 Indy + Condy The Extractor is computed once lazily equals(), balance the cascade of if … else depending on the cost of equals() for each components can re-balance the cascade if..else at runtime! equals and hashCode can do nullcheck implicitly
  92. 92. 95 Extractor Use ldc + constant dynamic /*record*/ final class Bus { 10: constant dynamic Extractor RecordMetafactory.extractor [Bus::weight, Bus::wheels] final int weight; final int wheels; public static /*extractor*/ Extractor extractor() { ldc [constant item 10] areturn } }
  93. 93. 96 Record vs Property Is Record + Extractor like Rémi / Stephen Colebourne Property Proposal written 10 years ago! shhhhhhhhhhhhhh!
  94. 94. 97 var local type var inference 10 11 var as lambda parameters raw string nestmatescondy 12 - 13 inner classes private in VM expr switch type switch const lambda record
  95. 95. 98
  96. 96. 99 Java 14+ Sealed interfaces Pattern matching Value types
  97. 97. 100 Exhaustive Switch
  98. 98. 101 Exhaustive Switch?? record Bike() implements Vehicle record Car(final int passengers) implements Vehicle record Bus(final int weight, final int wheels) implements Vehicle How can we remove this pesky default ? int computeTax(Vehicle v) { return switch(v) { case Bike: 10; case Car(var passengers): 42 + passengers * 10; case Bus(var weight, var wheels): weight * bus.wheels; default: throw new WTFException("unknown vehicle kind"); }; }
  99. 99. 102 Answer: Sealed Interface! Close the interface by listing all the subtypes sealed interface Vehicle { record Bike implements Vehicle record Car(...) implements Vehicle record Bus(...) implements Vehicle } Implemented using NestMates + flag on the interface
  100. 100. 103 Sealed Interface Enables Exhaustive Switch The compiler knows that all the subtypes are covered int computeTax(Vehicle v) { return switch(v) { case Bike: 10; case Car(var passengers): 42 + passengers * 10; case Bus(var weight, var wheels): weight * wheels; }; } How does the VM know that the switch is exhaustive?
  101. 101. 104 Sealed Interface Enables Exhaustive Switch How does the VM know that the switch is exhaustive? sealed interface Vehicle { record Bike implements Vehicle record Car(...) implements Vehicle record Bus(...) implements Vehicle } Because the subtypes are nestmates!
  102. 102. 105 Generalized Pattern Matching
  103. 103. 106 Generalized Pattern Matching Constants are allowed Can extract value from different objects “_” means whatever var value = switch(shape) { case Circle(_, 0): 0; case Circle(_, var radius): PI*radius*radius; case Rectangle(Point(var x1, var y1), Point(var x2, var y2)): abs(x2 – x1)*abs(y2 – y1); }
  104. 104. 108
  105. 105. 109 Value Type
  106. 106. 110 Problems Time ratio to read a value in a CPU register vs RAM circa 1990: 1 to 1 nowadays: 1 to 100 The cost of cache misses dramatically increases! Modern programming => more abstractions => JITs are more powerful but the programming model prevents JITs to deliver zero cost abstraction
  107. 107. 111 Value Type Writes like a class, works like an int No reference, only direct value No identity, == returns false System.identityHashCode(), synchronized, wait() all this fails No need to be allocated on the heap
  108. 108. 112 The Value Type Color A value type has fields and methods value class Color { final int red; final int green; final int blue; public static Color <create>() { … } public int red() { return red; } } A value type is immutable!
  109. 109. 113 An Instance of Color in Memory Color red blue green header
  110. 110. 114 An Array of Color Instances header With references With value types red blue green header red blue green header red blue green header red blue green red blue green red blue green
  111. 111. 117 Performance! Value types More pressure on the JITs (never escape) Less pressure to the GCs JMH on an array of Color 1 000 000 of colors creation time (write) calculation time (read) jdk10 97.2 ms 52.5 ms jdk10-mvt 30.5 ms 18.5 ms
  112. 112. 118 Value Based Class and Compatibility Since 8, some classes are documented as value based classes Beware, they will becomes value types in the future
  113. 113. 119 var local type var inference 10 11 var as lambda parameters raw string nestmatescondy 12 - 13 inner classes private in VM expr switch type switch const lambda record 14+ sealed interface pattern matching value type
  114. 114. 120 That’s it!
  115. 115. 121 Questions?

×