Java 9 major language and API improvements
Java ⑨ has been released in September 2017 and is the first release starting a new release cycle with a new release every 6 months.
The following content is summarizing the most important changes to the Java API and the Java language introduced with Java 9.
For more complete overview follow the links in the following sections referring to the official Oracle release documents.
In addition, Nicolai Parlog has a quite comprehensive guide to Java 9 in his "Ultimate Guide To Java 9".
Java 9 Language improvements
The following describes selected improvements of the Java language. See the Java 9 release notes.
Try With Resource
FileReader fileReader = new FileReader("Try.txt");
try (FileReader reader = fileReader) {
reader.read();
}
Before Java 9 a variable referencing a resource had to be redeclared (and assigned) in the try
block in order to be automatically closed.
// reader is an effectively final variable
// as it is not assigned after the initial assignment!
FileReader reader = new FileReader("Try.txt");
try (reader) { (1)
reader.read();
}
Variables that are effectively final can be used in a try with resource block (and don’t have to be redeclared).
Private Interface Method
An interface can now have private methods. These can simplify implementing default methods.
interface Hello {
default String sayHello(String firstName, String lastName) {
return formatGreeting(firstName, lastName);
}
default String sayGoodMorning(String firstName, String lastName) {
return formatGreeting(firstName, lastName);
}
private String formatGreeting(String firstName, String lastName) {
return String.format("Hello %s %s", firstName, lastName);
}
}
Java 9 API improvements
The following describes selected improvements of the Java API. See the Java 9 release notes.
Objects
Methods for convenient null
checking have been added to Objects
class.
return Objects.requireNonNullElse(arg1, 0) *
Objects.requireNonNullElse(arg2, 0);
return Objects.requireNonNullElse(arg1, 0) *
Objects.requireNonNullElseGet(arg2, () -> {
throw new IllegalArgumentException();
});
Immutable List Factory
Factory methods have been added to the Collections class for simplifying list creation.
List<Number> empty = new ArrayList<>();
List<Number> unmodifiable = Collections
.unmodifiableList(empty);
List<Number> unmodifiable = List.of();
List<Number> withItems = new ArrayList<>();
List<Number> unmodifiable = Collections
.unmodifiableList(withItems);
withItems.add(1);
withItems.add(2);
List<Number> unmodifiable = List.of(1, 2);
Immutable Map Entry Factory
Factory methods have been added to the Collections class for simplifying map entry creation.
Map<Number, String> unmodifiable = Map.ofEntries();
Map<Number, String> unmodifiable = Map.ofEntries(
Map.entry(1, "one"),
Map.entry(2, "two"));
Optional
Path name = Paths.get("file.txt");
Optional<File> file = search
.onLocalDisk(name)
.or(() -> search.onNetworkShare(name))
.or(() -> search.onCloudService(name));
file.ifPresentOrElse(
f -> System.out.format("File at %s", f.getName()),
() -> System.out.format("File %s not found", name.getFileName()));
long count = Optional
.ofNullable(null)
.stream()
.count();
Collectors
By applying a filter predicate we can adapt a collector to accept only elements matching a predicate.
List<Integer> list = IntStream.of(2, 4, 6, 8, 10, 12)
.boxed()
.collect(Collectors.filtering(i -> i % 3 == 0,
Collectors.toList()));
With the new flatMapping
method a stream of streams or stream of collections a collector is adapted to return a flattened result.
List<Integer> list = Stream.of(List.of(1, 3, 5), List.of(2, 4, 6))
.collect(Collectors.flatMapping(
l -> l.stream()
.filter(i -> i % 3 == 0),
Collectors.toList()
));
Immutable Set Factory
Factory methods have been added to the Collections class for simplifying set creation.
Set<Number> empty = new HashSet<>();
Set<Number> unmodifiable = Collections
.unmodifiableSet(empty);
Set<Number> unmodifiable = Set.of();
Set<Number> withItems = new HashSet<>();
Set<Number> unmodifiable = Collections
.unmodifiableSet(withItems);
withItems.add(1);
withItems.add(2);
Set<Number> unmodifiable = Set.of(1, 2);
Immutable Map Factory
Factory methods have been added to the Collections class for simplifying map creation.
Map<Number, String> empty = new HashMap<>();
Map<Number, String> unmodifiable = Collections
.unmodifiableMap(empty);
Map<Number, String> unmodifiable = Map
.ofEntries();
Map<Number, String> withItems = new HashMap<>();
Map<Number, String> unmodifiable = Collections
.unmodifiableMap(withItems);
withItems.put(1, "one");
withItems.put(2, "two");
Map<Number, String> unmodifiable = Map
.of(1, "one", 2, "two");
Matcher
With Matcher.results
we get a stream of all matched elements
Pattern pattern = Pattern.compile("\\d+");
Matcher matcher = pattern.matcher("11 2 3 4 5");
int result = matcher.results()
.map(MatchResult::group)
.mapToInt(Integer::parseInt)
.sum();
With Matcher.replaceAll
we can perform substitution of matches.
String WHITE_SPACE = "\\s+";
Pattern pattern = Pattern.compile(WHITE_SPACE);
Matcher matcher = pattern.matcher("snake case notation");
String result = matcher.replaceAll(matchResult -> "_");
Stream
List<Integer> subset = stream
.takeWhile(n -> n < 5)
.collect(Collectors.toList());
We can take (accept) stream elements matching a predicate.
List<Integer> subset = stream
.dropWhile(n -> n < 11)
.collect(Collectors.toList());
We can drop stream elements matching a predicate.
List<Integer> subset = Stream
.iterate(10, n -> n < 15, n -> n + 1)
.collect(Collectors.toList());
Generate a stream using an iteration.
Collection<Integer> collection = null;
List<Integer> list = Optional
.ofNullable(collection)
.stream()
.flatMap(Collection::stream)
.collect(Collectors.toList());
With Java ⑧ and before we have to use a conditional statement of Optional.ofNullable
to work with potentially null collections.
Collection<Integer> collection = null;
List<Integer> list = Stream
.ofNullable(collection)
.flatMap(Collection::stream)
.collect(Collectors.toList());
With Stream.ofNullable
we can work with a stream that is potentially null and avoid testing using a conditional statement or Optional.ofNullable
.