Revising current Java features (JAVA-9 to JAVA-14)

Java 9 Features

- Immutable List

  • Cannot add null value, it will throw NullPointerException.
  • Cannot add more values to the list, it will throw UnsupportedOperationException.
  • Can add values only at the time of initialization.

- Immutable Set

  • Cannot add duplicate values like Set.of(1,1,2), it will throw IllegalArgumentException.
  • Cannot add null value, it will throw NullPointerException.
  • Cannot add more values to the set, it will throw UnsupportedOperationException.
  • Can add values only at the time of initialization.

- Immutable Map

Map.of(K1,V1,K2,V2);      // K refers to key and V refers to value


  • Cannot add more values to the map, it will throw UnsupportedOperationException.

- Underscore become a keyword ‘_’

String _ = "alpha";        // compilation error

- Stream modifications :

To wrap a value which may be null, it prevents from null pointer exception.

String key = "";
Stream<String> strng = Stream.ofNullable(key);

2) takeWhile()

Takes a predicate and decides till when to process the data.

Stream<Integer> take = Stream.of(1, 2, 3, 4, 5).map(x -> x * x).takeWhile(x -> x < 3);

In this example it will create a stream of only 1 element because only 1 element satisfies the takewhile condition. Even if we change the values to (1,2,3,4,1) it will still create a stream of 1 element because once the predicate fails it stops its processing, it will not compute the further elements.

3) dropWhile()

Takes a predicate and decides from which element to start processing the data.

Stream<Integer> drop = Stream.of(1, 2, 3, 4, 5)
.map(x -> x * x).dropWhile(x -> x < 2);

It will create a stream of 4 elements (2,3,4,5) as they satisfies the dropwhile() condition. Now, if we change the values to (1,2,3,4,5,1) then it will create a stream of 5 elements because once the predicate condition passes it will take all the remaining elements without computing it with predicate present in dropwhile() method.

4) iterate()

Till Java-8 iterate method comes with seed and operator only. From Java-9 iterate comes with predicate.

till Java 8

Stream.iterate(1, count->count+2 ).forEach(System.out::println); // infinite loop

from Java 9

IntStream.iterate(0, i -> i <10, i-> i++).forEach(System.out::println);

- Optional modifications :

It is used to return an Optional default value. Till Java-8 we had orElse() and orElseGet() methods, these methods returns the object value but if we need the result in an optional format, we did not had any method for that, so in Java-9 then introduced or().

Optional<Integer> optionalValue = Optional
.or(() -> Optional.of(3));

If the value of ‘‘val’’ is null then it will return 3 as an optional value.

2) ifPresentOrElse()

It takes 2 arguments, 1st is a Consumer and second is a Runnable. Consumer gets executed if the given optional value computes to a not null value otherwise Runnable method will get executed.

v -> print(v),
Person:: error
public static void error() {

Here if the optional value is not null then it will print the value otherwise, it will execute the error() method.

3) stream()

Now we can create a stream on a optional value like:

List<String> collect =  Optional

It will first check if value of val variable is null or not, if it is not null then it will creates a stream on that, applies the upper case method and collects the response in a list.

- Private method in interface

- Try with resource

Let say we have a class name Person which implements Closable interface and we want to use it in try with resource. So, till Java-8 we have to use it like:

try(Person person = new Person()){

we have to declare the class object in the try statement.

So in Java-9, we can use objects which are defined outside try statement. Object must implement either Autocloseable or closeable interface and objects must be final of effective final.

Person person = new Person();
try(person) {

Here we can see we defined the person object outside the try statement.

We can use multiple objects in try block using ‘;’ as delimiter like:

try(Scanner scanner = new Scanner(new File("txt")); person) {

Java 10 Features

- Local variable type inference

int a = 10;

now from Java-10 we don't have to specify the data type of variable, compiler itself infers the type of message from the type of the initializer present on the right-hand side. we can just define it with var keyword

var a = 10;

Compiler will understand that it is a integer using the value on the right side. It can be used only for the local variables with initializer, it cannot be used as a member variable, parameter and return value.

- List.copyOf()

List<Integers> list = Arrays.asList(1,2,3);List<Integer> unmodifiableList = List.copyOf(list);

If we try to alter this unmodifiable list then we will get ‘java.lang.UnsupportedOperationException’. In this example we used list as a argument, here we can use any collection.

- Set.copyOf()

List<Integers> list = Arrays.asList(1,2,3);Set<Integer> unmodifiableSet = Set.copyOf(list);

- Map.copyOf()

Map<String,Integer> map = new HashMap<>();
Map<String,Integer> unmodifiableMap = Map.copyOf(map);

- Collectors.toUnmodifiable*()

List<String> strings = Arrays.asList("alpha","beta","gamma");
List<String> collect = strings

Similarly we have toUnmodifiableMap() and toUnmodifiableSet() to create read-only map and set respectively.

- orElseThrow() method in Optional

List<Integer> integers = Arrays.asList(1, 2, 3, 4);
Integer integer = -> x > 10).findFirst().orElseThrow();

JAVA 11 Features

- Running java class with a single command

// Till java 10
java Myclass
// From Java 11
java Myclass

- New String methods

1) isBlank()

Checks if the current string value is blank or not, empty string or the string with white spaces only will be considered as blank string. This method will throw NullPointerException in case the string value is null.

String str1 = "";
boolean isStr1Blank = str1.isBlank(); //true
String str2 = null;
boolean isStr2Blank = str1.isBlank(); //java.lang.NullPointerException
String str3 = "alpha";
boolean isStr3Blank = str3.isBlank(); //false

2) lines()

