Java 9-16 all useful features

Java 9

Private methods inside interface

package com.java.demo;

interface StringManipulationUtil{

    private static String reverseString(String str){
            return new StringBuilder(str).reverse().toString();
    }

    static String toUpperReverse(String str){
        String upperStr = str.toUpperCase();
        return reverseString(upperStr);
    }

    static String toLowerReverse(String str){
        String lowerStr = str.toLowerCase();
        return reverseString(lowerStr);
    }
}

public class Java9Demo {

    public static void main(String[] args) {

        System.out.println(StringManipulationUtil.toLowerReverse("Hello Java!!!"));
        System.out.println(StringManipulationUtil.toUpperReverse("Hello Java!!!"));

    }
}

takeWhile and dropWhile

       List<Integer> integerList = Arrays.asList(1,2,3,4,5,6,7,8,9);

        System.out.println("---takeWhile---");

        integerList.stream()
                .takeWhile(e->e<5)
                .forEach(System.out::println);

        System.out.println("---dropWhile---");

        integerList.stream()
                .dropWhile(e->e<5)
                .forEach(System.out::println);

Closed Range

package com.company;

import java.util.Arrays;
import java.util.List;
import java.util.stream.IntStream;

public class Main {
    public static void main(String[] args) {
        
        IntStream.range(1,5).forEach(System.out::println);

        System.out.println("--Closed Range--");

        IntStream.rangeClosed(1,5).forEach(System.out::println);
    }
}




More control over stream iterator

package com.company;

import java.util.stream.IntStream;

