Mohamed Taman
Chief Solutions Architect, Owner/CEO of SiriusXI, a Java Champion, Oracle ACE, JCP member, Consultant, Speaker, and Author.
Highlights of the latest upgrade of standard Java include primitive classes, sealed classes, records, a vector API, and ports for Windows on ARM64 and Alpine Linux.
@_tamanm
|
|
|
Mohamed Taman
Chief Solutions Architect
CEO @SiriusXI | Java Champion | Oracle ACE | Jakarta EE Ambassador Author | trainer | speaker.
Or by googling 🕵 me
"Mohamed Taman"
@_tamanm
|
|
➥
➥
➥
➥
➥
@_tamanm
|
|
JDK 16 is a feature release backed by just six months of support from Oracle.
JDK 17, due in September, will be a long-term support (LTS) release.
Oracle frames JDK16 as a starting point for migration to JDK 17, with users able to test on JDK 16 before deploying to JDK17.
- LTS releases are published every two years.
Check out Java's important features!
➥
@_tamanm
|
|
@_tamanm
|
|
Preview Feature.
Incubator Modules.
Deprecation.
Features Marked for Removals.
@_tamanm
|
|
@_tamanm
|
|
Since JDK 12
whose design, specification, and implementation are complete, but which would benefit from a period of broad exposure and evaluation before either achieving final and permanent status in the Java SE Platform or else being refined or removed.
@_tamanm
|
|
mohamed_taman:~$ jshell --enable-preview
mohamed_taman -- -bash
When using Jshell:
When using maven:
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>${maven-compiler-plugin.version}</version>
<configuration>
<release>${java.version}</release>
<compilerArgs>
<arg>--enable-preview</arg>
</compilerArgs>
...
</configuration>
</plugin>
mohamed_taman -- -bash
When using IDE:
@_tamanm
|
|
Since JDK 9
For example, the HTTP & WebSocket client module is introduced in Java 9 under incubator module jdk.incubator.httpclient, and in Java 11, it goes to production under module java.net.http.
@_tamanm
|
|
Since JDK 9
Check out Java's important features!
✓
➥
@_tamanm
|
|
@_tamanm
|
|
@_tamanm
|
|
1st Prev JDK 14
Final JDK 16
2nd Prev JDK 15
class Point {
private final int x;
private final int y;
Point(int x, int y) {
this.x = x;
this.y = y;
}
int x() { return x; }
int y() { return y; }
public boolean equals(Object o) {
if (!(o instanceof Point)) return false;
Point other = (Point) o;
return other.x == x && other.y == y;
}
public int hashCode() {
return Objects.hash(x, y);
}
public String toString() {
return String.format("Point[x=%d, y=%d]", x, y);
}
}
@_tamanm
|
|
record Point(int x, int y) { }
By reducing the ceremony of Java by cutting boilerplate code. So the Point class could be re-written as:
Constructors for record classes
record Point(int x, int y){
Point(int x, int y){
if(x == 0 && y == 0)
throw new IllegalArgumentException(String.format("(%d,%d)", x, y));
this.x = x;
this.y = y;
}
}
record Point(int x, int y){
Point{
if(x == 0 && y == 0)
throw new IllegalArgumentException (String.format("(%d,%d)", x, y));
}
}
List<Merchant> findTopMerchants(List<Merchant> merchants, int month) {
// Local record
record MerchantSales(Merchant merchant, double sales) {}
return merchants.stream()
.map(merchant -> new MerchantSales(merchant, computeSales(merchant, month)))
.sorted((m1, m2) -> Double.compare(m2.sales(), m1.sales()))
.map(MerchantSales::merchant)
.collect(toList());
}
Local Record Classes
Continue
@_tamanm
|
|
1st Prev JDK 14
Final JDK 16
2nd Prev JDK 15
public boolean equals(Object o) {
return (o instanceof CaseInsensitiveString) &&
((CaseInsensitiveString) o).s.equalsIgnoreCase(s);
}
public boolean equals(Object o) {
return (o instanceof CaseInsensitiveString cis) &&
cis.s.equalsIgnoreCase(s);
}
public boolean equals(Object o) {
if (!(o instanceof Point))
return false;
Point other = (Point) o;
return x == other.x
&& y == other.y;
}
public boolean equals(Object o) {
return (o instanceof Point other)
&& x == other.x
&& y == other.y;
}
@_tamanm
|
|
1st Prev JDK 17
static String formatter(Object o) {
String formatted = "unknown";
if (o instanceof Integer i) {
formatted = String.format("int %d", i);
} else if (o instanceof Long l) {
formatted = String.format("long %d", l);
} else if (o instanceof Double d) {
formatted = String.format("double %f", d);
} else if (o instanceof String s) {
formatted = String.format("String %s", s);
}
return formatted;
}
static String formatterPatternSwitch(Object o) {
return switch (o) {
case Integer i -> String.format("int %d", i);
case Long l -> String.format("long %d", l);
case Double d -> String.format("double %f", d);
case String s -> String.format("String %s", s);
default -> o.toString();
};
}
@_tamanm
|
|
Continue
We may wish to handle null in the same way as another case label. For example:
static void testFooBar(String s) {
if (s == null) {
System.out.println("oops!");
return;
}
switch (s) {
case "Foo", "Bar" -> System.out.println("Great");
default -> System.out.println("Ok");
}
}
static void testFooBar(String s) {
switch (s) {
case null -> System.out.println("Oops");
case "Foo", "Bar" -> System.out.println("Great");
default -> System.out.println("Ok");
}
}
static void testStringOrNull(Object o) {
switch (o) {
case null, String s -> System.out.println("String: " + s);
}
}
sealed interface S permits A, B, C {}
final class A implements S {}
final class B implements S {}
record C(int i) implements S {} // Implicitly final
static int testSealedCoverage(S s) {
return switch (s) {
case A a -> 1;
case B b -> 2;
case C c -> 3;
};
}
@_tamanm
|
|
1st Prev JDK 15
Final JDK 17
2nd Prev JDK 16
package com.example.geometry;
public abstract sealed class Shape
permits Circle, Rectangle, Square, WeirdShape { ... }
public final class Circle extends Shape { ... }
public sealed class Rectangle extends Shape
permits TransparentRectangle, FilledRectangle { ... }
public final class TransparentRectangle extends Rectangle { ... }
public final class FilledRectangle extends Rectangle { ... }
public final class Square extends Shape { ... }
public non-sealed class WeirdShape extends Shape { ... }
A class is sealed by applying the sealed modifier to its declaration. Then, after any extends and implements clauses, the permits clause specifies the classes permitted to extend the sealed class.
@_tamanm
|
|
1st Prev JDK 15
Final JDK 17
2nd Prev JDK 16
Here is another classic example of a class hierarchy with a known set of subclasses: modeling mathematical expressions.
Sealed classes work well with record classes. Record classes are implicitly final, so a sealed hierarchy of record classes is slightly more concise than the example above:
package com.example.expression;
public sealed interface Expr
permits ConstantExpr, PlusExpr, TimesExpr, NegExpr { ... }
public final class ConstantExpr implements Expr { ... }
public final class PlusExpr implements Expr { ... }
public final class TimesExpr implements Expr { ... }
public final class NegExpr implements Expr { ... }
package com.example.expression;
public sealed interface Expr
permits ConstantExpr, PlusExpr, TimesExpr, NegExpr { ... }
public record ConstantExpr(int i) implements Expr { ... }
public record PlusExpr(Expr a, Expr b) implements Expr { ... }
public record TimesExpr(Expr a, Expr b) implements Expr { ... }
public record NegExpr(Expr e) implements Expr { ... }
Sealing and record classes
The combination of sealed classes and record classes is sometimes referred to as algebraic data types: Record classes allow us to express product types, and sealed classes allow us to express sum types.
@_tamanm
|
|
JDK-8250629
Final JDK 16
Before JDK 16, the javac compiler accepted C-style array declarations in record components. In particular, the compiler had accepted code such as:
This code is no longer acceptable according to the JLS specification for JDK 16:
record R(int i[]) {}
jshell> record R(int i[]) {}
| Error:
| legacy array notation not allowed on record components
| record R(int i[]) {}
| ^
mohamed_taman -- -bash
@_tamanm
|
|
JDK-8250741
Final JDK 16
Before JDK 16, the javac compiler accepted annotations declared as local interfaces. For example, the javac compiler had accepted code such as:
This code is no longer acceptable according to Section [14.3] of the JLS 16: "A local interface may be a normal interface (§9.1), but not an annotation interface (§9.6)."
class C {
void m() {
@interface A {}
}
}
jshell> class C {
...> void m() {
...> @interface A {}
...> }
...> }
| Error:
| annotation type declaration not allowed here
| @interface A {}
| ^-------------^
mohamed_taman -- -bash
Check out Java's important features!
✓
➥
✓
@_tamanm
|
|
@_tamanm
|
|
@_tamanm
|
|
JDK-8247781
Final JDK 16
[mtaman]:~ ~~ jshell --enable-preview
| Welcome to JShell -- Version 17-ea
| For an introduction type: /help intro
jshell> import java.time.format.DateTimeFormatter
jshell> import java.time.LocalTime
jshell> DateTimeFormatter.ofPattern("B").format(LocalTime.now())
$3 ==> "at night"
mohamed_taman -- -bash
The following example translating the day periods, and produces day period text depending on the time of the day and locale:
@_tamanm
|
|
JDK-8180352
Final JDK 16
Since its introduction in Java 8, the Stream API was blamed for its verboseness. For example, performing a simple mapping transformation on a list requires writing as much as:
However, this is not just a simple shortcut. Why?
list.stream().map(fn).collect(Collectors.toList())
list.stream().map(fn).toList()
@_tamanm
|
|
Final JDK 16
jshell> Integer x = new Integer("12")
| Warning:
| Integer(java.lang.String) in java.lang.Integer has been deprecated and marked for removal
| Integer x = new Integer("12");
| ^---------------^
x ==> 12
jshell> Integer x = new Integer(12)
| Warning:
| Integer(int) in java.lang.Integer has been deprecated and marked for removal
| Integer x = new Integer(12);
| ^-------------^
x ==> 12
jshell> Integer x = 12
x ==> 12
mohamed_taman -- -bash
When running on a future Java release in which the migration has occurred:
@_tamanm
|
|
Final JDK 16
To support Unix-domain socket channels, the following API elements have been added:
@_tamanm
|
|
Final JDK 16
@_tamanm
|
|
Final JDK 16
@_tamanm
|
|
JDK 16
@_tamanm
|
|
JDK 16
1st Inc. JDK 14
2nd inc. JDK 15
@_tamanm
|
|
JDK 17
1st Inc. JDK 16
@_tamanm
|
|
Final JDK 16
Check out Java's important features!
✓
➥
✓
✓
@_tamanm
|
|
@_tamanm
|
|
New things come ... and sometimes old things have to go ...
@_tamanm
|
|
Final JDK 17
@_tamanm
|
|
Final JDK 17
@_tamanm
|
|
Final JDK 17
@_tamanm
|
|
Final JDK 16
@_tamanm
|
|
Obsoleted Option |
Unified Logging |
-XX:+TraceClassLoading | -Xlog:class+load=info |
-XX:+TraceClassUnloading | -Xlog:class+unload=info |
-XX:+TraceExceptions | -Xlog:exceptions=info |
Final JDK 16
Check out Java's important features!
✓
➥
✓
✓
✓
@_tamanm
|
|
@_tamanm
|
|
@_tamanm
|
|
Final JDK 16
Supports native packaging formats to give end-users a natural installation experience. These formats include:
- msi and exe on Windows,
- pkg, and dmg on macOS, and
- deb and rpm on Linux.
Suppose you have an application composed of JAR files, all in a directory named lib, and that lib/main.jar contains the main class. Then the command:
[mtaman]:~ ~~ jpackage --name myapp --input lib --main-jar main.jar
mohamed_taman -- -bash
--main-class myapp.Main
--type pkg
@_tamanm
|
|
Final JDK 16
@_tamanm
|
|
Final JDK 16
@_tamanm
|
|
Final JDK 17
Check out Java's important features!
✓
✓
✓
✓
@_tamanm
|
|
✓
@_tamanm
|
|
By Mohamed Taman
Every six months, we have a new Java release. And to be a practical Java engineer, you should know about what is new in your language. This session will sweep the dust over Java SE 16 hidden gems, including new cool language features, compiler changes, library additions, and critical bug fixes. What we’re going to look at here are all reasonably tremendous & they’re handy in your day-to-day work. Let’s take a features tour powered by code about Java 16 and future Java 17 LTS.
Chief Solutions Architect, Owner/CEO of SiriusXI, a Java Champion, Oracle ACE, JCP member, Consultant, Speaker, and Author.