This method returns a stream of strings, which is a collection of all sub-strings split by lines.

String essay = "line1\nline2\nline3";
System.out.println("Current value:");
System.out.println("List :");
List<String> collect = essay.lines().collect(Collectors.toList());
//Current value:
//[line1, line2, line3]

3) strip(), stripLeading(), stripTrailing()

These methods are used to remove the white spaces, leadingwhite spaces and trailing white spaces from a string. It is like a advanced version of trim, strip is unicode aware. Unicode was not there at the time of trim.

String className = "  My Class  ";System.out.println(className.strip());              // "MyClass"
System.out.println(className.stripLeading()); // "My Class "
System.out.println(className.stripTrailing()); // " My Class"

4) repeat()

It repeats the given string that many number of times as mentioned in the given parameter value.

String plus = "+";System.out.println(plus.repeat(3));    // +++

- Local variable syntax for lambda expression

(var a, var b) -> a+b;    // valid expressionvar a, var b  -> a +b;    // invalid expression(var a, int b) -> a+b;   // invalid expression

Second expression is invalid because we need to have parenthesis if we are using var in a lambda expression and third expression is invalid because mixing of any other data type is not allowed with var.

Java 12 Features

- Switch statement

String result = "";
int number = 1;
switch (number) {
case 1:
case 3: {
result = "odd number";
case 2:
case 4: {
result = "even number";
default: {
throw new NumberFormatException();

Now we can write the same switch expression with the lambda expressions like:

String result = "";
int number = 1;
result = switch (number) {
case 1, 3 -> "odd numbers";
case 2, 4 -> "even numbers";
default -> {
throw new NumberFormatException();

- File.mismatch method

public static long mismatch(Path path, Path path2) 
throws IOException

It compares the bytes of the files and returns the first byte which does not match, if all bytes matches then it returns -1L.

- Collectors.teeing()

public static <T, R1, R2, R> Collector<T, ?, R> teeing(
Collector<? super T, ?, R1> downstream1,
Collector<? super T, ?, R2> downstream2,
BiFunction<? super R1, ? super R2, R> merger)
return teeing0(downstream1, downstream2, merger);

So the result of first 2 collectors becomes the arguments of the Bifunction, lets understand with an example:

If we have a list of numbers and we want to calculate if the odd numbers are more or even numbers, how can we achieve this with teeing (I know there are much easier methods to solve this issue, here we are using teeing just for understanding this method).

So we can calculate the number of odd numbers in the 1st collector of the teeing method, even numbers in the 2nd collector and can compute which one is more in function.

Boolean isEvenDominatedList = Stream.of(1, 2, 3, 4, 5)
.filtering(x -> x % 2 == 0, Collectors.toList()),
.filtering(x -> x % 2 != 0, Collectors.toList()),
(evenList, oddList) -> evenList.size() > oddList.size()

- String new Methods

1) indent()

This method is used to add or remove white spaces in a multi line string.

String intro = "My\nname id\nRohan.";


//name id
System.out.println(intro.indent(2));// My
// name id
// Rohan.

Similarly if we have white space in a multi-line string we can remove it using negative value in the same method.

2) transform()

As the name suggests this method is used to transform a string value using java.util.Function

Integer transform = "x".transform(x -> x.length());
String transform1 = "alpha".transform(x -> x + "beta");

we can apply any function and transform a string in any format.

3) describeConstable()

It is used to get the optional value of any string

String name = "Rohan"
Optional<String> optionalName = name.describeConstable();
// Optional[Rohan]


- Text block

String html = """
<link href='/css/style.css' rel='stylesheet' />
<h1>Hello World</h1>

- Modification in switch expression

String result = switch (number) {
case 1,3:
yield "odd";
case 2,4:
yield "even";
throw new NumberFormatException();

- New String methods

2) stripIndent():
It is used to remove the incidental white space characters from the beginning and end of every line in the text block. This method is used by the text blocks and it preserves the relative indentation of the content.

3) translateEscapes():
It returns a string whose value is this string, with escape sequences translated as if in a string literal.

Java-14 features

- Switch expression

- Pattern matching

if(v instanceof String) {
String value = (String) v;

As we can see in this example first we are checking if the value of ‘v’ is an instance of String, if it is an instance of string then we are assigning a variable to its value. Now from Java-14 we can combine these 2 steps like

if(v instanceOf String value) {

- NullPointerException logs


If we get a NullPointerException here, its hard to tell from logs exactly because of which value it is causing NullPointerException. Now from Java-14 we get very specific logs for an exception

Exception in thread "main" java.lang.NullPointerException: Cannot invoke "Address.getSector()" because the return value of "Person.getAddress()" is null.

Here we can see where the exact problem is.

- Records

record Person() {}
record Person(String firstName, String lastName) {}

The Java compiler will generate a constructor, private final fields, accessors, equals/hashCode and toString methods automatically.

for more information about record, please refer :

Full stack developer