public class Main {
    public static void main(String[] args) {


        for (int i=0;i<=10;i+=2){
            System.out.println(i);
        }

        System.out.println("-------");

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




ifPresentOrElse

package com.company;

import java.util.Arrays;
import java.util.List;

public class Main {
    public static void main(String[] args) {

        List<Integer> integerList = Arrays.asList(1,2,3,4,5,6,7,8);

        integerList
                .stream()
                .filter(e->e>7).findFirst()
                .ifPresentOrElse(System.out::println,
                        ()-> System.out.println("Value doesn't exist"));
    }
}




Or With Optional

List<Integer> integerList = Arrays.asList(1,2,3,4,5,6,7,8);

integerList
.stream()
.filter(e->e>10).findFirst()
.or(()-> Optional.of(-1)).ifPresentOrElse(System.out::println,
()->System.out.println("Value doesn't exists"));

Convert Optional into Stream

 List<Integer> integerList = Arrays.asList(1,2,3,4,5,6,7,8);

integerList
.stream()
.filter(e->e>7).findFirst().stream()
// this is Java 16 method we will discuss it later
.mapMulti((number,consumer)-> IntStream.rangeClosed(1,10)
.forEach(e->consumer.accept(e*number)))
.forEach(System.out::println);

The of method

package com.company;

import java.util.List;
import java.util.Map;
import java.util.Set;

public class Main {

    public static void main(String[] args) {

        System.out.println(List.of(1,2,3,4,5,7,8,9));
        System.out.println(Set.of(1,2,3,4,5,6));
        System.out.println(Map.of(1,"One",2,"two",3,"three"));
    }
}




class Resource implements AutoCloseable{
    public Resource(){
        System.out.println("created");
    }

    public void display(){
        System.out.println("Resource");
    }

    public void close(){
        System.out.println("Clean up");
    }
}

class Resource2 implements AutoCloseable{
    public Resource2(){
        System.out.println("created2");
    }

    public void display(){
        System.out.println("Resource2");
    }

    public void close(){
        System.out.println("Clean up2");
    }
}

public class Java9Demo {

    public static void main(String[] args) {
        Resource resource= new Resource();
        Resource2 resource2= new Resource2();
        try(resource;resource2){
            resource.display();
            resource2.display();
        }

    }
}

AutoCloseable Enhancements

Jshell

Jshell is REPL for Java :

  • Read
  • Event
  • Print
  • Loop

Enter in jshell using the command below

jshell

Create a String

jshell> "hello world"
$1 ==> "hello world"

Print the String

System.out.println($1)

Change the value it holds

$1= $1 + " again"

Adding 2 numbers

int sum = 1+2;

Conditional Statement

jshell> if(sum>0)
   ...> System.out.println("Positive")
Positive

Create Method

int negativeNumber(int n)
   ...> {
   ...> return -n;
   ...> }
|  created method negativeNumber(int)

Call the created method

negativeNumber(sum)

Create Method before defining variable (Forward Refrencing)

jshell> int addRandomNumber(int n)
   ...> {
   ...> return n + RANDOM_NUMBER;
   ...> }
|  created method addRandomNumber(int), however, it cannot be invoked until variable RANDOM_NUMBER is declared

Attempting to use the previous method

jshell> addRandomNumber(10)
|  attempted to call method addRandomNumber(int) which cannot be invoked until variable RANDOM_NUMBER is declared

Defining the undefined variable

jshell> int RANDOM_NUMBER = 12;
RANDOM_NUMBER ==> 12

Calling after variable Definition

jshell> addRandomNumber(10)
$14 ==> 22

Creating a class in jshell

jshell> class Dummmy{
   ...> int number =3;
   ...> public void setNumber(int number){this.number=number; }
   ...> public int getNumber(){return number;}
   ...> }
  created class Dummmy


jshell> Dummmy d = new Dummmy(); 
d ==> Dummmy@184f6be2

jshell> d.setNumber(
setNumber(   

jshell> d.setNumber(3);

jshell> d.getNumber();
$18 ==> 3

Sleep in jshell

jshell> Thread.sleep(2000); System.out.println("Hello");
Hello

JShell Automatically Catches the Exception

jshell> 1/0
|  java.lang.ArithmeticException thrown: / by zero
|        at (#25:1)

Exit Jshell Console

jshell> /exit
 Goodbye

/list lists all valid statements

jshell> /list

   1 : "hello world"
   2 : System.out.println($1)
   3 : $1+ " again"
   4 : $1= $1 + " again"
   5 : int sum = 1+2;
   6 : if(sum>0)
       System.out.println("Positive");
   7 : System.out.println("Positive");
   8 : if(sum>0)
       System.out.println("Positive");
   9 : int negativeNumber(int n)
       {
       return -n;
       }
  10 : negativeNumber(sum)
  11 : int addRandomNumber(int n)
       {
       return n + RANDOM_NUMBER;
       }
  12 : addRandomNumber(10)
  13 : int RANDOM_NUMBER = 12;
  14 : addRandomNumber(10)
  15 : class Dummmy{
       int number =3;
       public void setNumber(int number){this.number=number; }
       public int getNumber(){return number;}
       }
  16 : Dummmy d = new Dummmy();
  17 : d.setNumber(3);
  18 : d.getNumber();
  19 : Thread.sleep(1000);
  20 :  System.out.println("Hello");
  21 : Thread.sleep(2000);
  22 :  System.out.println("Hello");
  23 : new Thread(()->System.out.println("Hello")).start()
  24 : CompletableFuture.runAsync(()->System.out.println("Hello")).thenRun(()->System.out.println("World"))
  25 : 1/0

/history show all valid and invalid commands

jshell> /history

"hello world"
System.out.println($1)
$1+ " again"
$1= $1 + " again"
int sum = 1+2;
if(sum>0)
System.out.println("Positive")
if(sum>0)
System.out.println("Positive") else System.out.println("negative")
System.out.println("Positive") else System.out.println("negative");
System.out.println("Positive"); else System.out.println("negative");
if(sum>0)
System.out.println("Positive")
int negativeNumber(int n)
{
return -n;
}
negativeNumber(sum)
int addRandomNumber(int n)
{
return n + RANDOM_NUMBER;
}
addRandomNumber(10)
int RANDOM_NUMBER = 12;
addRandomNumber(10)
class Dummmy{
int number =3;
public void setNumber(int number){this.number=number; }
public int getNumber(){return number;}
}
Dummy dummy = new Dummy()
Dummy dummy = new Dummy();
Dummmy d = new Dummmy(); 
d.setNumber(3);
d.getNumber();
Thread.sleep(); System.out.println("Hello");
Thread.sleep(1000); System.out.println("Hello");
Thread.sleep(2000); System.out.println("Hello");
new Thread(()->System.out.println("Hello")).start()
CompletableFuture.runAsync(()->System.out.println("Hello")).thenRun(()->System.out.println("World"))
1/0
/list
/history
amsldasd
/history

jshell> 

Display all variables

jshell> /vars
|    int sum = 1
|    String $2 = "Hello"

Using editor

jshell> /edit

See all the imports

jshell> /imports
|    import java.io.*
|    import java.math.*
|    import java.net.*
|    import java.nio.file.*
|    import java.util.*
|    import java.util.concurrent.*
|    import java.util.function.*
|    import java.util.prefs.*
|    import java.util.regex.*
|    import java.util.stream.*

Modularization is Java 9

What is a module ?

  • a collection of code (packages) and data
  • has a name (Generally a reverse DNS name)
  • tells what is needs (requires)
  • tells what is provides (exports)

Note:

You require modules

You Export Package

  • Create 3 modules in your project.
  • Introduce a main-info.jave file for each module in the root folder.

Require a module from JDK

module module1{
            requires java.logging;
            
}

module-info.java

package com.Arithemetic.demo;

import java.util.logging.Logger;

public class ArithmeticOperation {
    static Logger logger = Logger.getLogger(ArithmeticOperation.class.getName());
    public static void add(int a, int b) {
        logger.info("Sum::"+a+b);

    }
}
package com.String.demo;

import java.util.logging.Logger;

public class StringOperation {
    static Logger logger = Logger.getLogger(StringOperation.class.getName());
   public static void concatAndReverseString(String string1, String string2) {
        logger.info(new StringBuilder(string1 + " " + string2).reverse().toString());
    }


}

Handshake between 2 modules

module module1{
            requires java.logging;
            exports com.Arithemetic.demo;           
}
module module2{
    requires module1;
}
package com.module2.demo;

import com.Arithemetic.demo.ArithmeticOperation;

public class Module2Demo {
    public static void main(String[] args) {
        ArithmeticOperation.add(1,2);
    }

}

Restricting package access for a module

module module1{
            requires java.logging;
            exports com.Arithemetic.demo;
            exports com.String.demo to module3;
}

com.String.demo is available to module3 and this package cannot be access in module 2

Exercise 1

  • Practice following features of Java 9
    • Private Methods in interface
    • takeWhile and dropWhile methods in streams API
    • ClosedRange
    • Create a Stream using .iterator method apply some filter on it and Collect the result
    • ifPresentOrElse with Optional
    • or with Optional
    • Convert Optional into Stream
    • Use of method to create immutable collections
    • Enhanced try block with AutoCloseable
  • Try few jshell commands
  • Perform handshake between 2 modules

Java 10

Local Variable Type inference

  • One of the most visible enhancements in JDK 10 is type inference of local variables with initializers.
  • Until Java 9 we have to mention the type of the local  variable and insure that it was compatible with the initializer used to initialize it.
  • In Java 10 we can mark the variable with var and the compiler infers the type of the variable.
var message = "Hello, java 10";
System.out.println(message instanceof String);
  • Note that this feature is available only for local variables with the initializer. It cannot be used for member variables, method parameters, return types, et
var map = new HashMap<String, Integer>();
var list = new ArrayList<Integer>();
var set = new HashSet<String>();

Illegal use of var

var won't work without initializer

var n;

Nor would it work if initialized with null:

var empty=null;

It won't work for non-local variables:

public var empty=null;

Lambda expression needs explicit target type, and hence var cannot be used:

var p = (String s) -> s.length() > 10;
var arr = {1,2,3,4};

Same is the case with the array initializer:

Unmodifiable Collections

 

copyOf : java.util.List, java.util.Map and java.util.Set each got a new static method copyOf(Collection).

It returns the unmodifiable copy of the given Collection:

List<Integer> intList = new ArrayList<>();
intList.add(1);
intList.add(2);
intList.add(3);
intList.add(4);

List<Integer> unmodifiableCollection = List.copyOf(intList);
unmodifiableCollection.add(5);

toUnmodifiable : java.util.stream.Collectors get additional methods to collect a Stream into unmodifiable List, Map or Set

List<Integer> intList =  Stream.of(1,2,3,4,5,6,7)
				.filter(e->e%2==0)
				.collect(Collectors.toUnmodifiableList());

Optional*.orElseThrow()

java.util.Optional, got a new method orElseThrow() which doesn't take any argument and throws NoSuchElementException if no value is present:

 

 
Stream.of(1,2,3,4,5,6,7).filter(e->e>8).findFirst().orElseThrow();

Java 11

String API additions

 repeat() instance method repeats the string content.

String song = "we wish you a merry christmas!!!! ".repeat(3)+" and a happy new year";
System.out.println(song);

The strip() instance method returns a string with all leading and trailing whitespaces removed:

 String whiteTrailString = "\n\t   This is a string with white trails   \u2005";
 System.out.println(whiteTrailString.trim().equals("This is a string with white trails"));//false
 System.out.println(whiteTrailString.strip().equals("This is a string with white trails"));//true

The isBlank() instance method returns true if the string is empty or contains only whitespace

String blackString = "\n\t  ";
System.out.println(blackString.isBlank());

The lines() instance method returns a Stream of lines extracted from the string, separated by line terminators:

String multiLines = "This is line 1.\n This is line 2";
System.out.println("Total number of lines::"+multiLines.lines().count());
  • The java.util.Collection interface contains a new default toArray method.
  • This toArray method is also provided as stream terminal operation.
  • It is a handy method to transform a collection or Stream to Arrays

toArray with Stream and Collection

List<Integer> integerList = Arrays.asList(1, 2, 3, 4);
Integer[] intArray = integerList.toArray(Integer[]::new);
System.out.println(Arrays.compare(intArray, new Integer[]{1,2,3,4}));

System.out.println(Arrays.toString(integerList.stream().filter(e -> e % 2 != 0).toArray()));

New IO methods introduced in Java 11

String path = "/Users/pulkitpushkarna/demo.txt";
try {
 String fileContent = Files.readString(Path.of(path)); 
 System.out.println(fileContent);
 Files.writeString(Path.of(path),"This is third line.", StandardOpenOption.APPEND);

 List<String> stringList = Files.readAllLines(Path.of(path));
 stringList.forEach(System.out::println);
} catch (IOException e) {
	e.printStackTrace();
}

 java.net.http package has become standard feature in Java 11

HttpRequest httpRequest = HttpRequest
                .newBuilder()
                .uri(URI.create("http://dummy.restapiexample.com/api/v1/employee/1"))
                .GET()
                .build();

        HttpClient httpClient = HttpClient.newBuilder().build();
        try {
            HttpResponse<String> httpResponse = httpClient.send(httpRequest, HttpResponse.BodyHandlers.ofString());
            System.out.println(httpResponse.body());
        } catch (IOException e) {
            e.printStackTrace();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }

Support for using the var keyword in lambda parameters was added in Java 11

 BiFunction<Integer,Integer,Integer> function = (var a, var b)->a+b;
 System.out.println(function.apply(1,2));

isEmpty method introduced Optional class

Optional<Integer> integerOptional= List.of(1,2,3,4).stream().filter(e->e>7).findFirst();

System.out.println(integerOptional.isPresent());
System.out.println(integerOptional.isEmpty());

Predicate Not Method in Streams

Optional<Integer> integerOptional= List.of(1,2,3,4)
.stream()
.filter(Predicate.not(e->e>7))
.findFirst();
System.out.println(integerOptional);

Java 12

String text = "Hello Guys ! This is Java 12 article.";
text = text.indent(15);
System.out.println(text);
text = text.indent(-20);
System.out.println(text);
  • indent adjusts the indentation of each line based on the integer parameter.
  • If the parameter is greater than zero, new spaces will be inserted at the beginning of each line.
  • On the other hand, if the parameter is less than zero, it removes spaces from the begging of each line.

indent method

Transform Method

 transform. It accepts a single argument function as a parameter that will be applied to the string.

String returnString = text.transform(string-> new StringBuilder(string)
.reverse().toString());
System.out.println(returnString);

File Mismatch method

It returns -1L if the files are identical

Path path1 = Files.createTempFile("file1",".txt");
Path path2 = Files.createTempFile("file2",".txt");
Files.writeString(path1,"Java 12 features");
Files.writeString(path2,"Java 12 features");
System.out.println(Files.mismatch(path1,path2));;

Teeing Collector

  • It is a composite of two downstream collectors.
  • Every element is processed by both downstream collectors.
  • Then their results are passed to the merge function and transformed into the final result.
 double mean = Stream.of(1,2,3,4,5)
 .collect(Collectors.teeing(
 		Collectors.counting(), 
        Collectors.summingDouble(e->e+5),
        (a,b)->b/a));
 
 
 
System.out.println(mean);
        
double result = (double)Stream.of(1,2,3,4,5)
					.collect(
                        Collectors.teeing(Collectors.reducing(1,(a,b)->a*b),
                                Collectors.reducing(0,
                                        (a,b)->a+b),(a,b)->a/b));
System.out.println(result);;

Compact Number Formatting

the CompactNumberFormat. It's designed to represent a number in a shorter form, based on the patterns provided by a given locale.

NumberFormat likesShort =
NumberFormat.getCompactNumberInstance(new Locale("en", "US"), NumberFormat.Style.SHORT);
likesShort.setMaximumFractionDigits(2);
System.out.println(likesShort.format(12345678));

NumberFormat likesLong =
NumberFormat.getCompactNumberInstance(new Locale("en", "US"), NumberFormat.Style.LONG);
likesLong.setMaximumFractionDigits(2);
System.out.println(likesLong.format(12345678));

Switch Expressions compact and more readable (Preview)

String dayOfWeek = "SUNDAY";
       String day = switch (dayOfWeek){
            case "MONDAY","TUESDAY","WEDNESDAY","THURSDAY","FRIDAY"->"WEEKDAY";
            case "SATURDAY","SUNDAY"->"WEEKEND";
           default -> throw new IllegalStateException("Unexpected value: " + dayOfWeek);
       };

Pattern Matching with instanceof (Preview)

Object object = "Hello Java";
        if(object instanceof String s){
            System.out.println(s.length());
        }

Exercise 2

  • Perform Local Variable Type inferencing with var
  • Create Unmodifiable Collections from modifiable Collections
  • Try orElseThrow method with Optional
  • Try out following String methods
    • repeat
    • strip
    • isBlank
    • lines
  • Use toArray method to convert Stream and List into array
  • Perform files operation using new readString and writeString methods.
  • Perform Rest API GET call using java.net.http
  • use Predicate.not with streams
  • Try out indent and tranform methods of String
  • Use file::mismatch  method to compare 2 files.

Exercise 2 (Cont.)

  • Use teeing collector with Streams
  • Try out Compact Number Formatting
  • Use Switch Expressions with  Compact Syntax
  • Use Pattern matching with instanceOf

Java 13

yield in switch expression

  String dayOfWeek = "TUESDAY";
        String day = switch (dayOfWeek) {
            case "MONDAY", "TUESDAY", "WEDNESDAY", "THURSDAY", "FRIDAY" -> {
                System.out.println("Performing Some operations for this case");
                yield "WEEKDAY";
            }
            case "SATURDAY", "SUNDAY" -> {yield "WEEKEND";}
            default -> throw new IllegalStateException("Unexpected value: " + dayOfWeek);
        };
        System.out.println(day);

yield, we can now effectively return values from a switch expression. In case of multiple lines in 

triple quote notation for text blocks

This will allow us to defined strings on multiple line without the need to escape new lines \n or use the + sign for string concatenation on multiple lines.

 String multiLines = """
                This is line 1.
                This is line 2.
                """;
        System.out.println(multiLines);

        String JSON_STRING = """
              {"name":    "Pulkit",
                          "age":31
                }
                """;

        System.out.println(JSON_STRING);

java.lang.String now has three new methods

  • stripIndent() – mimics the compiler to remove incidental white space

 

 

  • translateEscapes() – translates escape sequences such as “\\t” to “\t”

 

 

  • formatted() – works the same as String::format, but for text blocks
String html = "\t<html>\n" +
                "\t\t<body>\n" +
                "\t\t\t<p>Hello, world</p>\n" +
                "\t\t</body>\n" +
                "\t</html>";
        System.out.println(html);
        System.out.println(html.stripIndent());
String str = "\"Hello\\nWorld\"";
System.out.println(str);
System.out.println(str.translateEscapes());
System.out.println(String.format("Java %s", "12"));
System.out.println("Java %s".formatted("12"));

Java 14

 Text Blocks (Preview)

text blocks now have two new escape sequences:

  • \: to indicate the end of the line, so that a new line character is not introduced
  • \s: to indicate a single space
String multiline = """
    This is line 1.\
     This is line 2.
""";
        
        
System.out.println(multiline);

String stringWithSpaces = "This is line with \s\sspaces";
        
System.out.println(stringWithSpaces);

Records (Preview)

  • Passing immutable data between objects is one of the most common tasks in many Java applications.
  •  This required the creation of a class with boilerplate fields and methods, which were susceptible to trivial mistakes
  • we can replace our repetitious data classes with records.
  • Records are immutable data classes that require only the type and name of fields.
  • The equals, hashCode, and toString methods, as well as the private, final fields, and public constructor, are generated by the Java compiler.

To create a Person record, we use the record keyword:

record Person(String name, String age){};
Person person = new Person("Pulkit","23");

This constructor can be used in the same way as a class to instantiate objects from the record:

We also receive public getters methods – whose names match the name of our field

Person person = new Person("Pulkit","23");
System.out.println(person.name());
System.out.println(person.age());

equals method returns true if the supplied object is of the same type and the values of all of its fields match:

Person person1 = new Person("Pulkit","23");
Person person2 = new Person("Pulkit","23");
System.out.println(person1.equals(person2));

hashCode method returns the same value for two Person objects if all of the field values for both object match

Person person1 = new Person("Pulkit","23");
Person person2 = new Person("Pulkit","23");
System.out.println(person1.hashCode());
System.out.println(person2.hashCode());

toString method that results in a string containing the name of the record, followed by the name of each field and its corresponding value in square brackets.


System.out.println(person);

While a public constructor is generated for us, we can still customize our constructor implementation.

This customization is intended to be used for validation and should be kept as simple as possible.


        record Person(String name, String age){
        //canonical constructor Java 15
            Person{
                Objects.requireNonNull(name);
                Objects.requireNonNull(age);
            }
            public Person(String name) {
                this(name, "Unknown");
            }
        };

        Person person = new Person("Pulkit");
        System.out.println(person);

 we can also include static variables and methods in our records.

	record Person(String name, int age) {
            static int counter = 0;

            static void incrementCounter() {
                counter++;
            }

            Person {
                incrementCounter();
            }
        };
        
        new Person("Pulkit", 23);
        new Person("Sunny", 24);
        System.out.println(Person.counter);

We can also include instance methods in our records

record Person(String name, int age) {

            String getOnlyName(){
                return Person.this.name;
            }
        };

        System.out.println(new Person("Sunny", 24).getOnlyName());

Java 15

Sealed Classes (Preview)

  •  The goal of sealed class is to allow individual classes to declare which types may be used as sub-types.
  • This also applies to interfaces and determining which types can implement them.
  • Sealed classes involve two new keywords — sealed and permits:
sealed class Base permits Child1,Child2{ }

final class Child1 extends Base{}
final class Child2 extends Base{}
//  Child3 is not allowed in sealed hierarchy
final class Child3 extends Base{}

Every permitted class must be set with an explicit modifier. It can either be final, sealed or non sealed

  • A permitted subclass that’s declared final cannot be extended further
  • A permitted subclass that’s declared sealed can be extended further but only by classes that are permitted by the subclass.
  • A permitted subclass may be declared non-sealed can be extended further by any class. The superclass cannot restrict the subclasses further down this class hierarchy.
sealed class Base permits Child1,Child2,Child3{ }

final class Child1 extends Base{}
sealed class Child2 extends Base permits GrandChild{}
non-sealed class Child3 extends Base{}

final class GrandChild extends Child2{}
//GrandChile2 not allowed in sealed hierarchy
class GrandChild2 extends Child2{}

Sealed Classes with Records

sealed interface Vehicle permits Car,Bike{
    int numberOfWheels();
}

record Car() implements Vehicle {
    @Override
    public int numberOfWheels() {
        return 4;
    }
}

record Bike() implements Vehicle{
    @Override
    public int numberOfWheels() {
        return 2;
    }
}

public class Java15Demo {
    public static void main(String[] args) {
        Car car = new Car();
        System.out.println(car.numberOfWheels());

        Bike bike = new Bike();
        System.out.println(bike.numberOfWheels());

    }
}

Pattern Matching Type Checks with Records

sealed interface Vehicle permits Car,Bike{
    int numberOfWheels();
}

record Car() implements Vehicle {
    @Override
    public int numberOfWheels() {
        return 4;
    }
}

record Bike() implements Vehicle{
    @Override
    public int numberOfWheels() {
        return 2;
    }
}

public class Java15Demo {
    public static void main(String[] args) {
        Object obj = new Car();
        if(obj instanceof Vehicle vehicle && vehicle.numberOfWheels()>2){
            System.out.println(vehicle.numberOfWheels());
        }
    }
}

Java 16

  • The pattern matching for instanceof is a standard or product feature in Java 16.
  • The record is finalized and becomes a standard feature.
  • Java 16 introduces a new Stream.mapMulti method which allows you to replace elements in a stream with multiple elements.
Stream.of("hello","world").mapMulti((string,consumer)->consumer.accept(string));

 System.out.println(Stream.of("hello","world","java")
                .mapMulti((string,consumer)->{
                    if(string.length()>4) {
                        consumer.accept(string);
                        consumer.accept(string.toUpperCase());
                        consumer.accept(new StringBuilder(string).reverse().toString());
                    }
                })
                .collect(Collectors.toList()));;
                
                                
Stream.of(1,2,3)
.mapMultiToInt((number,consumer)->{  
IntStream.range(1,11).forEach(e->consumer.accept((Integer)(number *e)));
} )
.filter(e->e>15)
.forEach(System.out::println);


 record Artist(String name) {}

record Album(String title, List<Artist> artistList) {}
record Pair(String album,String artist){}

        List<Album> albums =
                List.of(new Album("Album1",
                                List.of(new Artist("Artist1"), new Artist("Artist2"))),
                        new Album("Album2",
                                List.of(new Artist("Artist3"), new Artist("Artist4"))));
        albums.stream().mapMulti((album, consumer) -> {
            for (Artist artist : album.artistList()) {
                    consumer.accept(new Pair(album.title,artist.name));
            }
        }).forEach(System.out::println);

Exercise 3

  • use yield with Switch Statement
  • Create a String using Triple Quote notation
  • Use following operations with String
    • stripIndent
    • translateEscapes
    • formatted
    • escape new line in triple quote text block
  • Create a Record for Student with following Fields:
    • id
    • name
    • standard
  • Make sure that no null values should be used for initialization.
  • Use equal and hashCode methods with Student records

Exercise 3 (Cont.)

  • Use a Sealed class Class concept to create a class hierarchy
  • Mark Child classes as final, sealed and non sealed and observe their behaviour
  • Try out MultiMap intermediate method of Stream

Java 9-16 all useful features

By Pulkit Pushkarna

Java 9-16 all useful features

  • 740