From Java 9


Creative Commons License
This -From Java 9- tutorial is licensed under a Creative Commons Attribution-NonCommercial 4.0 International License
Preamble
https://koor.fr/Java/Tutorial/java_text_blocks_string.wp

This tutorial is about Java features, starting from Java 9. New releases (Java 10, 11, 12, 13, 14, 15…) come with both inter-release compatibility disruption and, as expected, novelties, say: Java 9 (in French), Java 10, Java 11, etc.

Headlines
The big picture: Java 9 key enhancement is the introduction of modules (module keyword) in order to rationalize the stuff present in the Java Virtual Machine (JVM) at execution time. Java 9-based design of an app. then arises from the “module” principle in the sense that developers have to isolate their code in execution-independent components.

Rule(s)

Modules

Rule(s)

Further detail on Java 9 modules here

Immutable collections

Rule(s)

Example From_Java_9.Java.zip 

Mammutidae m0 = new Mammutidae("Macron");
Mammutidae m1 = new Mammutidae("Poutine");
Mammutidae m2 = new Mammutidae("Trump");
// Immutable collections (e.g., a set):
try {
    java.util.Set.of(m1, m2).add(m0); // Poutine and Trump don't want Macron!
} catch (UnsupportedOperationException uoe) {
    System.err.println("In essence, immutable collections do not support changes like additions: " + uoe.toString());
}

Example From_Java_9.Java.zip 

java.util.Set<Integer> primes = new java.util.HashSet<>() { // <- Creation of an anonymous inner class, which extends 'java.util.HashSet'
    { // <- Block initializer
        add(2);
        add(3);
    }
};
try { // Java 10 'copyOf':
    java.util.Set.copyOf(primes).add(4);
} catch (UnsupportedOperationException uoe) {
    System.err.println("In essence, immutable collections do not support changes like additions: " + uoe.toString());
}

Streams improvement

Rule(s)

Example From_Java_9.Java.zip 

java.util.List<Integer> positives = java.util.Arrays.asList(0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12);
java.util.stream.Stream<Integer> stream = positives.stream().filter(p -> p > 1 && java.util.stream.IntStream.rangeClosed(2, (int) Math.sqrt(p)).noneMatch(i -> (p % i == 0)));
System.out.println(stream.takeWhile(p -> !p.equals(7)).collect(java.util.stream.Collectors.toList())); // '[2, 3, 5]' is displayed...
java.util.stream.Stream<Integer> stream_ = positives.stream().filter(p -> p > 1 && java.util.stream.IntStream.rangeClosed(2, (int) Math.sqrt(p)).noneMatch(i -> (p % i == 0)));
System.out.println(stream_.dropWhile(p -> !p.equals(7)).collect(java.util.stream.Collectors.toList())); // '[7, 11]' is displayed...

Rule(s)

Example From_Java_9.Java.zip 

java.util.List<Object> objects = java.util.Arrays.asList(new Object(), null, new Object());
java.util.stream.Stream<Object> stream__ = objects.stream().flatMap(o -> java.util.stream.Stream.ofNullable(o));
System.out.println(stream__.count()); // '2' is displayed...
As strongly typed programming language, Java imposes the typing of objects. Usages are then checked by the compiler in conformance with “announced” types. Contrary to JavaScript or Python, anomalies as potential execution errors are eliminated at compilation time (execution time for JavaScript or Python). Nonetheless, in many cases, “type announcement” creates no added value code. In this scope, type inference is the ability of the compiler to derive the type of an object. From Java 10, the var keyword forces the compiler to establish the type an object on its own.

var keyword (Java 10)

Example (“old” type inference based on diamond-based instantiation)

java.util.Map<Integer, Double> polynomial = new java.util.HashMap<>();
polynomial.put(1, -12.D);
polynomial.put(39, 8.D);

Example

var polynomial = new java.util.HashMap<Double, Double>();
polynomial.put(1, -12.D);
polynomial.put(39, 8.D);

var keyword in conjunction with lambda expression (Java 11)

Rule(s)

Example From_Java_9.Java.zip 

var positives = java.util.Arrays.asList(0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12);
var stream = positives.stream().filter((var p) -> p > 1 && java.util.stream.IntStream.rangeClosed(2, (int) Math.sqrt(p)).noneMatch((var i) -> (p % i == 0)));
var primes = stream.collect(java.util.stream.Collectors.toList());
primes.forEach((var p) -> System.out.print(" " + p)); // '2 3 5 7 11' is displayed...

Rule(s)

Example From_Java_9.Java.zip  (annotation imposes Integer and int as types of lambda expression parameters)

@java.lang.annotation.Target(value = java.lang.annotation.ElementType.PARAMETER)
@interface Must_be_positive {
}
…
var stream = positives.stream().filter((@Must_be_positive Integer p) -> p > 1 && java.util.stream.IntStream.rangeClosed(2, (int) Math.sqrt(p)).noneMatch((@Must_be_positive int i) -> (p % i == 0)));
…
primes.forEach((@Must_be_positive Integer p) -> System.out.print(" " + p)); // '2 3 5 7 11' is displayed...

Example From_Java_9.Java.zip  (using var ejects Integer and int)

…
var stream = positives.stream().filter((@Must_be_positive var p) -> p > 1 && java.util.stream.IntStream.rangeClosed(2, (int) Math.sqrt(p)).noneMatch((@Must_be_positive var i) -> (p % i == 0)));
…
primes.forEach((@Must_be_positive var p) -> System.out.print(" " + p)); // '2 3 5 7 11' is displayed...
Java 12 comes with much flexibility with the use of the historical switchkeyword.

Rule(s)

Example From_Java_9.Java.zip 

enum Direction {
    East, South, West, North
}
…
var my_direction = Direction.East;
var next_direction = switch (my_direction) { // '--enable-preview'
    case East -> /* 'break' disappears! */ Direction.South; 
    case South, North -> /* 'break' disappears and multiple choices! */ Direction.East; 
    default -> my_direction;
};