From JDK 9 to 16 New Java Workshop Presented by Simon Ritter, Deputy CTO | Azul Systems Inc.
Introduction 2 •Six-month release cadence •Seven releases since JDK 9 •More features being delivered faster than ever before Java has changed… …a lot
Incubator Modules 3 • Defined by JEP 11 • Non-final APIs and non-final tools ‒ Deliver to developers to solicit feedback ‒ Can result in changes or even removal ‒ First example: HTTP/2 API (Introduced in JDK 9, final in JDK 11)
Preview Features 4 • Defined by JEP 12 • New feature of the Java language, JVM or Java SE APIs ‒ Fully specified, fully implemented but not permanent ‒ Solicit developer real-world use and experience ‒ May lead to becoming a permanent feature in future release • Must be explicitly enabled ‒ javac --release 14 --enable-preview ... ‒ java --enable-preview ... • Preview APIs ‒ May be required for a preview language feature ‒ Part of the Java SE API (java or javax namespace)
JDK 9
Project Jigsaw And Modules
Why Do We Need Modularity in Java? 7 • JDK 1.0 ‒ 122 library classes for simplifying application development • JDK 8.0 ‒ Over 4,500 public classes in the rt.jar file • JDK 9 ‒ 27 Java SE modules, 48 JDK modules • Two sides to modularity: 1. JDK core libraries 2. Application code
Module Fundamentals 8 • Module is a grouping of code ‒ For Java this is a collection of packages • Modules can contain other things ‒ Native code ‒ Resources ‒ Configuration data com.azul.zoop com.azul.zoop.alpha.Name com.azul.zoop.alpha.Position com.azul.zoop.beta.Animal com.azul.zoop.beta.Reptile com.azul.zoop.theta.Zoo com.azul.zoop.theta.Lake
Module Declaration module com.azul.zoop {} module-info.java com/azul/zoop/alpha/Name.java com/azul/zoop/alpha/Position.java com/azul/zoop/beta/Animal.java com/azul/zoop/beta/Reptile.java com/azul/zoop/theta/Zoo.java com/azul/zoop/theta/Lake.java
Module Dependencies module com.azul.zoop { requires com.azul.zeta; } com.azul.zoop com.azul.zeta
Module Dependencies module com.azul.zapp { requires com.azul.zoop; requires java.sql; } com.azul.zapp com.azul.zoop java.sql
Module Dependency Graph com.azul.zapp java.base java.sql com.azul.zoop com.azul.zeta java.xml java.logging explicit implicit
Module Dependency Graph 13 • No missing dependencies • No cyclic dependencies • No split packages
Readability v. Dependency com.azul.zapp java.sql java.logging module java.sql { requires transitive java.logging; } Driver d = … Logger l = d.getParentLogger(); l.log(“azul’); Implied readability
Module Implied Readability Graph com.azul.zapp java.base java.sql com.azul.zoop com.azul.zeta java.xml java.logging explicit implicit implied
Package Visibility module com.azul.zoop { requires com.azul.zeta; exports com.azul.zoop.alpha; exports com.azul.zoop.beta to com.azul.zapp; } com.azul.zoop com.azul.zoop.alpha com.azul.zoop.beta com.azul.zoop.theta com.azul.zapp only
More Package Visibility open module com.azul.zoop { requires com.azul.zeta; } com.azul.zoop com.azul.zoop.alpha com.azul.zoop.beta com.azul.zoop.theta com.azul.zoop.alpha com.azul.zoop.beta com.azul.zoop.theta REFLECTION IMPORT
Even More Package Visibility module com.azul.zoop { requires com.azul.zeta; exports com.azul.zoop.alpha; exports com.azul.zoop.beta to com.azul.zapp; opens com.azul.theta; } com.azul.zoop com.azul.zoop.theta REFLECTION IMPORT com.azul.zoop.alpha com.azul.zoop.beta com.azul.zapp only
Restricted Keywords module requires requires; exports exports to to; module { opens opens; }
Accessibility • For a package to be visible ‒ The package must be exported by the containing module ‒ The containing module must be read by the using module • Public types from those packages can then be used com.azul.zoop com.azul.zapp reads
Using Modules
Module Path $ javac –modulepath dir1:dir2:dir3
Compilation With Module Path $ javac –-module-path mods –d mods src/module-info.java src/com/azul/zoop/alpha/Name.java mods/module-info.class mods/com/azul/zoop/alpha/Name.class src/module-info.java src/com/azul/zoop/alpha/Name.java
Application Execution • -p is the abbreviation of --module-path $ java –p mods –m com.azul.zapp/com.azul.zapp.Main Azul application initialised! module name main class
Packaging With Modular JAR Files mods/module-info.class mods/com/azul/zapp/Main.class $ jar --create --file=mylib/zapp.jar --main-class=com.azul.zapp.Main -C mods . module-info.class com/azul/zapp/Main.class zapp.jar
Application Execution (JAR) $ java –p mylib:mods –m com.azul.zapp Azul application initialised!
Linking Modular run-time image … conf bin jlink $ jlink --module-path $JDKMODS --add-modules java.base –-output myimage $ myimage/bin/java –-list-modules java.base@9.0
Linking An Application $ jlink --module-path $JDKMODS:$MYMODS --add-modules com.azul.zapp –-output myimage $ myimage/bin/java –-list-modules java.base@9 java.logging@9 java.sql@9 java.xml@9 com.azul.zapp@1.0 com.azul.zoop@1.0 com.azul.zeta@1.0
The Implications Of jlink • "Write once, run anywhere"  Long term Java slogan, mainly held true • jlink generated runtime may not include all Java SE modules ‒ But is still a conforming Java implementation ‒ To conform to the specification, the runtime:  Must include the java.base module  If other modules are included, all transitive module dependencies must also be included  Defined as a closed implementation
Application Migration
Typical Application (JDK 8) jar jar jar JDK jar jar jar jar jar jar jar jar jar Classpath
Typical Application (JDK 9) jar jar jar module java.base module java.desktop module java.datatransfer module java.xml jar jar jar jar jar jar jar jar jar Unnamed module
Sample Application myapp.jar libgl.jar mylib.jar gluegen.jar jogl.jar module java.base module java.desktop module java.datatransfer module java.xml
Run Application With Classpath $ java –classpath lib/myapp.jar: lib/mylib.jar: lib/libgl.jar: lib/gluegen.jar: lib/jogl.jar: myapp.Main
Sample Application module myapp.jar libgl.jar module mylib.jar gluegen.jar jogl.jar module java.base module java.desktop module java.datatransfer module java.xml
Application module-info.java module myapp { requires mylib; requires java.base; requires java.sql; requires libgl; ???? requires gluegen; ???? requires jogl; ???? }
Sample Application module myapp.jar module libgl.jar module mylib.jar module gluegen.jar module jogl.jar module java.base module java.desktop module java.datatransfer module java.xml
Automatic Modules 38 • Real modules • Simply place unmodified jar file on module path ‒ Rather than classpath • No changes to JAR file • Module name derived from JAR file name • Exports all its packages ‒ No selectivity • Automatically requires all modules on the module path
Application Module Dependencies module myapp.jar module libgl.jar module mylib.jar module gluegen.jar module jogl.jar module java.base module java.desktop module java.datatransfer module java.xml Implicit Explicit
Run Application With Modules $ java –classpath lib/myapp.jar: lib/mylib.jar: lib/libgl.jar: lib/gluegen.jar: lib/jogl.jar: myapp.Main $ java –p mylib:lib –m myapp
Migrating Applications To The Java Platform Module System
Migration Guidance From Oracle "Clean applications that just depend on java.se should just work"
Migrating Applications to JPMS 43 • Initially, leave everything on the classpath • Anything on the classpath is in the unnamed module ‒ All packages are exported ‒ The unnamed module depends on all modules • Migrate to modules as required ‒ Try automatic modules ‒ Move existing jar files from classpath to modulepath
Classpath v Modulepath classpath modulepath Unnamed module jar jar jar module-info.class jar module-info.class jar Automatic module module-info.class
Reversing Encapsulation • "The Big Kill Switch" --illegal-access • Four options: ‒ permit (current default) ‒ warn ‒ debug ‒ deny (JDK 16 default)
Reversing Encapsulation • Big kill switch overrides encapsulation ‒ From the unnamed module (i.e. classpath) ‒ Allows unlimited refective access to named modules  Not from named modules • Warning messages written to error stream • Useful to understand use of --add-exports and --add-opens when migrating to named modules
Reversing Encapsulation 47 • Allowing direct access to encapsulated APIs ‒ --add-exports • Allowing reflective access to encapsulated APIs ‒ --add-opens --add-exports java.management/com.sun.jmx.remote.internal=mytest --add-exports java.management/sun.management=ALL-UNNAMED --add-opens java.base/java.util=ALL-UNNAMED
Finding Dependencies: jdeps > jdeps --module-path /opt/javafx-sdk-11/lib --add-modules=javafx.controls --list-deps FlightTracker.jar JDK removed internal API/com.sun.media.jfxmediaimpl.platform.ios java.base java.datatransfer java.desktop/java.awt.dnd.peer java.desktop/sun.awt java.desktop/sun.awt.dnd java.desktop/sun.swing java.logging java.scripting java.sql java.xml jdk.jsobject jdk.unsupported jdk.unsupported.desktop jdk.xml.dom
JDK 10
Java Storage Basics 50 • Fields (instance and static) ‒ Part of an object, exist for the lifetime of an object ‒ Initialisation guaranteed by compiler • Local variables ‒ Scoped to region of code (method, statement, block) ‒ Initialisation not guaranteed ‒ Cheap when allocated on the stack ‒ Name and use is often more important than the type
Local Variable Type Inference • Why? ‒ JavaScript has it so it must be good ‒ Streams hide intermediate types ‒ Why not expand this elsewhere? ‒ var can make code more concise  Without sacrificing readability List l = names.stream() // Stream<String> .filter(s -> s.length() > 0) // Stream<String> .map(s -> getRecord(s)) // Stream<Record> .collect(toList()); // ArrayList<Record>
Simple Uses of Local Variables ArrayList<String> nameList = new ArrayList<String>(); List<String> userList = new ArrayList<>(); Stream<String> stream = userList.stream(); for (String name : userList) { ... } for (int i = 0; i < 10; i++) { ... }
Simple Uses of Local Variable Type Inference var userList = new ArrayList<String>(); // Infers ArrayList<String> var stream = userList.stream(); // Infers Stream<String> for (var name : userList) { // Infers String ... } for (var i = 0; i < 10; i++) { // Infers int ... }
Simple Uses of var • Clearer try-with-resources try (InputStream inputStream = socket.getInputStream(); InputStreamReader inputStreamReader = new InputStreamReader(inputStream, UTF_8); BufferedReader bufferedReader = new BufferedReader(inputStreamReader)) { // Use bufferedReader }
Simple Uses of var • Clearer try-with-resources try (var inputStream = socket.getInputStream(); var inputStreamReader = new inputStreamReader(inputStream, UTF_8); var bufferedReader = new BufferedReader(inputStreamReader)) { // Use bufferedReader }
More Typing With Less Typing • Java is still statically typed var name = "Simon"; // Infers String, so name is String name = "Dylan"; // Still String name = 42; // Not a String error: incompatible types: int cannot be converted to String
Final and Non-Final 57 • var simply indicates the compiler infers the type • Use of var does not make a variable final • Still need final • No shortcut for final var (like val) ‒ How often do you make local-variables final? var name = "Simon"; name = "Dylan"; // name is not final final var name = "Simon";
Action At A Distance var l = new ArrayList<String>(); var s = l.stream(); // Lots of lines of complex code var n = l.get(0); // Err, what is n?
Not Everything Can Be Inferred int[] firstSixPrimes = {2, 3, 5, 7, 11, 13}; var firstSixPrimes = {2, 3, 5, 7, 11, 13}; error: cannot infer type for local variable firstSixPrimes var firstSixPrimes = {2, 3, 5, 7, 11, 13}; ^ (array initializer needs an explicit target-type) var firstSixPrimes = new int[]{2, 3, 5, 7, 11, 13}; var firstTwoPrimes = new Integer[]{2, 3};
Types Required On Both Sides var list = null; error: cannot infer type for local variable list var list = null; ^ (variable initializer is 'null')
Types Required On Both Sides var list; list = new ArrayList<String>(); error: cannot infer type for local variable list var list; ^ (cannot use 'var' on variable without initializer)
No Multiple Variable Declaration 62 var a, b = 1; error: 'var' is not allowed in a compound declaration
Literals with var (Good) • Original ‒ boolean ready = true; ‒ char ch = 'x'; ‒ long sum = 0L; ‒ String label = "Foo";
Literals with var (Good) • With var ‒ var ready = true; ‒ var ch = 'x'; ‒ var sum = 0L; ‒ var label = "Foo";
Literals with var (Dangerous) • Original ‒ byte flags = 0; ‒ short mask = 0x7fff; ‒ long base = 10;
Literals with var (Dangerous) • Original ‒ var flags = 0; ‒ var mask = 0x7fff; ‒ var base = 10; All these cases will infer int
Beware of Multiple Type Inference var itemQueue = new PriorityQueue<>(); Diamond operator, primary type inference Secondary type inference itemQueue infered as PriorityQueue<Object>(); PriorityQueue<Integer> itemQueue = new PriorityQueue<>();
Programming To An Interface • Common to use interface rather than concrete type • Using var always infers concrete type • Polymorphism still works ‒ArrayList<String> is still a List ‒You can use myList wherever a List is required List<String> myList = new ArrayList<>(); var myList = new ArrayList<String>();
Lambdas and var Predicate<String> blankLine = s -> s.isBlank(); var blankLine = s -> s.isBlank(); error: cannot infer type for local variable blankLine var blankLine = s -> s.isBlank(); ^ (lambda expression needs an explicit target-type)
Intersection Types <T extends Closeable & Iterable<E>> T getData() { // Return something that implements both // Closeable and Iterable<E> } Valid Java syntax
Intersection Types • The problem <E> Optional<E> firstMatch(Predicate<? super E> condition) { XXX elements = getData(); try (elements) { return StreamSupport.stream(elements.spliterator(), false) .filter(condition) .findAny(); } } elements must implement Closeable elements must implement Iterable<E> XXX is Closeable & Iterable<E>, which won't compile
Intersection Types • The solution: var <E> Optional<E> firstMatch(Predicate<? super E> condition) { var elements = getData(); try (elements) {` return StreamSupport.stream(elements.spliterator(), false) .filter(condition) .findAny(); } } Compiler infers a valid type that is impossible to express with Java syntax
Inner Classes 73 • This code won't compile Object fruit = new Object() { String name = "apple"; String inFrench() { return "pomme"; } }; System.out.println("Fruit = " + fruit.name); System.out.println("In French = " + fruit.inFrench());
Inner Classes 74 • Using var this will compile and run ‒ The key is non-denotable types var fruit = new Object() { String name = "apple"; String inFrench() { return "pomme"; } }; System.out.println("Fruit = " + fruit.name); System.out.println("In French = " + fruit.inFrench());
var: Reserved Type (Not Keyword) var var = new Var(); public class var { public var(String x) { ... } } public class Var { public Var(String x) { ... } }
Puzzler 1 static boolean calc1(int mask) { long temp = 0x12345678; return (((temp << 6) | temp) & mask) > 0; }
Puzzler 1 • Should we use var? Yes? No? static boolean calc1(int mask) { var temp = 0x12345678; return (((temp << 6) | temp) & mask) > 0; }
Puzzler 1 • 0x12345678 fits in an int ‒ Using var will infer an int, not a long • Passing a mask < 0 will give different results ‒ Using long, mask < 0 returns true ‒ Using var (infer int), mask < 0 returns false
Puzzler 2 static List<String> create1(boolean foo, boolean bar) { List<String> list = new ArrayList<>(); if (foo) list.add("foo"); if (bar) list.add("bar"); return list; }
Puzzler 2 • Should we use var? Yes? No? static List<String> create1(boolean foo, boolean bar) { var list = new ArrayList<>(); if (foo) list.add("foo"); if (bar) list.add("bar"); return list; }
Puzzler 2 • Remember, "Beware of multiple type inference" ‒ var list = new ArrayList<>(); ‒ Diamond operator infers Object error: incompatible types: ArrayList<Object> cannot be converted to List<String> return list;
Puzzler 3 • Good use of var? Yes? No? static List<Integer> listRemoval() { List<Integer> list = new ArrayList<>(Arrays.asList(1, 3, 5, 7, 9)); var v = valueToRemove(); list.remove(v); return list; } // Separate class, package or module (in a galaxy far, far away) static Integer valueToRemove() { return 3; }
Puzzler 3 • New intern arrives and changes code... • Unexpected change in behaviour static int valueToRemove() { return 3; } List.remove(int) // Remove element at given index List.remove(Object) // Remove first instance of object {1,3,7,9} // Using var with changed valueToRemove {1,5,7,9} // Using var with unchanged valueToRemove
Guidelines For Use of var 84 1. Reading code is more important that writing it 2. Code should be clear from local reasoning 3. Code readability shouldn't depend on an IDE 4. Choose variable names that provide useful information 5. Minimise the scope of local variables 6. Consider var when the initialiser provides sufficient information 7. Use var to break up chained or nested expressions 8. Take care when using var with generics 9. Take care when using var with literals
JDK 11
JDK 11: Extend Local-Variable Syntax • Lambda parameters list.stream() .map(s -> s.toLowerCase()) .collect(Collectors.toList()); list.stream() .map((var s) -> s.toLowerCase()) .collect(Collectors.toList()); list.stream() .map((@Notnull var s) -> s.toLowerCase()) .collect(Collectors.toList());
New APIs 87 • New I/O methods  InputStream nullInputStream()  OutputStream nullOutputStream()  Reader nullReader()  Writer nullWriter() • Optional  isEmpty() // Opposite of isPresent
New APIs 88 • New String methods ‒ isBlank() ‒ Stream lines() ‒ String repeat(int) ‒ String strip() ‒ String stripLeading() ‒ String stripTrailing()
New APIs 89 • Predicate not(Predicate) lines.stream() .filter(s -> !s.isBlank()) lines.stream() .filter(Predicate.not(String::isBlank)) lines.stream() .filter(not(String::isBlank))
Missing Modules 90 • Remember, "Clean applications that only use java.se..." • The java.se.ee aggregator module removed in JDK 11 • Affected modules ‒ java.corba ‒ java.transaction ‒ java.activation ‒ java.xml.bind ‒ java.xml.ws ‒ java.xml.ws.annotation
Resolving Missing Modules 91 • All modules (except CORBA) have standalone versions ‒ Maven central ‒ Relevant JSR RI • Deploy standalone version on the upgrade module path ‒ --upgrade-module-path <path> • Deploy standalone version on the classpath
JDK 12
Switch Expressions (Preview) 93 • Switch construct was a statement ‒ No concept of generating a result that could be assigned • Rather clunky syntax ‒ Every case statement needs to be separated ‒ Must remember break (default is to fall through) ‒ Scope of local variables is not intuitive
Old-Style Switch Statement 94 int numberOfLetters; switch (day) { case MONDAY: case FRIDAY: case SUNDAY: numberOfLetters = 6; break; case TUESDAY: numberOfLetters = 7; break; case THURSDAY: case SATURDAY: numberOfLetters = 8; break; case WEDNESDAY: numberOfLetters = 9; break; default: throw new IllegalStateException("Huh?: " + day); };
New-Style Switch Expression int numberOfLetters = switch (day) { case MONDAY, FRIDAY, SUNDAY -> 6; case TUESDAY -> 7; case THURSDAY, SATURDAY -> 8; case WEDNESDAY -> 9; default -> throw new IllegalStateException("Huh?: " + day); };
New Old-Style Switch Expression int numberOfLetters = switch (day) { case MONDAY: case FRIDAY: case SUNDAY: break 6; case TUESDAY break 7; case THURSDAY case SATURDAY break 8; case WEDNESDAY break 9; default: throw new IllegalStateException("Huh?: " + day); };
New Old-Style Switch Expression outside: for (day : dayList) int numberOfLetters = switch (day) { case MONDAY: case FRIDAY: case SUNDAY: break 6; case TUESDAY break 7; case THURSDAY case SATURDAY break 8; case WEDNESDAY break 9; default: continue outside; }; Illegal jump through switch expression
Streams • New collector, teeing ‒ teeing(Collector, Collector, BiFunction) • Collect a stream using two collectors • Use a BiFunction to merge the two collections 98 Collector 1 Collector 2 BiFunction Stream Result
Streams 99 // Averaging Double average = Stream.of(1, 4, 5, 2, 1, 7) .collect(teeing(summingDouble(i -> i), counting(), (sum, n) -> sum / n));
JDK 13
Text Blocks (Preview) String webPage = """ <html> <body> <p>My web page</p> </body> </html>"""; System.out.println(webPage); $ java WebPage <html> <body> <p>My web page</p> </body> </html> $ incidental white space
Text Blocks (Preview) String webPage = """ <html> <body> <p>My web page</p> </body> </html> """; System.out.println(webPage); $ java WebPage <html> <body> <p>My web page</p> </body> </html> $ Additional blank line incidental white space Intentional indentation
Switch Expression int numberOfLetters = switch (day) { case MONDAY: case FRIDAY: case SUNDAY: break 6; case TUESDAY break 7; case THURSDAY case SATURDAY break 8; case WEDNESDAY break 9; default: throw new IllegalStateException("Huh?: " + day); };
Switch Expression int numberOfLetters = switch (day) { case MONDAY: case FRIDAY: case SUNDAY: yield 6; case TUESDAY yield 7; case THURSDAY case SATURDAY yield 8; case WEDNESDAY yield 9; default: throw new IllegalStateException("Huh?: " + day); };
JDK 14
Simple Java Data Class 106 class Point { private final double x; private final double y; public Point(double x, double y) { this.x = x; this.y = y; } public double x() { return x; } public double y() { return y; } }
Records (Preview) 107 record Point(double x, double y) { } record Range(int low, int high) { public Range { // Compact constructor if (low > high) throw new IllegalArgumentException("Bad values"); } }
Record Additional Details 108 • Compact constructor can only throw unchecked exception ‒ Syntax does not allow for specifying a checked exception • Object methods equals(), hashCode() and toString() can be overridden • The base class of all records is java.lang.Record ‒ This is an example of a preview feature Java SE API ‒ Records cannot sub-class (but may implement interfaces) • Records do not follow the Java bean pattern ‒ x() not getX() in previous example • Instance fields cannot be added to a record ‒ Static fields can • Records can be generic
Using instanceof 109 if (obj instanceof String) { String s = (String)obj; System.out.println(s.length()); }
Pattern Matching instanceof (Preview) 110 if (obj instanceof String s) System.out.println(s.length()); else // Use of s not allowed here if (obj instanceof String s && s.length() > 0) System.out.println(s.length()); // Compiler error if (obj instanceof String s || s.length() > 0) System.out.println(s.length());
Pattern Matching instanceof (Preview) 111 if (!(o instanceof String s && s.length() > 3) return; System.out.println(s.length());
Pattern Matching instanceof 112 • Be careful of scope! class BadPattern { String s = "One"; void testMyObject(Object o) { if (o instanceof String s) { System.out.println(s); // Prints contents of o s = s + " Two"; // Modifies pattern variable } System.out.println(s); // Prints "One" } }
Text Blocks • Second preview • Two new escape sequences String continuous = """This line will not contain a newline in the middle and solves the extra blank line issue """; String endSpace = """This line will not s lose the trailing spaces s""";
Helpful NullPointerException 114 • Who's never had an NullPointerException? • Enabled with -XX:+ShowCodeDetailsInExceptionMessages a.b.c.i = 99; Exception in thread "main" java.lang.NullPointerException at Prog.main(Prog.java:5) Exception in thread "main" java.lang.NullPointerException: Cannot read field "c" because "a.b" is null at Prog.main(Prog.java:5)
JDK 15
Java Inheritance 116 • A class (or interface) in Java can be sub-classed by any class ‒ Unless it is marked as final Shape Triangle Square Pentagon
Sealed Classes (JEP 360) 117 • Preview feature • Sealed classes allow control over which classes can sub-class a class ‒ Think of final as the ultimate sealed class • Although called sealed classes, this also applies to interfaces
Sealed Classes (JEP 360) 118 • Uses contextual keywords ‒ New idea replacing restricted identifiers and keywords ‒ sealed, permits and non-sealed • Classes must all be in the same package or module public sealed class Shape permits Triangle, Square, Pentagon { ... } Shape Triangle Square Pentagon Circle X
Sealed Classes (JEP 360) 119 • All sub-classes must have inheritance capabilities explicitly specified // Restrict sub-classes to defined set public sealed class Triangle permits Equilateral, Isosoles extends Shape { ... } // Prevent any further sub-classing public final class Square extends Shape { ... } // Allow any classes to sub-class this one (open) public non-sealed class Pentagon extends Shape { ... }
Contextual Keyword Humour 120 int non = 2; int sealed = 1; var var = non-sealed;
Hidden Classes (JEP 371) 121 • JVM rather than language-level feature • Classes that cannot be used directly by the bytecodes of other classes • Several situations where bytecodes generated at runtime ‒ Use of invokedynamic bytecode ‒ Lambdas are a good example ‒ Mostly bound to static class (not for use elsewhere) ‒ Often only used for short time • Hidden classes can only be accessed via reflection ‒ Primarily intended for framework developers
Records (Second Preview) 122 • Record fields are now (really) final ‒ Cannot be changed via reflection (will throw IllegalAccessException) • Native methods now explicitly prohibited ‒ Could introduce behaviour dependent on external state
Records (Second Preview) 123 • Local records ‒ Like a local class ‒ Implicitly static List<Seller> findTopSellers(List<Seller> sellers, int month) { // Local record record Sales(Seller seller, double sales) {} return sellers.stream() .map(seller -> new Sales(seller, salesInMonth(seller, month))) .sorted((s1, s2) -> Double.compare(s2.sales(), s1.sales())) .map(Sales::seller) .collect(toList()); }
Records (Second Preview) 124 • Records work with sealed classes (interfaces) public sealed interface Car permits RedCar, BlueCar { ... } public record RedCar(int w) implements Car { ... } public record BlueCar(long w, int c) implements Car { ... }
JDK 16
Pattern Matching instanceof (JEP 394) 126 • Now final, i.e. part of the Java SE specification • Two minor changes to previous iterations ‒ Pattern variables are no longer implicitly final ‒ Compile-time error to compare an expression of type S against a pattern of type T where S is a sub-type of T  if (x instanceof Object o) …  It will always succeed and so is pointless
Records (JEP 395) 127 • Records now final, i.e., part of the Java SE specification • Record fields are (really) final ‒ Cannot be changed via reflection (will throw IllegalAccessException) • Native methods explicitly prohibited ‒ Could introduce behaviour dependent on external state • Inner classes can now declare explicit/implicit static members ‒ Allows an inner class to declare a member that is a Record class
Add UNIX-Domain Socket Channels 128 • Add UNIX_AF socket channels ‒ Used for IPC on UNIX-based OSs and Windows • Better security and performance than TCP/IP loopback connections ‒ Behaviour is identical • No constructor, use factory methods var unix = UnixDomainSocketAddress.of("/tmp/foo");
Streams mapMulti 129 • Similar to flatMap ‒ Each element on the input stream is mapped to zero or more elements on the output stream ‒ Difference is that a mapping can be applied at the same time ‒ Uses a BiConsumer • 1 to (0..1) example Stream.of("Java", "Python", "JavaScript", "C#", "Ruby") .mapMulti((str, consumer) -> { if (str.length() > 4) consumer.accept(str.length()); // lengths larger than 4 }) .forEach(i -> System.out.print(i + " ")); // 6 10
Stream mapMulti 130 • 1 to 1 example Stream.of("Java", "Python", "JavaScript", "C#", "Ruby") .mapMulti((str, consumer) -> consumer.accept(str.length())) .forEach(i -> System.out.print(i + " ")); // 4 6 10 2 4
Stream mapMulti 131 • 1 to many example Stream.of("Java", "Python", "JavaScript", "C#", "Ruby", "") .mapMulti((str, consumer) -> { for (int i = 0; i < str.length(); i++) consumer.accept(str.length()); }) .forEach(i -> System.out.print(i + " ")); // 4 4 4 4 6 6 6 6 6 6 10 10 10 10 10 10 10 10 10 10 2 2 4 4 4 4
Vector API (JEP 338) 132 • Incubator module (not part of the Java SE specification) • API to express vector computations ‒ Compile at runtime to optimal hardware instructions ‒ Deliver superior performance to equivalent scalar operations • Ideally, this would not be necessary ‒ Compiler should identify where vector operations can be used
Vector API (JEP 338) 133 void scalarComputation(float[] a, float[] b, float[] c) { for (int i = 0; i < a.length; i++) c[i] = (a[i] * a[i] + b[i] * b[i]) * -1.0f; } static final VectorSpecies<Float> SPECIES = FloatVector.SPECIES_256; void vectorComputation(float[] a, float[] b, float[] c) { for (int i = 0; i < a.length; i += SPECIES.length()) { var m = SPECIES.indexInRange(i, a.length); var va = FloatVector.fromArray(SPECIES, a, i, m); var vb = FloatVector.fromArray(SPECIES, b, i, m); var vc = va.mul(va). add(vb.mul(vb)). neg(); vc.intoArray(c, i, m); } }
Foreign-Memory Access API (JEP 393) 134 • Introduced in JDK 14, now third incubator iteration • API for safe and efficient access to memory outside of the Java heap • MemorySegment ‒ Models a contiguous area of memory • MemoryAddress ‒ Models an individual memory address (on or off heap) • MemoryLayout ‒ Programmatic description of a MemorySegment try (MemorySegment segment = MemorySegment.allocateNative(100)) { for (int i = 0; i < 25; i++) MemoryAccess.setIntAtOffset(segment, i * 4, i); }
Foreign-Memory Access API (JEP 393) 135 • Example using MemoryLayout and VarHandle ‒ Simpler access of structured data SequenceLayout intArrayLayout = MemoryLayout.ofSequence(25, MemoryLayout.ofValueBits(32, ByteOrder.nativeOrder())); VarHandle indexedElementHandle = intArrayLayout.varHandle(int.class, PathElement.sequenceElement()); try (MemorySegment segment = MemorySegment.allocateNative(intArrayLayout)) { for (int i = 0; i < intArrayLayout.elementCount().getAsLong(); i++) indexedElementHandle.set(segment, (long) i, i); }
Foreign Linker API (JEP 389): Incubator 136 • Provides statically-typed, pure-Java access to native code ‒ Works in conjunction with the Foreign Memory Access API ‒ Initially targeted at C native code. C++ should follow • More powerful when combined with Project Panama jextract command public static void main(String[] args) throws Throwable { var linker = CLinker.getInstance(); var lookup = LibraryLookup.ofDefault(); // get a native method handle for 'getpid' function var getpid = linker.downcallHandle(lookup.lookup("getpid").get(), MethodType.methodType(int.class), FunctionDescriptor.of(CLinker.C_INT)); System.out.println((int)getpid.invokeExact()); }
Warnings for Value-Based Classes 137 • Part of Project Valhalla, which adds value-types to Java ‒ Introduces the concept of primitive classes • Primitive wrapper classes (Integer, Float, etc.) designated value-based ‒ Constructors were deprecated in JDK 9 ‒ Now marked as for removal ‒ Attempting to synchronize on an instance of a value-based class will issue a warning
Summary
Zulu Enterprise 139 • Enhanced build of OpenJDK source code  Fully TCK tested  JDK 6, 7, 8, 11 and 13  TLS1.3, Flight Recorder backports for Zulu 8 • Wide platform support:  Intel 64-bit Windows, Mac, Linux  Intel 32-bit Windows and Linux • Real drop-in replacement for Oracle JDK  Many enterprise customers  No reports of any compatibility issues
Zulu Extended Support 140 • Backporting of bug fixes and security patches from supported OpenJDK release • Zulu 8 supported until December 2030 • LTS releases have 9 years active + 2 years passive support • JDK 15 is a Medium Term Support release ‒ Bridge to next LTS release (JDK 17) ‒ Supported until 18 months after JDK 17 release
Conclusions 141 • The six-month release cycle is working well • Not all releases will have lots of new features • Use Zulu builds of OpenJDK if you want to deploy to production • Java continues to evolve!
THANK YOU

Modern Java Workshop

  • 1.
    From JDK 9to 16 New Java Workshop Presented by Simon Ritter, Deputy CTO | Azul Systems Inc.
  • 2.
    Introduction 2 •Six-month release cadence •Sevenreleases since JDK 9 •More features being delivered faster than ever before Java has changed… …a lot
  • 3.
    Incubator Modules 3 • Definedby JEP 11 • Non-final APIs and non-final tools ‒ Deliver to developers to solicit feedback ‒ Can result in changes or even removal ‒ First example: HTTP/2 API (Introduced in JDK 9, final in JDK 11)
  • 4.
    Preview Features 4 • Definedby JEP 12 • New feature of the Java language, JVM or Java SE APIs ‒ Fully specified, fully implemented but not permanent ‒ Solicit developer real-world use and experience ‒ May lead to becoming a permanent feature in future release • Must be explicitly enabled ‒ javac --release 14 --enable-preview ... ‒ java --enable-preview ... • Preview APIs ‒ May be required for a preview language feature ‒ Part of the Java SE API (java or javax namespace)
  • 5.
  • 6.
  • 7.
    Why Do WeNeed Modularity in Java? 7 • JDK 1.0 ‒ 122 library classes for simplifying application development • JDK 8.0 ‒ Over 4,500 public classes in the rt.jar file • JDK 9 ‒ 27 Java SE modules, 48 JDK modules • Two sides to modularity: 1. JDK core libraries 2. Application code
  • 8.
    Module Fundamentals 8 • Moduleis a grouping of code ‒ For Java this is a collection of packages • Modules can contain other things ‒ Native code ‒ Resources ‒ Configuration data com.azul.zoop com.azul.zoop.alpha.Name com.azul.zoop.alpha.Position com.azul.zoop.beta.Animal com.azul.zoop.beta.Reptile com.azul.zoop.theta.Zoo com.azul.zoop.theta.Lake
  • 9.
    Module Declaration module com.azul.zoop{} module-info.java com/azul/zoop/alpha/Name.java com/azul/zoop/alpha/Position.java com/azul/zoop/beta/Animal.java com/azul/zoop/beta/Reptile.java com/azul/zoop/theta/Zoo.java com/azul/zoop/theta/Lake.java
  • 10.
    Module Dependencies module com.azul.zoop{ requires com.azul.zeta; } com.azul.zoop com.azul.zeta
  • 11.
    Module Dependencies module com.azul.zapp{ requires com.azul.zoop; requires java.sql; } com.azul.zapp com.azul.zoop java.sql
  • 12.
  • 13.
    Module Dependency Graph 13 •No missing dependencies • No cyclic dependencies • No split packages
  • 14.
    Readability v. Dependency com.azul.zapp java.sql java.logging modulejava.sql { requires transitive java.logging; } Driver d = … Logger l = d.getParentLogger(); l.log(“azul’); Implied readability
  • 15.
    Module Implied ReadabilityGraph com.azul.zapp java.base java.sql com.azul.zoop com.azul.zeta java.xml java.logging explicit implicit implied
  • 16.
    Package Visibility module com.azul.zoop{ requires com.azul.zeta; exports com.azul.zoop.alpha; exports com.azul.zoop.beta to com.azul.zapp; } com.azul.zoop com.azul.zoop.alpha com.azul.zoop.beta com.azul.zoop.theta com.azul.zapp only
  • 17.
    More Package Visibility openmodule com.azul.zoop { requires com.azul.zeta; } com.azul.zoop com.azul.zoop.alpha com.azul.zoop.beta com.azul.zoop.theta com.azul.zoop.alpha com.azul.zoop.beta com.azul.zoop.theta REFLECTION IMPORT
  • 18.
    Even More PackageVisibility module com.azul.zoop { requires com.azul.zeta; exports com.azul.zoop.alpha; exports com.azul.zoop.beta to com.azul.zapp; opens com.azul.theta; } com.azul.zoop com.azul.zoop.theta REFLECTION IMPORT com.azul.zoop.alpha com.azul.zoop.beta com.azul.zapp only
  • 19.
    Restricted Keywords module requires requires; exportsexports to to; module { opens opens; }
  • 20.
    Accessibility • For apackage to be visible ‒ The package must be exported by the containing module ‒ The containing module must be read by the using module • Public types from those packages can then be used com.azul.zoop com.azul.zapp reads
  • 21.
  • 22.
    Module Path $ javac–modulepath dir1:dir2:dir3
  • 23.
    Compilation With ModulePath $ javac –-module-path mods –d mods src/module-info.java src/com/azul/zoop/alpha/Name.java mods/module-info.class mods/com/azul/zoop/alpha/Name.class src/module-info.java src/com/azul/zoop/alpha/Name.java
  • 24.
    Application Execution • -pis the abbreviation of --module-path $ java –p mods –m com.azul.zapp/com.azul.zapp.Main Azul application initialised! module name main class
  • 25.
    Packaging With ModularJAR Files mods/module-info.class mods/com/azul/zapp/Main.class $ jar --create --file=mylib/zapp.jar --main-class=com.azul.zapp.Main -C mods . module-info.class com/azul/zapp/Main.class zapp.jar
  • 26.
    Application Execution (JAR) $java –p mylib:mods –m com.azul.zapp Azul application initialised!
  • 27.
    Linking Modular run-time image … conf bin jlink $ jlink--module-path $JDKMODS --add-modules java.base –-output myimage $ myimage/bin/java –-list-modules java.base@9.0
  • 28.
    Linking An Application $jlink --module-path $JDKMODS:$MYMODS --add-modules com.azul.zapp –-output myimage $ myimage/bin/java –-list-modules java.base@9 java.logging@9 java.sql@9 java.xml@9 com.azul.zapp@1.0 com.azul.zoop@1.0 com.azul.zeta@1.0
  • 29.
    The Implications Ofjlink • "Write once, run anywhere"  Long term Java slogan, mainly held true • jlink generated runtime may not include all Java SE modules ‒ But is still a conforming Java implementation ‒ To conform to the specification, the runtime:  Must include the java.base module  If other modules are included, all transitive module dependencies must also be included  Defined as a closed implementation
  • 30.
  • 31.
    Typical Application (JDK8) jar jar jar JDK jar jar jar jar jar jar jar jar jar Classpath
  • 32.
    Typical Application (JDK9) jar jar jar module java.base module java.desktop module java.datatransfer module java.xml jar jar jar jar jar jar jar jar jar Unnamed module
  • 33.
  • 34.
    Run Application WithClasspath $ java –classpath lib/myapp.jar: lib/mylib.jar: lib/libgl.jar: lib/gluegen.jar: lib/jogl.jar: myapp.Main
  • 35.
  • 36.
    Application module-info.java module myapp{ requires mylib; requires java.base; requires java.sql; requires libgl; ???? requires gluegen; ???? requires jogl; ???? }
  • 37.
  • 38.
    Automatic Modules 38 • Realmodules • Simply place unmodified jar file on module path ‒ Rather than classpath • No changes to JAR file • Module name derived from JAR file name • Exports all its packages ‒ No selectivity • Automatically requires all modules on the module path
  • 39.
  • 40.
    Run Application WithModules $ java –classpath lib/myapp.jar: lib/mylib.jar: lib/libgl.jar: lib/gluegen.jar: lib/jogl.jar: myapp.Main $ java –p mylib:lib –m myapp
  • 41.
    Migrating Applications ToThe Java Platform Module System
  • 42.
    Migration Guidance FromOracle "Clean applications that just depend on java.se should just work"
  • 43.
    Migrating Applications toJPMS 43 • Initially, leave everything on the classpath • Anything on the classpath is in the unnamed module ‒ All packages are exported ‒ The unnamed module depends on all modules • Migrate to modules as required ‒ Try automatic modules ‒ Move existing jar files from classpath to modulepath
  • 44.
    Classpath v Modulepath classpath modulepath Unnamedmodule jar jar jar module-info.class jar module-info.class jar Automatic module module-info.class
  • 45.
    Reversing Encapsulation • "TheBig Kill Switch" --illegal-access • Four options: ‒ permit (current default) ‒ warn ‒ debug ‒ deny (JDK 16 default)
  • 46.
    Reversing Encapsulation • Bigkill switch overrides encapsulation ‒ From the unnamed module (i.e. classpath) ‒ Allows unlimited refective access to named modules  Not from named modules • Warning messages written to error stream • Useful to understand use of --add-exports and --add-opens when migrating to named modules
  • 47.
    Reversing Encapsulation 47 • Allowingdirect access to encapsulated APIs ‒ --add-exports • Allowing reflective access to encapsulated APIs ‒ --add-opens --add-exports java.management/com.sun.jmx.remote.internal=mytest --add-exports java.management/sun.management=ALL-UNNAMED --add-opens java.base/java.util=ALL-UNNAMED
  • 48.
    Finding Dependencies: jdeps >jdeps --module-path /opt/javafx-sdk-11/lib --add-modules=javafx.controls --list-deps FlightTracker.jar JDK removed internal API/com.sun.media.jfxmediaimpl.platform.ios java.base java.datatransfer java.desktop/java.awt.dnd.peer java.desktop/sun.awt java.desktop/sun.awt.dnd java.desktop/sun.swing java.logging java.scripting java.sql java.xml jdk.jsobject jdk.unsupported jdk.unsupported.desktop jdk.xml.dom
  • 49.
  • 50.
    Java Storage Basics 50 •Fields (instance and static) ‒ Part of an object, exist for the lifetime of an object ‒ Initialisation guaranteed by compiler • Local variables ‒ Scoped to region of code (method, statement, block) ‒ Initialisation not guaranteed ‒ Cheap when allocated on the stack ‒ Name and use is often more important than the type
  • 51.
    Local Variable TypeInference • Why? ‒ JavaScript has it so it must be good ‒ Streams hide intermediate types ‒ Why not expand this elsewhere? ‒ var can make code more concise  Without sacrificing readability List l = names.stream() // Stream<String> .filter(s -> s.length() > 0) // Stream<String> .map(s -> getRecord(s)) // Stream<Record> .collect(toList()); // ArrayList<Record>
  • 52.
    Simple Uses ofLocal Variables ArrayList<String> nameList = new ArrayList<String>(); List<String> userList = new ArrayList<>(); Stream<String> stream = userList.stream(); for (String name : userList) { ... } for (int i = 0; i < 10; i++) { ... }
  • 53.
    Simple Uses ofLocal Variable Type Inference var userList = new ArrayList<String>(); // Infers ArrayList<String> var stream = userList.stream(); // Infers Stream<String> for (var name : userList) { // Infers String ... } for (var i = 0; i < 10; i++) { // Infers int ... }
  • 54.
    Simple Uses ofvar • Clearer try-with-resources try (InputStream inputStream = socket.getInputStream(); InputStreamReader inputStreamReader = new InputStreamReader(inputStream, UTF_8); BufferedReader bufferedReader = new BufferedReader(inputStreamReader)) { // Use bufferedReader }
  • 55.
    Simple Uses ofvar • Clearer try-with-resources try (var inputStream = socket.getInputStream(); var inputStreamReader = new inputStreamReader(inputStream, UTF_8); var bufferedReader = new BufferedReader(inputStreamReader)) { // Use bufferedReader }
  • 56.
    More Typing WithLess Typing • Java is still statically typed var name = "Simon"; // Infers String, so name is String name = "Dylan"; // Still String name = 42; // Not a String error: incompatible types: int cannot be converted to String
  • 57.
    Final and Non-Final 57 •var simply indicates the compiler infers the type • Use of var does not make a variable final • Still need final • No shortcut for final var (like val) ‒ How often do you make local-variables final? var name = "Simon"; name = "Dylan"; // name is not final final var name = "Simon";
  • 58.
    Action At ADistance var l = new ArrayList<String>(); var s = l.stream(); // Lots of lines of complex code var n = l.get(0); // Err, what is n?
  • 59.
    Not Everything CanBe Inferred int[] firstSixPrimes = {2, 3, 5, 7, 11, 13}; var firstSixPrimes = {2, 3, 5, 7, 11, 13}; error: cannot infer type for local variable firstSixPrimes var firstSixPrimes = {2, 3, 5, 7, 11, 13}; ^ (array initializer needs an explicit target-type) var firstSixPrimes = new int[]{2, 3, 5, 7, 11, 13}; var firstTwoPrimes = new Integer[]{2, 3};
  • 60.
    Types Required OnBoth Sides var list = null; error: cannot infer type for local variable list var list = null; ^ (variable initializer is 'null')
  • 61.
    Types Required OnBoth Sides var list; list = new ArrayList<String>(); error: cannot infer type for local variable list var list; ^ (cannot use 'var' on variable without initializer)
  • 62.
    No Multiple VariableDeclaration 62 var a, b = 1; error: 'var' is not allowed in a compound declaration
  • 63.
    Literals with var(Good) • Original ‒ boolean ready = true; ‒ char ch = 'x'; ‒ long sum = 0L; ‒ String label = "Foo";
  • 64.
    Literals with var(Good) • With var ‒ var ready = true; ‒ var ch = 'x'; ‒ var sum = 0L; ‒ var label = "Foo";
  • 65.
    Literals with var(Dangerous) • Original ‒ byte flags = 0; ‒ short mask = 0x7fff; ‒ long base = 10;
  • 66.
    Literals with var(Dangerous) • Original ‒ var flags = 0; ‒ var mask = 0x7fff; ‒ var base = 10; All these cases will infer int
  • 67.
    Beware of MultipleType Inference var itemQueue = new PriorityQueue<>(); Diamond operator, primary type inference Secondary type inference itemQueue infered as PriorityQueue<Object>(); PriorityQueue<Integer> itemQueue = new PriorityQueue<>();
  • 68.
    Programming To AnInterface • Common to use interface rather than concrete type • Using var always infers concrete type • Polymorphism still works ‒ArrayList<String> is still a List ‒You can use myList wherever a List is required List<String> myList = new ArrayList<>(); var myList = new ArrayList<String>();
  • 69.
    Lambdas and var Predicate<String>blankLine = s -> s.isBlank(); var blankLine = s -> s.isBlank(); error: cannot infer type for local variable blankLine var blankLine = s -> s.isBlank(); ^ (lambda expression needs an explicit target-type)
  • 70.
    Intersection Types <T extendsCloseable & Iterable<E>> T getData() { // Return something that implements both // Closeable and Iterable<E> } Valid Java syntax
  • 71.
    Intersection Types • Theproblem <E> Optional<E> firstMatch(Predicate<? super E> condition) { XXX elements = getData(); try (elements) { return StreamSupport.stream(elements.spliterator(), false) .filter(condition) .findAny(); } } elements must implement Closeable elements must implement Iterable<E> XXX is Closeable & Iterable<E>, which won't compile
  • 72.
    Intersection Types • Thesolution: var <E> Optional<E> firstMatch(Predicate<? super E> condition) { var elements = getData(); try (elements) {` return StreamSupport.stream(elements.spliterator(), false) .filter(condition) .findAny(); } } Compiler infers a valid type that is impossible to express with Java syntax
  • 73.
    Inner Classes 73 • Thiscode won't compile Object fruit = new Object() { String name = "apple"; String inFrench() { return "pomme"; } }; System.out.println("Fruit = " + fruit.name); System.out.println("In French = " + fruit.inFrench());
  • 74.
    Inner Classes 74 • Usingvar this will compile and run ‒ The key is non-denotable types var fruit = new Object() { String name = "apple"; String inFrench() { return "pomme"; } }; System.out.println("Fruit = " + fruit.name); System.out.println("In French = " + fruit.inFrench());
  • 75.
    var: Reserved Type(Not Keyword) var var = new Var(); public class var { public var(String x) { ... } } public class Var { public Var(String x) { ... } }
  • 76.
    Puzzler 1 static booleancalc1(int mask) { long temp = 0x12345678; return (((temp << 6) | temp) & mask) > 0; }
  • 77.
    Puzzler 1 • Shouldwe use var? Yes? No? static boolean calc1(int mask) { var temp = 0x12345678; return (((temp << 6) | temp) & mask) > 0; }
  • 78.
    Puzzler 1 • 0x12345678fits in an int ‒ Using var will infer an int, not a long • Passing a mask < 0 will give different results ‒ Using long, mask < 0 returns true ‒ Using var (infer int), mask < 0 returns false
  • 79.
    Puzzler 2 static List<String>create1(boolean foo, boolean bar) { List<String> list = new ArrayList<>(); if (foo) list.add("foo"); if (bar) list.add("bar"); return list; }
  • 80.
    Puzzler 2 • Shouldwe use var? Yes? No? static List<String> create1(boolean foo, boolean bar) { var list = new ArrayList<>(); if (foo) list.add("foo"); if (bar) list.add("bar"); return list; }
  • 81.
    Puzzler 2 • Remember,"Beware of multiple type inference" ‒ var list = new ArrayList<>(); ‒ Diamond operator infers Object error: incompatible types: ArrayList<Object> cannot be converted to List<String> return list;
  • 82.
    Puzzler 3 • Gooduse of var? Yes? No? static List<Integer> listRemoval() { List<Integer> list = new ArrayList<>(Arrays.asList(1, 3, 5, 7, 9)); var v = valueToRemove(); list.remove(v); return list; } // Separate class, package or module (in a galaxy far, far away) static Integer valueToRemove() { return 3; }
  • 83.
    Puzzler 3 • Newintern arrives and changes code... • Unexpected change in behaviour static int valueToRemove() { return 3; } List.remove(int) // Remove element at given index List.remove(Object) // Remove first instance of object {1,3,7,9} // Using var with changed valueToRemove {1,5,7,9} // Using var with unchanged valueToRemove
  • 84.
    Guidelines For Useof var 84 1. Reading code is more important that writing it 2. Code should be clear from local reasoning 3. Code readability shouldn't depend on an IDE 4. Choose variable names that provide useful information 5. Minimise the scope of local variables 6. Consider var when the initialiser provides sufficient information 7. Use var to break up chained or nested expressions 8. Take care when using var with generics 9. Take care when using var with literals
  • 85.
  • 86.
    JDK 11: ExtendLocal-Variable Syntax • Lambda parameters list.stream() .map(s -> s.toLowerCase()) .collect(Collectors.toList()); list.stream() .map((var s) -> s.toLowerCase()) .collect(Collectors.toList()); list.stream() .map((@Notnull var s) -> s.toLowerCase()) .collect(Collectors.toList());
  • 87.
    New APIs 87 • NewI/O methods  InputStream nullInputStream()  OutputStream nullOutputStream()  Reader nullReader()  Writer nullWriter() • Optional  isEmpty() // Opposite of isPresent
  • 88.
    New APIs 88 • NewString methods ‒ isBlank() ‒ Stream lines() ‒ String repeat(int) ‒ String strip() ‒ String stripLeading() ‒ String stripTrailing()
  • 89.
    New APIs 89 • Predicatenot(Predicate) lines.stream() .filter(s -> !s.isBlank()) lines.stream() .filter(Predicate.not(String::isBlank)) lines.stream() .filter(not(String::isBlank))
  • 90.
    Missing Modules 90 • Remember,"Clean applications that only use java.se..." • The java.se.ee aggregator module removed in JDK 11 • Affected modules ‒ java.corba ‒ java.transaction ‒ java.activation ‒ java.xml.bind ‒ java.xml.ws ‒ java.xml.ws.annotation
  • 91.
    Resolving Missing Modules 91 •All modules (except CORBA) have standalone versions ‒ Maven central ‒ Relevant JSR RI • Deploy standalone version on the upgrade module path ‒ --upgrade-module-path <path> • Deploy standalone version on the classpath
  • 92.
  • 93.
    Switch Expressions (Preview) 93 •Switch construct was a statement ‒ No concept of generating a result that could be assigned • Rather clunky syntax ‒ Every case statement needs to be separated ‒ Must remember break (default is to fall through) ‒ Scope of local variables is not intuitive
  • 94.
    Old-Style Switch Statement 94 intnumberOfLetters; switch (day) { case MONDAY: case FRIDAY: case SUNDAY: numberOfLetters = 6; break; case TUESDAY: numberOfLetters = 7; break; case THURSDAY: case SATURDAY: numberOfLetters = 8; break; case WEDNESDAY: numberOfLetters = 9; break; default: throw new IllegalStateException("Huh?: " + day); };
  • 95.
    New-Style Switch Expression intnumberOfLetters = switch (day) { case MONDAY, FRIDAY, SUNDAY -> 6; case TUESDAY -> 7; case THURSDAY, SATURDAY -> 8; case WEDNESDAY -> 9; default -> throw new IllegalStateException("Huh?: " + day); };
  • 96.
    New Old-Style SwitchExpression int numberOfLetters = switch (day) { case MONDAY: case FRIDAY: case SUNDAY: break 6; case TUESDAY break 7; case THURSDAY case SATURDAY break 8; case WEDNESDAY break 9; default: throw new IllegalStateException("Huh?: " + day); };
  • 97.
    New Old-Style SwitchExpression outside: for (day : dayList) int numberOfLetters = switch (day) { case MONDAY: case FRIDAY: case SUNDAY: break 6; case TUESDAY break 7; case THURSDAY case SATURDAY break 8; case WEDNESDAY break 9; default: continue outside; }; Illegal jump through switch expression
  • 98.
    Streams • New collector,teeing ‒ teeing(Collector, Collector, BiFunction) • Collect a stream using two collectors • Use a BiFunction to merge the two collections 98 Collector 1 Collector 2 BiFunction Stream Result
  • 99.
    Streams 99 // Averaging Double average= Stream.of(1, 4, 5, 2, 1, 7) .collect(teeing(summingDouble(i -> i), counting(), (sum, n) -> sum / n));
  • 100.
  • 101.
    Text Blocks (Preview) StringwebPage = """ <html> <body> <p>My web page</p> </body> </html>"""; System.out.println(webPage); $ java WebPage <html> <body> <p>My web page</p> </body> </html> $ incidental white space
  • 102.
    Text Blocks (Preview) StringwebPage = """ <html> <body> <p>My web page</p> </body> </html> """; System.out.println(webPage); $ java WebPage <html> <body> <p>My web page</p> </body> </html> $ Additional blank line incidental white space Intentional indentation
  • 103.
    Switch Expression int numberOfLetters= switch (day) { case MONDAY: case FRIDAY: case SUNDAY: break 6; case TUESDAY break 7; case THURSDAY case SATURDAY break 8; case WEDNESDAY break 9; default: throw new IllegalStateException("Huh?: " + day); };
  • 104.
    Switch Expression int numberOfLetters= switch (day) { case MONDAY: case FRIDAY: case SUNDAY: yield 6; case TUESDAY yield 7; case THURSDAY case SATURDAY yield 8; case WEDNESDAY yield 9; default: throw new IllegalStateException("Huh?: " + day); };
  • 105.
  • 106.
    Simple Java DataClass 106 class Point { private final double x; private final double y; public Point(double x, double y) { this.x = x; this.y = y; } public double x() { return x; } public double y() { return y; } }
  • 107.
    Records (Preview) 107 record Point(doublex, double y) { } record Range(int low, int high) { public Range { // Compact constructor if (low > high) throw new IllegalArgumentException("Bad values"); } }
  • 108.
    Record Additional Details 108 •Compact constructor can only throw unchecked exception ‒ Syntax does not allow for specifying a checked exception • Object methods equals(), hashCode() and toString() can be overridden • The base class of all records is java.lang.Record ‒ This is an example of a preview feature Java SE API ‒ Records cannot sub-class (but may implement interfaces) • Records do not follow the Java bean pattern ‒ x() not getX() in previous example • Instance fields cannot be added to a record ‒ Static fields can • Records can be generic
  • 109.
    Using instanceof 109 if (objinstanceof String) { String s = (String)obj; System.out.println(s.length()); }
  • 110.
    Pattern Matching instanceof(Preview) 110 if (obj instanceof String s) System.out.println(s.length()); else // Use of s not allowed here if (obj instanceof String s && s.length() > 0) System.out.println(s.length()); // Compiler error if (obj instanceof String s || s.length() > 0) System.out.println(s.length());
  • 111.
    Pattern Matching instanceof(Preview) 111 if (!(o instanceof String s && s.length() > 3) return; System.out.println(s.length());
  • 112.
    Pattern Matching instanceof 112 •Be careful of scope! class BadPattern { String s = "One"; void testMyObject(Object o) { if (o instanceof String s) { System.out.println(s); // Prints contents of o s = s + " Two"; // Modifies pattern variable } System.out.println(s); // Prints "One" } }
  • 113.
    Text Blocks • Secondpreview • Two new escape sequences String continuous = """This line will not contain a newline in the middle and solves the extra blank line issue """; String endSpace = """This line will not s lose the trailing spaces s""";
  • 114.
    Helpful NullPointerException 114 • Who'snever had an NullPointerException? • Enabled with -XX:+ShowCodeDetailsInExceptionMessages a.b.c.i = 99; Exception in thread "main" java.lang.NullPointerException at Prog.main(Prog.java:5) Exception in thread "main" java.lang.NullPointerException: Cannot read field "c" because "a.b" is null at Prog.main(Prog.java:5)
  • 115.
  • 116.
    Java Inheritance 116 • Aclass (or interface) in Java can be sub-classed by any class ‒ Unless it is marked as final Shape Triangle Square Pentagon
  • 117.
    Sealed Classes (JEP360) 117 • Preview feature • Sealed classes allow control over which classes can sub-class a class ‒ Think of final as the ultimate sealed class • Although called sealed classes, this also applies to interfaces
  • 118.
    Sealed Classes (JEP360) 118 • Uses contextual keywords ‒ New idea replacing restricted identifiers and keywords ‒ sealed, permits and non-sealed • Classes must all be in the same package or module public sealed class Shape permits Triangle, Square, Pentagon { ... } Shape Triangle Square Pentagon Circle X
  • 119.
    Sealed Classes (JEP360) 119 • All sub-classes must have inheritance capabilities explicitly specified // Restrict sub-classes to defined set public sealed class Triangle permits Equilateral, Isosoles extends Shape { ... } // Prevent any further sub-classing public final class Square extends Shape { ... } // Allow any classes to sub-class this one (open) public non-sealed class Pentagon extends Shape { ... }
  • 120.
    Contextual Keyword Humour 120 intnon = 2; int sealed = 1; var var = non-sealed;
  • 121.
    Hidden Classes (JEP371) 121 • JVM rather than language-level feature • Classes that cannot be used directly by the bytecodes of other classes • Several situations where bytecodes generated at runtime ‒ Use of invokedynamic bytecode ‒ Lambdas are a good example ‒ Mostly bound to static class (not for use elsewhere) ‒ Often only used for short time • Hidden classes can only be accessed via reflection ‒ Primarily intended for framework developers
  • 122.
    Records (Second Preview) 122 •Record fields are now (really) final ‒ Cannot be changed via reflection (will throw IllegalAccessException) • Native methods now explicitly prohibited ‒ Could introduce behaviour dependent on external state
  • 123.
    Records (Second Preview) 123 •Local records ‒ Like a local class ‒ Implicitly static List<Seller> findTopSellers(List<Seller> sellers, int month) { // Local record record Sales(Seller seller, double sales) {} return sellers.stream() .map(seller -> new Sales(seller, salesInMonth(seller, month))) .sorted((s1, s2) -> Double.compare(s2.sales(), s1.sales())) .map(Sales::seller) .collect(toList()); }
  • 124.
    Records (Second Preview) 124 •Records work with sealed classes (interfaces) public sealed interface Car permits RedCar, BlueCar { ... } public record RedCar(int w) implements Car { ... } public record BlueCar(long w, int c) implements Car { ... }
  • 125.
  • 126.
    Pattern Matching instanceof(JEP 394) 126 • Now final, i.e. part of the Java SE specification • Two minor changes to previous iterations ‒ Pattern variables are no longer implicitly final ‒ Compile-time error to compare an expression of type S against a pattern of type T where S is a sub-type of T  if (x instanceof Object o) …  It will always succeed and so is pointless
  • 127.
    Records (JEP 395) 127 •Records now final, i.e., part of the Java SE specification • Record fields are (really) final ‒ Cannot be changed via reflection (will throw IllegalAccessException) • Native methods explicitly prohibited ‒ Could introduce behaviour dependent on external state • Inner classes can now declare explicit/implicit static members ‒ Allows an inner class to declare a member that is a Record class
  • 128.
    Add UNIX-Domain SocketChannels 128 • Add UNIX_AF socket channels ‒ Used for IPC on UNIX-based OSs and Windows • Better security and performance than TCP/IP loopback connections ‒ Behaviour is identical • No constructor, use factory methods var unix = UnixDomainSocketAddress.of("/tmp/foo");
  • 129.
    Streams mapMulti 129 • Similarto flatMap ‒ Each element on the input stream is mapped to zero or more elements on the output stream ‒ Difference is that a mapping can be applied at the same time ‒ Uses a BiConsumer • 1 to (0..1) example Stream.of("Java", "Python", "JavaScript", "C#", "Ruby") .mapMulti((str, consumer) -> { if (str.length() > 4) consumer.accept(str.length()); // lengths larger than 4 }) .forEach(i -> System.out.print(i + " ")); // 6 10
  • 130.
    Stream mapMulti 130 • 1to 1 example Stream.of("Java", "Python", "JavaScript", "C#", "Ruby") .mapMulti((str, consumer) -> consumer.accept(str.length())) .forEach(i -> System.out.print(i + " ")); // 4 6 10 2 4
  • 131.
    Stream mapMulti 131 • 1to many example Stream.of("Java", "Python", "JavaScript", "C#", "Ruby", "") .mapMulti((str, consumer) -> { for (int i = 0; i < str.length(); i++) consumer.accept(str.length()); }) .forEach(i -> System.out.print(i + " ")); // 4 4 4 4 6 6 6 6 6 6 10 10 10 10 10 10 10 10 10 10 2 2 4 4 4 4
  • 132.
    Vector API (JEP338) 132 • Incubator module (not part of the Java SE specification) • API to express vector computations ‒ Compile at runtime to optimal hardware instructions ‒ Deliver superior performance to equivalent scalar operations • Ideally, this would not be necessary ‒ Compiler should identify where vector operations can be used
  • 133.
    Vector API (JEP338) 133 void scalarComputation(float[] a, float[] b, float[] c) { for (int i = 0; i < a.length; i++) c[i] = (a[i] * a[i] + b[i] * b[i]) * -1.0f; } static final VectorSpecies<Float> SPECIES = FloatVector.SPECIES_256; void vectorComputation(float[] a, float[] b, float[] c) { for (int i = 0; i < a.length; i += SPECIES.length()) { var m = SPECIES.indexInRange(i, a.length); var va = FloatVector.fromArray(SPECIES, a, i, m); var vb = FloatVector.fromArray(SPECIES, b, i, m); var vc = va.mul(va). add(vb.mul(vb)). neg(); vc.intoArray(c, i, m); } }
  • 134.
    Foreign-Memory Access API(JEP 393) 134 • Introduced in JDK 14, now third incubator iteration • API for safe and efficient access to memory outside of the Java heap • MemorySegment ‒ Models a contiguous area of memory • MemoryAddress ‒ Models an individual memory address (on or off heap) • MemoryLayout ‒ Programmatic description of a MemorySegment try (MemorySegment segment = MemorySegment.allocateNative(100)) { for (int i = 0; i < 25; i++) MemoryAccess.setIntAtOffset(segment, i * 4, i); }
  • 135.
    Foreign-Memory Access API(JEP 393) 135 • Example using MemoryLayout and VarHandle ‒ Simpler access of structured data SequenceLayout intArrayLayout = MemoryLayout.ofSequence(25, MemoryLayout.ofValueBits(32, ByteOrder.nativeOrder())); VarHandle indexedElementHandle = intArrayLayout.varHandle(int.class, PathElement.sequenceElement()); try (MemorySegment segment = MemorySegment.allocateNative(intArrayLayout)) { for (int i = 0; i < intArrayLayout.elementCount().getAsLong(); i++) indexedElementHandle.set(segment, (long) i, i); }
  • 136.
    Foreign Linker API(JEP 389): Incubator 136 • Provides statically-typed, pure-Java access to native code ‒ Works in conjunction with the Foreign Memory Access API ‒ Initially targeted at C native code. C++ should follow • More powerful when combined with Project Panama jextract command public static void main(String[] args) throws Throwable { var linker = CLinker.getInstance(); var lookup = LibraryLookup.ofDefault(); // get a native method handle for 'getpid' function var getpid = linker.downcallHandle(lookup.lookup("getpid").get(), MethodType.methodType(int.class), FunctionDescriptor.of(CLinker.C_INT)); System.out.println((int)getpid.invokeExact()); }
  • 137.
    Warnings for Value-BasedClasses 137 • Part of Project Valhalla, which adds value-types to Java ‒ Introduces the concept of primitive classes • Primitive wrapper classes (Integer, Float, etc.) designated value-based ‒ Constructors were deprecated in JDK 9 ‒ Now marked as for removal ‒ Attempting to synchronize on an instance of a value-based class will issue a warning
  • 138.
  • 139.
    Zulu Enterprise 139 • Enhancedbuild of OpenJDK source code  Fully TCK tested  JDK 6, 7, 8, 11 and 13  TLS1.3, Flight Recorder backports for Zulu 8 • Wide platform support:  Intel 64-bit Windows, Mac, Linux  Intel 32-bit Windows and Linux • Real drop-in replacement for Oracle JDK  Many enterprise customers  No reports of any compatibility issues
  • 140.
    Zulu Extended Support 140 •Backporting of bug fixes and security patches from supported OpenJDK release • Zulu 8 supported until December 2030 • LTS releases have 9 years active + 2 years passive support • JDK 15 is a Medium Term Support release ‒ Bridge to next LTS release (JDK 17) ‒ Supported until 18 months after JDK 17 release
  • 141.
    Conclusions 141 • The six-monthrelease cycle is working well • Not all releases will have lots of new features • Use Zulu builds of OpenJDK if you want to deploy to production • Java continues to evolve!
  • 142.