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 :
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 ?
Note:
You require modules
You Export Package
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
Java 10
Local Variable Type inference
var message = "Hello, java 10";
System.out.println(message instanceof String);
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:
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());
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());
String multiLines = "This is line 1.\n This is line 2";
System.out.println("Total number of lines::"+multiLines.lines().count());
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 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
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
Exercise 2 (Cont.)
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
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:
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)
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)
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
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
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
Exercise 3 (Cont.)