This is a list of the changes at Java’s API I found interesting or that I may use frecuently. Not all the changes from Java9, 10 & 11 are listed here.
Java 9
Java REPL (JShell)
It stands for Java Shell. It’s used to easily execute and test any Java construction like a class, interface, enum, etc.
Module System
The way we deploy Java-Based applications using jars has a lot of limitations & drawbacks. Some of these are: The JRE & JDK are too big; JAR files are too big to use in small devices and applications; There’s no strong encapsulation, public is open to everyone.
The new Module System introduces new features to avoid all this. More information here.
Factory Methods for Inmutable Collections (List, Map, Set & Map.Entry)
(I’ll use Lists as an example in this file, but this is valid for Maps and Sets too)
Until Java8 we could use Collections.unmodifiableList()
to achieve this, but this is really verbose. Now we can do the same with
List inmutableList = List.of("bla", "ble", "bli");
Private methods in Interfaces
To avoid redundant code and more re-usability we can use private and private static methods directly in interfaces now. Their behaviour is the same as in a normal class
public interface Card {
private Long createcardID() {
// calculate and return ID
}
private static void displayCardDetails() {
// implement
}
}
Try-with resources improvements
The new version improves the one which was implemented in Java SE 7 with better automatic resource management.
Java SE 7 Example
BufferedReader reader1 = new BufferedReader(new FileReader("file.txt"));
try(BufferedReader reader2 = reader1) {
// do something
}
Java 9 Example
BufferedReader reader1 = new BufferedReader(new FileReader("file.txt"));
try(reader1) {
// do something
}
Optionals’ improvements
#stream()
If a value is present in the given Optional object, stream returns a sequential Stream with that value. Otherwise, it returns an empty Stream.
Stream<Optional> employee = this.getEmployee(id);
Stream employeeStream = employee
.flatMap(Optional::stream);
#ifPresentOrElse(Consumer<? super Tl> action, Runnable emptyAction)
If a value is present, performs the given action with the value, otherwise performs the given empty-based action.
Optional<Integer> opt = Optional.of(4);
opt.ifPresentOrElse(System.out::println,
() -> System.out.println("Not found"));
#or(Supplier<? extends Optional<? extends T» supplier)
Returns the value contained by the Optional if it has one, or the value given by the supplier if empty.
Optional<String> opt = Optional.of("bla");
Supplier<Optional<String>> supplier =
() -> Optional.of("ble");
System.out.println(opt.or(supplier)); // bla
Optional<String> opt = Optional.empty()
Supplier<Optional<String>> supplier =
() -> Optional.of("ble");
System.out.println(opt.or(supplier)); // ble
Streams
#takeWhile(Predicate) / #dropWhile(Predicate)
Takes a predicate as an argument and returns a Stream of the subset until the predicate returns false for the first time. If the first value is false, it gives an empty Stream back.
Stream.of(1, 2, 3, 4, 5)
.takeWhile(i -> i < 4)
.forEach(System.out::println); // 1
// 2
// 3
#iterate(T seed, Predicate<? super T> hasNext, UnaryOperator next)
It’s similar to the for loop. First parameter is init value, second is the condition and third is to generate the next element.
// start value = 2; while value < 20;
// then value *= value
IntStream.iterate(2, x -> x < 20, x -> x * x)
.forEach(System.out::println);
#ofNullable()
Returns a sequential Stream containing a single element, or an empty Stream if null.
Stream<Integer> i = Stream.ofNullable(9);
i.forEach(System.out::println); // 9
Stream<Integer> i = Stream.ofNullable(null);
i.forEach(System.out::println); //
References
https://www.journaldev.com/13121/java-9-features-with-examples
Java 10
Local-variable Type Inference (var)
It adds type inference to declarations of local variables with initializers. It can only be used in the following scenarios:
- Limited only to local variable with initializer
var numbers = List.of(1, 2, 3, 4);
- Indexes of foreach loops
for(var number : numbers) { // do something }
- Local declared in for loop
for(var i = 0; i < numbers.size(); i++) { // do something }
API Improvements
Collection#copyOf(Collection)
Returns an unmodifiable list, map or set containing the entries provided. For a List, if the original list is subsequently modified, the returned List will not reflect this modifications.
List<String> strings = new ArrayList<>();
strings.add("bla");
strings.add("ble");
List<String> copy = List.copyOf(strings);
strings.add("bli");
System.out.println(strings); // bla, ble, bli
System.out.println(copy); // bla, ble
Collectors#toUnmodifiable…()
Different methods to collect into a unmodifiable collection.
List<String> strings = new ArrayList<>();
strings.add("bla");
strings.add("ble");
List<String> unmodifiableStrings =
strings.stream()
.collect(Collectors.toUnmodifiableList());
Optional#orElseThrow()
Is the same as Optional#get() but the doc states that this is a preferred alternative.
String name = "bla";
Optional<String> optionalName = Optional.ofNullable(name);
String s = optionalName.orElseThrow(); // bla
Optional<String> empty = Optional.empty();
// throws java.util.NoSuchElementException
String s = empty.orElseThrow();
References
https://www.journaldev.com/20395/java-10-features#local-variable-type-inference-jep-286 https://howtodoinjava.com/java10/java10-features/
Java 11
Single-file Applications
Now it’s possible to run single-file applications without the need to compile. It really simplifies the process to test new features.
In the file we have to write the following shebang
#!/usr/bin/java --source11
To run
java HelloWorld.java
Parameters before the name of the source file are passed as parameters to the java launcher. Parameters after are passed as parameters to the program.
java -classpath /home/bla/java HelloWorld.java Param1
Type inference for lambdas
var was introduced in Java10. The ability to use it in lambdas has been introduced in Java11.
list.stream()
.map((var s) -> s.toLowerCase())
.collect(Collectors.toList());
We already had type inference in lambdas, the difference is that with var we can use now type annotations to Lambda parameters.
lists.stream()
.map((@Notnull var s) -> s.toLowerCase())
.collect(Collectors.toList());
More info on type annotations.
String API improvements
#repeat
Allows concatenating a String with itself a number x of times
String s = "bla ";
String result = s.repeat(2); // bla bla
#isBlank
Checks wether a String is empty or contains a whitespace
String s = "";
boolean result = s.isBlank(); // true
#strip
Deletes whitespace on the start & end of a String. The difference with String#trim is that this is unicode aware. It relies on the same definition of whitespace as String#isBlank. This is a preparation for raw strings.
String s = " bla ";
String result = s.strip(); // bla (without spaces)
#lines
To easily split a String into a Stream
String s = "bla\nble";
List<String> lines = s.lines()
.collect(Collectors.toList()); // bla
// ble
Reference(s)
https://www.azul.com/90-new-features-and-apis-in-jdk-11/
https://4comprehension.com/java-11-string-api-updates/