0% found this document useful (0 votes)
20 views66 pages

Java Unit 3

Copyright
© © All Rights Reserved
Available Formats
Download as PDF, TXT or read online on Scribd
Download as pdf or txt
0% found this document useful (0 votes)
20 views66 pages

Java Unit 3

Copyright
© © All Rights Reserved
Available Formats
Download as PDF, TXT or read online on Scribd
Download as pdf or txt
Download as pdf or txt
You are on page 1/ 66

Lambda Expression

Lambda expression is an anonymous function.


ie
1. Not having any name
2. Not having any return type
3. Not have any modifier
eg1:
package com.edigest.lambda
public class A
{
public void show()
{
System.out.println("Hello");
}
}

Steps to make any function lambda expression


1. Remove modifier
2. Remove return type
3. Remove method name
4. Place arrow

1. Remove public / private


2. Remove void
3. Remove show
4. Place arrow after the brackets of the method
Now it look like
() - > {System.out.println("Hello");}

eg2:
private void add(int x, int y)
{
System.out.println(x+y)
}
(int x, int y) - >{System.out.println(x+y);}

Properties of lambda expression


1. If the body has just one statement then we can remove the curly braces

private void add(int x, int y)


{
System.out.println(x+y)
}

Convert to
(int x, int y) - >{System.out.println(x+y);}

Convert to
(int x, int y) - >System.out.println(x+y);

2. Use type inference, compiler guess the situation or context

Convert to
(x, y) - >System.out.println(x+y);

3. No return keyword
Private int show(String str)
{
return str.lenth();
}
Convert to lambda expression

(String str) - > {retuen str.length();}

Convert to
(str) - > str.length();
4. If only one param remove small brackets

(str) - >str.lebgth();

Convert to

str - > str.length();

Benefits of lambda expression


1. To enable functional programing in java
2. To make code more readable and concise
3. To enable parallel processing

Without Lambda Expression


interface Drawable
{
public void draw();
}
public class LambdaExpressionExample
{
public static void main(String[] args)
{
int width=10;

//without lambda, Drawable implementation using anonymous class


Drawable d=new Drawable()
{
public void draw()
{
System.out.println("Drawing "+width);

}
};
d.draw();
}
}
Output:
java -cp /tmp/Jr0t0G9g1k/LambdaExpressionExample
Drawing 10

=== Code Execution Successful ===

Java Lambda Expression Example


@FunctionalInterface //It is optional
interface Drawable
{
public void draw();
}
public class LambdaExpressionExample2
{
public static void main(String[] args)
{
int width=10; //with lambda
Drawable d2=()->{
System.out.println("Drawing "+width);
};
d2.draw();
}
}
Output:
java -cp /tmp/lX1o3vXdRt/LambdaExpressionExample2
Drawing 10

=== Code Execution Successful ===


Java Functional Interfaces
An Interface that contains exactly one abstract method is known as functional interface.
It can have any number of default, static methods but can contain only one abstract method.
Functional Interface is also known as Single Abstract Method Interfaces or SAM Interfaces. It
is a new feature in Java, which helps to achieve functional programming approach.
We can invoke lambda expression by using functional interface.

Example 1

@FunctionalInterface
interface sayable
{
void say(String msg);
}
public class FunctionalInterfaceExample implements sayable
{
public void say(String msg)
{
System.out.println(msg);
}
public static void main(String[] args)
{
FunctionalInterfaceExample fie = new FunctionalInterfaceExample();
fie.say("Hello there");
}
}
Output:
java -cp /tmp/Za4Nfts1VV/FunctionalInterfaceExample
Hello there

=== Code Execution Successful ===


Java Method References
Java provides a new feature called method reference in Java 8.
Method reference is used to refer method of functional interface.
It is compact and easy form of lambda expression.
Each time when you are using lambda expression to just referring a method, you can replace
your lambda expression with method reference.
Types of Method References
There are following types of method references in java:
1. Reference to a static method. – used to refer static methods from a class – Math::max is
equivalent to math.max(x,y)
2. Reference to an instance method. – refer to an instance method using a reference to the
supplied object – System.out::println is equivalent to System.out.println(x)
3. Reference to a constructor. – Reference to constructor – ArrayList::new is equivalent to
new ArrayList()
Reference to a Static Method
You can refer to static method defined in the class.
Syntax: ContainingClass::staticMethodName
In the following example, we have defined a functional interface and referring a static method
to it's functional method say().
interface abc
{
void say();
}
public class A
{
public static void main(String args[])
{
System.out.println("Learning Method ref");

//provide the implementation of abc


abc ob=()->
{
System.out.println("New Task");
};
ob.say();
}
}
Output:
Learning Method ref
New Task

=== Code Execution Successful ===

Now if suppose we don’t want to write the lambda expression code. Don’t want to write the
new implementation
We want to use the method of any other class defined previously.
We are creating a class A and method name is show() and want to use the same method in
place of lambda expression then we will use method reference.

interface abc
{
void say();
}
public class A
{
public static void show()
{
System.out.println("Hello, this is static method.");
}
public static void main(String[] args)
{
// Referring static method
abc ob = A::show;
// Calling interface method
ob.say();
}
}
Output:
Hello, this is static method.

=== Code Execution Successful ===

Reference to an Instance Method


Like static methods, you can refer instance methods also.
Syntax
containingObject::instanceMethodName
In the following example, we are referring non-static methods. You can refer methods by class
object and anonymous object.
interface abc
{
void say();
}
public class A
{
public void show()
{
System.out.println("Hello, this is non-static method.");
}
public static void main(String[] args)
{
A ob = new A(); // Creating object

// Referring non-static method using reference


abc ob1 = ob::show;

// Calling interface method


ob1.say();

// Referring non-static method using anonymous object


abc ob2 = new A()::show;
// You can use anonymous object also

// Calling interface method


ob2.say();
}
}
Output:
Hello, this is non-static method.
Hello, this is non-static method.

=== Code Execution Successful ===


Reference to a Constructor
You can refer a constructor by using the new keyword.
Syntax
ClassName::new

interface abc
{
void show(String msg);
}
class A
{
A(String msg)
{
System.out.print(msg);
}
}
public class B
{
public static void main(String[] args)
{
abc ob = A::new;
ob.show("Hello");
}
}

Output:
Hello
=== Code Execution Successful ===

Java 8 Stream
Java provides a new additional package in Java 8 called java.util.stream.
Collection: Single unit of object.
Stream: If we want to process the object from a collection, then we should use a stream.
Collection to stream conversion
Stream s=collection.stream();
In Stream API, there are 2 types of operations
1. Intermediate operation
Transform a stream into another stream.
Available methods are: filter, map, distinct, sorted limit etc.

2. Terminal operation
It produces the result and terminates the string.
Available methods are forEach, collect, reduce, count etc.

filter()
The filter method is used to select elements as per the Predicate passed as an argument.
Used to filter the data

Syntax: Stream filterStream=orginalStream.filter(element->/*predicate*/);

List names = Arrays.asList("Reflection","Collection","Stream");


List result = names.stream().filter(s->s.startsWith("S")).collect(Collectors.toList());

map()
The map method is used to return a stream consisting of the results of applying the given
function to the elements of this stream.
List number = Arrays.asList(2,3,4,5);
List square = number.stream().map(x->x*x).collect(Collectors.toList());

sorted()
The sorted method is used to sort the stream.

List names = Arrays.asList("Reflection","Collection","Stream");


List result = names.stream().sorted().collect(Collectors.toList());

collect()
The collect method is used to return the result of the intermediate operations performed on the
stream.

List number = Arrays.asList(2,3,4,5,3);


Set square = number.stream().map(x->x*x).collect(Collectors.toSet());

forEach()
The forEach method is used to iterate through every element of the stream.

List number = Arrays.asList(2,3,4,5);


number.stream().map(x->x*x).forEach(y->System.out.println(y));

reduce()
The reduce method is used to reduce the elements of a stream to a single value. The reduce
method takes a BinaryOperator as a parameter.

List number = Arrays.asList(2,3,4,5);


int even = number.stream().filter(x->x%2==0).reduce(0,(ans,i)-> ans+i);
Benefit of Java Stream
There are some benefits because of which we use Stream in Java as mentioned below:
 No Storage
 Pipeline of Functions
 Laziness
 Can be infinite
 Can be parallelized
 Can be created from collections, arrays, Files Lines, Methods in Stream, IntStream etc.

You can use stream to iterate any number of times. Stream provides predefined methods to deal
with the logic you implement. In the following example, we are iterating, filtering and passed a
limit to fix the iteration.

import java.util.stream.*;
public class JavaStreamExample
{
public static void main(String[] args)
{
Stream.iterate(1, element->element+1)
.filter(element->element%5==0)
.limit(5)
// .map(element->element*element)
// .sorted()
.forEach(System.out::println);
}
} Output:
5
10
15
20
25

=== Code Execution Successful ===


In the following example, we are filtering data without using stream. This approach we are
used before the stream package was released.
import java.util.*;
class A
{
int id;
String name;
float price;

public A(int id, String name, float price)


{
this.id = id;
this.name = name;
this.price = price;
}
}
public class B
{
public static void main(String[] args)
{
List<A> pl = new ArrayList<A>();
//Adding Products
pl.add(new A(1,"HP Laptop",25000f));
pl.add(new A(2,"Dell Laptop",30000f));
pl.add(new A(3,"Lenevo Laptop",28000f));
pl.add(new A(4,"Sony Laptop",28000f));
pl.add(new A(5,"Apple Laptop",90000f));
List<Float> productPriceList = new ArrayList<Float>();
for(A ob: pl)
{
// filtering data of list
if(ob.price<30000)
{
productPriceList.add(ob.price);
// adding price to a productPriceList
}
}
System.out.println(productPriceList); // displaying data
}
}

Output:
[25000.0, 28000.0, 28000.0]

=== Code Execution Successful ===

Here, we are filtering data by using stream. You can see that code is optimized and maintained.
Stream provides fast execution.
import java.util.*;
import java.util.stream.Collectors;
class A
{
int id;
String name;
float price;
public A(int id, String name, float price)
{
this.id = id;
this.name = name;
this.price = price;
}
}
public class B
{
public static void main(String[] args)
{
List<A> pl = new ArrayList<A>();
//Adding Products
pl.add(new A(1,"HP Laptop",25000f));
pl.add(new A(2,"Dell Laptop",30000f));
pl.add(new A(3,"Lenevo Laptop",28000f));
pl.add(new A(4,"Sony Laptop",28000f));
pl.add(new A(5,"Apple Laptop",90000f));
List<Float> productPriceList2 =pl.stream()
.filter(p -> p.price > 30000)// filtering data
.map(p->p.price) // fetching price
.collect(Collectors.toList()); // collecting as list
System.out.println(productPriceList2);
}
}
Output:
[100000.0, 90000.0]

=== Code Execution Successful ===


Java Default Methods
Java provides a facility to create default methods inside the interface. Methods which are defined
inside the interface and tagged with default are known as default methods. These methods are
non-abstract methods.
Java Default Method Example
In the following example, show is a functional interface that contains a default and an abstract
method. The concept of default method is used to define a method with default implementation.
You can override default method also to provide more specific implementation for the method.
interface abc
{
// Default method
default void say()
{
System.out.println("Hello, this is default method");
}
// Abstract method
void show(String msg);
}
public class A implements abc
{
public void show(String msg)
{ // implementing abstract method
System.out.println(msg);
}
public static void main(String[] args)
{
A ob = new A();
ob.say(); // calling default method
ob.show("Work is worship"); // calling abstract method

}
}
Output:
Hello, this is default method
Work is worship

=== Code Execution Successful ===


Static Methods inside Java 8 Interface
You can also define static methods inside the interface. Static methods are used to define utility
methods.
interface abc
{
// default method
default void say()
{
System.out.println("Hello, this is default method");
}
// Abstract method
void show(String msg);
// static method
static void display(String msg)
{
System.out.println(msg);
}
}
public class A implements abc
{
public void show(String msg)
{ // implementing abstract method
System.out.println(msg);
}
public static void main(String[] args)
{
A ob = new A();
ob.say(); // calling default method
ob.show("Work is worship"); // calling abstract method

abc.display("Helloooo..."); // calling static method


}
}
Output:
Hello, this is default method
Work is worship
Helloooo...

=== Code Execution Successful ===

Java Base64 Encode and Decode


Java provides a class Base64 to deal with encryption. You can encrypt and decrypt your data by
using provided methods. You need to import java.util.Base64 in your source file to use its
methods.
This class provides three different encoders and decoders to encrypt information at each level.
You can use these methods at the following levels.
Basic Encoding and Decoding
It uses the Base64 alphabet specified by Java in RFC 4648 and RFC 2045 for encoding and
decoding operations. The encoder does not add any line separator character. The decoder rejects
data that contains characters outside the base64 alphabet.
URL and Filename Encoding and Decoding
It uses the Base64 alphabet specified by Java in RFC 4648 for encoding and decoding operations.
The encoder does not add any line separator character. The decoder rejects data that contains
characters outside the base64 alphabet.
MIME
It uses the Base64 alphabet as specified in RFC 2045 for encoding and decoding operations. The
encoded output must be represented in lines of no more than 76 characters each and uses a
carriage return '\r' followed immediately by a linefeed '\n' as the line separator. No line separator
is added to the end of the encoded output. All line separators or other characters not found in the
base64 alphabet table are ignored in decoding operation.

Class Description

Base64.Decoder This class implements a decoder for decoding byte data using the Base64
encoding scheme as specified in RFC 4648 and RFC 2045.

Base64.Encoder This class implements an encoder for encoding byte data using the
Base64 encoding scheme as specified in RFC 4648 and RFC 2045.
Base64 Methods

Methods Description

public static Base64.Decoder It returns a Base64.Decoder that decodes using the Basic
getDecoder() type base64 encoding scheme.

public static Base64.Encoder It returns a Base64.Encoder that encodes using the Basic
getEncoder() type base64 encoding scheme.

public static Base64.Decoder It returns a Base64.Decoder that decodes using the URL
getUrlDecoder() and Filename safe type base64 encoding scheme.

public static Base64.Decoder It returns a Base64.Decoder that decodes using the MIME
getMimeDecoder() type base64 decoding scheme.

public static Base64.Encoder It Returns a Base64.Encoder that encodes using the MIME
getMimeEncoder() type base64 encoding scheme.

Base64.Decoder Methods

Methods Description

public byte[] decode(byte[] src) It decodes all bytes from the input byte array using
the Base64 encoding scheme, writing the results into
a newly-allocated output byte array. The returned
byte array is of the length of the resulting bytes.

public byte[] decode(String src) It decodes a Base64 encoded String into a newly-
allocated byte array using the Base64 encoding
scheme.

public int decode(byte[] src, It decodes all bytes from the input byte array using
byte[] dst) the Base64 encoding scheme, writing the results into
the given output byte array, starting at offset 0.

Public ByteBuffer It decodes all bytes from the input byte buffer using
decode(ByteBuffer buffer) the Base64 encoding scheme, writing the results into
a newly-allocated ByteBuffer.

public InputStream It returns an input stream for decoding Base64


wrap(InputStream is) encoded byte stream.
Base64.Encoder Methods

Methods Description

public byte[] encode(byte[] src) It encodes all bytes from the specified byte array into
a newly-allocated byte array using the Base64
encoding scheme. The returned byte array is of the
length of the resulting bytes.

public int encode(byte[] src, It encodes all bytes from the specified byte array
byte[] dst) using the Base64 encoding scheme, writing the
resulting bytes to the given output byte array,
starting at offset 0.

public String It encodes the specified byte array into a String using
encodeToString(byte[] src) the Base64 encoding scheme.

public ByteBuffer It encodes all remaining bytes from the specified


encode(ByteBuffer buffer) byte buffer into a newly-allocated ByteBuffer using
the Base64 encoding scheme. Upon return, the
source buffer's position will be updated to its limit;
its limit will not have been changed. The returned
output buffer's position will be zero and its limit will
be the number of resulting encoded bytes.

public OutputStream It wraps an output stream for encoding byte data


wrap(OutputStream os) using the Base64 encoding scheme.

public Base64.Encoder It returns an encoder instance that encodes


withoutPadding() equivalently to this one, but without adding any
padding character at the end of the encoded byte
data.

import java.util.Base64;
public class A
{
public static void main(String[] args)
{
// Getting encoder
Base64.Encoder encoder = Base64.getUrlEncoder();

// Encoding URL
String str = encoder.encodeToString("http://www.google.com/".getBytes());
System.out.println("Encoded URL: "+str);

// Getting decoder
Base64.Decoder decoder = Base64.getUrlDecoder();

// Decoding URl
String str1 = new String(decoder.decode(str));
System.out.println("Decoded URL: "+str1);
}
}

Output:
Encoded URL: aHR0cDovL3d3dy5nb29nbGUuY29tLw==
Decoded URL: http://www.google.com/

=== Code Execution Successful ===

The try-with-resources statement

try-with-resources was introduced in Java 7 that allows us to declare resources to be used in


a try block with the assurance that the resources will be closed after the execution of that block..

In Java, the Try-with-resources statement is a try statement that declares one or more
resources in it. A resource is an object that must be closed once your program is done using it.
For example, a File resource or a Socket connection resource. The try-with-resources
statement ensures that each resource is closed at the end of the statement execution. If we don’t
close the resources, it may constitute a resource leak and also the program could exhaust the
resources available to it.

You can pass any object as a resource that implements java.lang.AutoCloseable, which
includes all objects which implement java.io.Closeable.

By this, now we don’t need to add an extra finally block for just passing the closing statements
of the resources. The resources will be closed as soon as the try-catch block is executed.

Exceptions:
When it comes to exceptions, there is a difference in try-catch-finally block and try-with-
resources block. If an exception is thrown in both try block and finally block, the method
returns the exception thrown in finally block.

For try-with-resources, if an exception is thrown in a try block and in a try-with-resources


statement, then the method returns the exception thrown in the try block. The exceptions
thrown by try-with-resources are suppressed, i.e. we can say that try-with-resources block
throws suppressed exceptions.

Now, let us discuss both the possible scenarios which are demonstrated below as an example as
follows:

 Case 1: Single resource


 Case 2: Multiple resources

Until java 1.6version it is highly recommended to write finally block to close resources which
are open as a part of try block

1. Programmer is required to close resource inside the finally block. It increases the
complexity of programing.
2. We have to write the finally block compulsory and hence it increases the length of the
code

To overcome the above problem java introduced try with resource in Java 1.7 version.

The main advantage with try with resource is whatever resources we open as a part of try
block will be closed automatically once control reaches end of the try block either normally
or abnormally and hence we are not required to close explicitly so that complexity of the
programing should be reduced.

We are not required to write finally block so that length of the code will be reduced.

Java 1.6

try

use resources

catch()

handle exception
}

finally

close resources

Java 1.7

try(resources)

use resources

catch()

handle resources

Example

import java.io.InputStream;

import java.io.DataInputStream;

import java.io.FileInputStream;

import java.io.FileOutputStream;

public class TRE1

public static void main(String args[])

// Using try-with-resources
try(FileOutputStream ob =new FileOutputStream("C:\\Users\\MY
COMPUTER\\Desktop\\abc.txt"))

String msg = "Welcome to the jungle";

byte byteArray[] = msg.getBytes(); //converting string into byte array

ob.write(byteArray);

System.out.println("Message written to file successfuly!");

catch(Exception exception)

System.out.println(exception);

Output:

Multiple resources
We can declare multiple resouirces but these resources should be saperated with semi column
try(Resourse1, Resource2, Resource3)
{
}
Resources we can use
1. All resources should be AutoClosable resources
2. A resource is said to be auto closable if and only if corresponding class implements
java.lang.AutoClosable interface.
3. All IO related resources, database resources and network related resources are already
implemented auto closable interface.
4. Auto closable interface came in version 1.7 and it contain only one method public void
close
Example with multiple resource
/ Java program for try-with-resources
// having multiple resources

// Importing all input output classes


import java.io.*;

// Class
class GFG {

// Main driver method


public static void main(String[] args)
{
// Try block to check for exceptions

// Writing data to a file using FileOutputStream


// by passing input file as a parameter
try (FileOutputStream fos
= new FileOutputStream("outputfile.txt");

// Adding resource

// Reading the stream of character from


BufferedReader br = new BufferedReader(
new FileReader("gfgtextfile.txt"))) {
// Declaring a string holding the
// stream content of the file
String text;

// Condition check using readLine() method


// which holds true till there is content
// in the input file
while ((text = br.readLine()) != null) {

// Reading from input file passed above


// using getBytes() method
byte arr[] = text.getBytes();

// String converted to bytes


fos.write(arr);

// Copying the content of passed input file


// 'inputgfgtext' file to outputfile.txt
}

// Display message when


// file is successfully copied
System.out.println(
"File content copied to another one.");
}

// Catch block to handle generic exceptions


catch (Exception e) {

// Display the exception on the


// console window
System.out.println(e);
}

// Display message for successful execution of the


// program
System.out.println(
"Resource are closed and message has been written into the gfgtextfile.txt");
}
}
Output:
File content copied to another one.
Resource are closed and message has been written into the gfgtextfile.txt

Type & Repeating Annotation


Annotations are used to provide supplemental information about a program.
 Annotations start with ‘@’.
 Annotations do not change the action of a compiled program.
 Annotations help to associate metadata (information) to the program elements i.e.
instance variables, constructors, methods, classes, etc.
 Annotations are not pure comments as they can change the way a program is treated by
the compiler. See below code for example.
 Annotations basically are used to provide additional information, so could be an
alternative to XML and Java marker interfaces.
Categories of Annotations
There are broadly 5 categories of annotations as listed:
1. Marker Annotations
2. Single value Annotations
3. Full Annotations
4. Type Annotations
5. Repeating Annotations

Java Type Annotations


Java 8 has included two new features repeating and type annotations.
In early Java versions, you can apply annotations only to declarations. After releasing of Java
SE 8 , annotations can be applied to any type use.
It means that annotations can be used anywhere you use a type. For example, if you want to
avoid NullPointerException in your code, you can declare a string variable like this:

1. @NonNull String str;


2. @NonNull List<String>
3. List<@NonNull String> str

The @Target annotation in Java is part of the java.lang.annotation package. This annotation is
used to specify the kinds of program elements to which an annotation type is applicable.

Syntax:
import java.lang.annotation.ElementType;
import java.lang.annotation.Target;

// Define a custom annotation with a target


@Target(ElementType.TYPE_USE)
@interface NonNull { }

Example
// Java Program to Demonstrate Type Annotation

// Importing required classes


import java.lang.annotation.ElementType;
import java.lang.annotation.Target;

// Using target annotation to annotate a type


@Target(ElementType.TYPE_USE)

// Declaring a simple type annotation


@interface demo{}

// Main class
public class A
{
// Annotating return type of a function
static @demo int abc() {
System.out.println("This function's return type is annotated");

return 0;
}
// Main driver method
public static void main(String[] args) {

// Annotating the type of a string


@demo String str = "I am annotated with a type annotation";
System.out.println(str);
abc();
}
}

Output:
I am annotated with a type annotation
This function's return type is annotated

=== Code Execution Successful ===

Java Repeating Annotations


In Java 8 release, Java allows you to repeating annotations in your source code. It is helpful when
you want to reuse annotation for the same class. You can repeat an annotation anywhere that you
would use a standard annotation.

For compatibility reasons, repeating annotations are stored in a container annotation that is
automatically generated by the Java compiler. In order for the compiler to do this, two
declarations are required in your code.

1. Declare a repeatable annotation type


2. Declare the containing annotation type
Declare a repeatable annotation type

@Repeatable(Games.class)
@interfaceGame{
String name();
String day();
}

The value of the @Repeatable meta-annotation, in parentheses, is the type of the container
annotation that the Java compiler generates to store repeating annotations. In the following
example, the containing annotation type is Games. So, repeating @Game annotations is stored
in an @Games annotation.

Declare the containing annotation type


Containing annotation type must have a value element with an array type. The component type
of the array type must be the repeatable annotation type. In the following example, we are
declaring Games containing annotation type:

@interfaceGames{
Game[] value();
}

Step 1: Define the Annotation - First, define the repeatable annotation and its container.
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
import java.lang.annotation.ElementType;
import java.lang.annotation.Repeatable;

// Define the repeatable annotation


@Repeatable(Schedules.class)
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface Schedule {
String day();
String time();
}

// Define the containing annotation


@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface Schedules {
Schedule[] value();
}

Step 2: Use the Repeating Annotation - Now you can use the @Schedule annotation multiple
times on the same element.
public class A {

// Apply the repeatable annotation multiple times


@Schedule(day = "Monday", time = "09:00")
@Schedule(day = "Wednesday", time = "10:00")
@Schedule(day = "Friday", time = "11:00")
public void scheduledMethod() {
// Method implementation
}
}
Module System
Java Module System is a major change in Java 9 version. Java added this feature to
collect Java packages and code into a single unit called module.
In earlier versions of Java, there was no concept of module to create modular Java applications,
that why size of application increased and difficult to move around. Even JDK itself was too
heavy in size, in Java 8, rt.jar file size is around 64MB.
To deal with situation, Java 9 restructured JDK into set of modules so that we can use only
required module for our project.
Apart from JDK, Java also allows us to create our own modules so that we can develop module
based application.
The module system includes various tools and options that are given below.
o includes various options to the Java tools javac, jlink and java where we can specify
module paths that locates to the location of module.
o Modular JAR file is introduced. This JAR contains module-info.class file in its root
folder.
o JMOD format is introduced, which is a packaging format similar to JAR except it can
include native code and configuration files.
o The JDK and JRE both are reconstructed to accommodate modules. It improves
performance, security and maintainability.
o Java defines a new URI scheme for naming modules, classes and resources.

Java 9 Module
Java added this feature to collect java packages and codes into a single unit called module.
Module is a collection of Java programs or software. To describe a module, a Java file module-
info.java is required. This file also known as module descriptor and defines the following

o Module name
o What does it export
o What does it require

Module Name
It is a name of module and should follow the reverse-domain-pattern. Like we name packages,
e.g. com.Package

How to create Java module


Creating Java module required the following steps.

o Create a directory structure


o Create a module discriptor
o Java source code

Create a Directory Structure


To create module, it is recommended to follow given directory structure, it is same as reverse-
domain-pattern, we do to create packages / project-structure in Java.

Create a file module-info.java, inside this file, declare a module by using module identifier
and provide module name same as the directory name that contains it.
In our case, our directory name is com.javamodule
This is module descriptor file (empty module)
module com.javamodule
{

}
Leave module body empty, if it does not has any module dependency. Save this file
inside Java 9 space/com.javatpoint with module-info.java name.

Java Source Code


Now, create a Java file to compile and execute module. In our example, we have
a Hello.java file that contains the following code.
package com.javamodule;
public class Greeting
{
public static void main(String[] args)
{
System.out.println("Welcome to Jungle");
}
}
Save this file inside Java9 space/com.javamodule/com/javamodule/
with Greeting.java name.
Compile Java Module
To compile the module use the following command.
1. javac -d mods --module-source-path src/ --module com.javamodule
2. mods is the module name that is going to be created after running this compile
command.
After compiling, it will create a new directory that contains the following structure.

Run Module
To run the compiled module, use the following command.
java --module-path mods/ --module com.javamodule/com.javamodule.Greeting
Output:
Welcome to the Jungle

Anonymous Class

class A

public void show()

System.out.println("Class A");
}

class B extends A

public void show()

System.out.println("Class B");

public class C

public static void main(String args[])

A ob=new B();

ob.show();

Output:

Class B

=== Code Execution Successful ===

class A

public void show()

{
System.out.println("Class A");

public class C

public static void main(String args[])

A ob=new A()

public void show()

System.out.println("Class B");

};

ob.show();

Output:

Class B

=== Code Execution Successful ===

Diamond Operator

Java 9 introduced a new feature that allows us to use diamond operator with anonymous classes.
Using the diamond with anonymous classes was not allowed in Java 7.
In Java 9, as long as the inferred type is denotable, we can use the diamond operator when we
create an anonymous inner class.

In Java, the diamond syntax (<>) is used to simplify the instantiation of generic classes by
allowing the compiler to infer the type parameters. When using inner anonymous classes, you
can still take advantage of the diamond syntax.

With the help of Diamond operator, we can create an object without mentioning the generic type
on the right hand side of the expression.

public class A extends ABCD<Integer>

public Integer show(Integer a, Integer b)

return a + b;

Example:

abstract class ABCD<T>

abstract T show(T a, T b);

public class A

public static void main(String[] args)

ABCD<String> a = new ABCD<>()

{
// diamond operator is empty, compiler infer type

String show(String a, String b)

return a+b;

};

String result = a.show("Java ","9");

System.out.println(result);

Output:

Java 9

=== Code Execution Successful ===

In Java, the method declaration abstract T show(T a, T b); has the following components:

1. abstract : This keyword indicates that the method is abstract and does not have a body. It
must be implemented by any concrete subclass of the class that contains this method.
2. T: This represents a generic type parameter. The method is part of a generic class or
interface, and T is a placeholder for the actual type that will be specified when the class
or interface is instantiated.
3. show : This is the name of the method.
4. (T a, T b): These are the parameters of the method. Both a and b are of type T.

Local Variable Type Inference or LVTI in Java 10

Type inference refers to the automatic detection of the datatype of a variable, done generally at
the compiler time.

Local variable type inference is a feature in Java 10 that allows the developer to skip the type
declaration associated with local and the type is inferred by the JDK. It will, then, be the job of
the compiler to figure out the datatype of the variable.

Till Java 9, to define a local variables of class type, the following was the only correct syntax:
Class_name variable_name=new Class_name(arguments);

Local variable – Deals with local variables only

Type Inference – Java compiler infers the type for you instead of us writing the type.

public class A

public void display()

String name= “ABC”;

Can be written as

public class A

public void display()

var name= “ABC”;

var age=12;

100% compile feature with no side effect in terms of bytecode, runtime or performance.

Instead of mentioning the variable datatype on the left-side, before the variable, LVTI
allows you to simply put the keyword ‘var’. For example,
// Java code for Normal local

// variable declaration

import java.util.ArrayList;

import java.util.List;

class A {

public static void main(String ap[])

List<Map> data = new ArrayList<>();

Can be re-written as:

// Java code for local variable

// declaration using LVTI

import java.util.ArrayList;

import java.util.List;

class A {

public static void main(String ap[])

var data = new ArrayList<>();

Use Cases

Here are the cases where you can declare variables using LVTI:

1. In a static/instance initialization block


// Declaration of variables in static/init

// block using LVTI in Java 10

class A {

static

var x = "Hi there";

System.out.println(x)'

public static void main(String[] ax)

Output: Oh hi there

Use Cases

1. In a static/instance initialization block

// Declaration of variables in static/init

// block using LVTI in Java 10

class A {

static

var x = "Hi there";

System.out.println(x)'
}

public static void main(String[] ax)

Output:
Oh hi there

2. As a local variable

// Declaration of a local variable in java 10 using LVTI

class A {

public static void main(String a[])

{ var x = "Hi there";

System.out.println(x)

}}

Output: Hi there

3. As iteration variable in enhanced for-loop

// Declaring iteration variables in enhanced for loops using LVTI in Java

class A {
public static void main(String a[])

int[] arr = new int[3];

arr = { 1, 2, 3 };

for (var x : arr)

System.out.println(x + "\n");

Output:
1
2
3

4. As looping index in for-loop

// Declaring index variables in for loops using LVTI in Java

class A {

public static void main(String a[])

int[] arr = new int[3];

arr = { 1, 2, 3 };

for (var x = 0; x < 3; x++)


System.out.println(arr[x] + "\n");

Output:
1
2
3

5. As a return value from another method

// Storing the return value of a function in a variable declared with LVTI

class A {

int ret()

{ return 1;

public static void main(String a[])

{ var x = new A().ret();

System.out.println(x);

Output:
1

6. As a return value in a method


// Using a variable declared

//using the keyword 'var' as a return value of a function

class A {

int ret()

var x = 1;

return x;

public static void main(String a[])

System.out.println(new A().ret());

Output:
1

Switch Expressions

An easy way to differentiate between switch expressions and switch statements is that switch
expressions cannot have break in them, and switch statements cannot have yield in them.

Like all expressions, switch expressions evaluate to a single value and can be used in statements.

They may contain "case L ->" labels that eliminate the need for break statements to prevent fall
through.

You can use a yield statement to specify the value of a switch expression.
"case L ->" Labels

Consider the following switch statement that prints the number of letters of a day of the week:

public enum Day { SUNDAY, MONDAY, TUESDAY,

WEDNESDAY, THURSDAY, FRIDAY, SATURDAY; }

// ...

int numLetters = 0;

Day day = Day.WEDNESDAY;

switch (day) {

case MONDAY:

case FRIDAY:

case SUNDAY:

numLetters = 6;

break;

case TUESDAY:

numLetters = 7;

break;

case THURSDAY:

case SATURDAY:

numLetters = 8;

break;

case WEDNESDAY:

numLetters = 9;

break;

default:
throw new IllegalStateException("Invalid day: " + day);

System.out.println(numLetters);

It would be better if you could "return" the length of the day's name instead of storing it in the
variable numLetters; you can do this with a switch expression. Furthermore, it would be better
if you didn't need break statements to prevent fall through; they are laborious to write and easy
to forget. You can do this with a new kind of case label. The following is a switch expression
that uses the new kind of case label to print the number of letters of a day of the week:

Day day = Day.WEDNESDAY;

System.out.println(

switch (day) {

case MONDAY, FRIDAY, SUNDAY -> 6;

case TUESDAY -> 7;

case THURSDAY, SATURDAY -> 8;

case WEDNESDAY -> 9;

default -> throw new IllegalStateException("Invalid day: " + day);

);

The new kind of case label has the following form:

case label_1, label_2, ..., label_n -> expression;|throw-statement;|block

"case L:" Statements and the yield Statement

The yield keyword lets us exit a switch expression by returning a value that becomes the value
of the switch expression.

This means we can assign the value of a switch expression to a variable.

yield with Arrow Operator

To start, let’s say we have the following enum and switch statement:
public enum Number {

ONE, TWO, THREE, FOUR;

String message;

switch (number) {

case ONE:

message = "Got a 1";

break;

case TWO:

message = "Got a 2";

break;

default:

message = "More than 2";

Let’s convert this to a switch expression and use the yield keyword along with the arrow operator:

String message = switch (number) {

case ONE -> {

yield "Got a 1";

case TWO -> {

yield "Got a 2";

default -> {

yield "More than 2";


}

};

yield with Colon Delimiter

String message = switch (number) {

case ONE:

yield "Got a 1";

case TWO:

yield "Got a 2";

default:

yield "More than 2";

};

Java Text Blocks

Since Java 15, text blocks are available as a standard feature.

Text blocks start with a “”” (three double-quote marks)

The simplest example looks like this:

String example = """

Example text""";

In this article, we are going to discuss the Java 15 text blocks feature to declare multi-line strings
most efficiently.

We all know that how we can declare multi-line strings and that too quite easily with the help of
concatenation, string’s join method, StringBuilder append method, etc.

Why text block

In earlier releases of the JDK, embedding multi-line code snippets required a tangled mess of
explicit line terminators, string concatenations, and delimiters.

Text blocks eliminate most of these obstructions, allowing you to embed code snippets and text
sequences more or less as-is.
A text block is an alternative form of Java string representation that can be used anywhere a
traditional double-quoted string literal can be used. Text blocks begin with a “”” (3 double-quote
marks) followed by optional whitespaces and a newline.

For example:

// Using a literal string

String text1 = "Geeks For Geeks";

// Using a text block

String text2 = """

Geeks For Geeks""";

Text blocks may be utilized in the region of a string literal to enhance the clarity and readability
of the code.

This typically takes place whilst a string literal is used to symbolize a multi-line string.

In this example there’s a substantial muddle from citation marks, newline escapes, and
concatenation operators:

// ORIGINAL

String message = "A-143, 9th Floor, Sovereign Corporate Tower,\n" +

"Sector-136, Noida,\n" +

"Uttar Pradesh - 201305";

// BETTER : Using text blocks

// gets rid of lots of the clutter

String message = """

A-143, 9th Floor, Sovereign Corporate Tower,

Sector-136, Noida,

Uttar Pradesh - 201305""";


Java Records

In Java, a record is a special type of class declaration aimed at reducing the boilerplate code.

Java records were introduced with the intention to be used as a fast way to create data carrier
classes, i.e. the classes whose objective is to simply contain data and carry it between modules,
also known as POJOs (Plain Old Java Objects) and DTOs (Data Transfer Objects).

Record was introduced in Java SE 14 as a preview feature, which is a feature whose design,
implementation, and specification are complete but it is not a permanent addition to the language,
which means that the feature may or may not exist in the future versions of the language.

Java SE 15 extends the preview feature with additional capabilities such as local record classes.

Why Record

Consider a simple class Employee, whose objective is to contain an employee’s data such as its
ID and name and act as a data carrier to be transferred across modules.

To create such a simple class, you’d need to define its constructor, getter, and setter methods,
and if you want to use the object with data structures like HashMap or print the contents of its
objects as a string, we would need to override methods such as equals(), hashCode(), and
toString().

// Java Program Illustrating Program Without usage of

// Records

// A sample Employee class

class Employee {

// Member variables of this class

private String firstName;

private String lastName;

private int Id;

// Constructor of this class

public Employee(String firstName, String lastName, int Id)

{
// This keyword refers to current instance itself

this.firstName = firstName;

this.lastName = lastName;

this.Id = Id;

// Setter and Getter methods

// Setter-getter Method 1

public void setFirstName(String firstName)

this.firstName = firstName;

// Setter-getter Method 2

// to get the first name of employee

public String getFirstName() { return firstName; }

// Setter-getter Method 3

// To set the last name of employees

public void setLastName(String lasstName)

this.lastName = lastName;

// Setter-getter Method 3

// To set the last name of employees

public String getLastName() { return lastName; }


// Setter-getter Method 4

// To set the last name of employees

public void setId(int Id) { this.Id = Id; }

// Setter-getter Method 5

// To set the last name of employees

public int getId() { return Id; }

// Setter-getter Method 6

public String toString()

// Return the attributes

return "Employee [firstName=" + firstName

+ ", lastName=" + lastName + ", Id=" + Id + "]";

// Method 7

// Overriding hashCode method

@Override public int hashCode()

// Final variable

final int prime = 31;

int result = 1;

result = prime * result + Id;

result = prime * result + ((firstName == null)? 0: firstName.hashCode());


result = prime * result+ ((lastName == null) ? 0: lastName.hashCode());

return result;

// Method 8

// Overriding equals method to

// implement with data structures

@Override public boolean equals(Object obj)

// This refers to current instance itself

if (this == obj)

return true;

if (obj == null)

return false;

if (getClass() != obj.getClass())

return false;

Employee other = (Employee)obj;

if (Id != other.Id)

return false;

if (firstName == null) {

if (other.firstName != null)

return false;

else if (!firstName.equals(other.firstName))

return false;

if (lastName == null) {
if (other.lastName != null)

return false;

else if (!lastName.equals(other.lastName))

return false;

return true;

Some more Properties of Records

 You can use nested classes and interfaces inside a record.


 You can have nested records too, which will implicitly be static.
 A record can implement interfaces.
 You can create a generic record class.
 It is possible to use local record classes (since Java SE 15).
 Records are serializable.

Steps in setting up java records

Step 1: Create a new Java project and select JavaSE-14 as the execution environment.
Step 2: If this is your first time using JDK-14 then there will be some more steps that you’ll need
to follow in order to configure for records to work. You might see this type of exception mark
on your project folder.
Step 3: To fix that, on the top, go to Window -> Preferences.

Step 4: In the Preferences window, click on Installed JREs and then click on Add as shown
below:
Step 5: Now on the Add JRE window that opens, select Standard VM and click Next. You’ll see
a new window open to select a JRE, now click on Directory and navigate to where your jdk-14
is installed and select that folder. Click on Finish.
Step 6: Checkmark the JDK-14 that you just added and Apply it.
Step 7: We are not done yet. Since records are a preview feature, we need to enable them to use
it. On your Project Explorer window on the left side, select your project and right-click and go
to its Properties.

Step 8: On the window that opens, to the right of it, from the various options select Java
Compiler. After that on the left side, uncheck the settings marked with red arrows in the image,
and check mark the setting highlighted with green. Doing that will enable the preview features.
Step 9: After clicking on Apply and Close, you’ll see a prompt asking whether you want to
rebuild the project. Select Yes.

Sealed Class in Java

Java 15 introduced the concept of sealed classes. It is a preview feature. Java sealed classes and
interfaces restrict that which classes and interfaces may extend or implement them.

In other words, we can say that the class that cannot be inherited but can be instantiated is known
as the sealed class

Uses of Sealed Class

Sealed classes work well with the following:

o Java Reflection API


o Java Records
o Pattern Matching

Advantages of Sealed Class and Interface

o It allows permission to the subclasses that can extend the sealed superclass.
o It makes superclass broadly accessible but not broadly extensible.
o It allows compilers to enforce the type system on the users of the class.
o Developer of a superclass gets control over the subclasses. Hence, they can define
methods in a more restricted way.

Defining a Sealed Class

The declaration of a sealed class is not much complicated. If we want to declare a class as sealed,
add a sealed modifier to its declaration. After the class declaration and extends and implements
clause, add permits clause. The clause denotes the classes that may extend the sealed class.

o It presents the following modifiers and clauses:


o sealed: It can only be extended by its permitted subclasses.
o non-sealed: It can be extended by unknown subclasses; a sealed class cannot prevent its
permitted subclasses from doing this.
o permits: It allows the subclass to inherit and extend.
o final: The permitted subclass must be final because it prevents further extensions.

For example, the following declaration of Subjects class specifies four permitted subclasses,
English, Science, Mathematics, and Physics.

Subjects.java

//declaration of the sealed class


public sealed class Subjects
permits English, Science, Mathematics, Physics {
}

Let's define the four permitted subclasses, English, Science, Mathematics, and Physics, in the
same module or package in which the sealed class is defined.

English.java

public final class English extends Subjects {


public double percentage;
}

Science.java

public non-sealed class Science extends Subjects {


public String grade;
}

Mathematics.java

public sealed class Mathematics extends Subjects permits AppliedMathematics {


public double percentage;
public String grade;
}

The Mathematics class has a further subclass, AppliedMathematics:

AppliedMathematics.java

public final class AppliedMathematics extends Mathematics {


public int marks;
public String grade;
public double percentage;
}

Physics.java

public non-sealed class Physics extends Subjects {


public int marks;
}

On the other hand, we can also define permitted subclasses in the same file as the sealed class.
In such a case, we can omit the permits clause:

//declaration of the sealed class


public sealed class Subjects
permits English, Science, Mathematics, Physics {
}
public final class English extends Subjects {
public double percentage;
}
public non-sealed class Science extends Subjects {
public String grade;
}
public sealed class Mathematics extends Subjects permits AppliedMathematics {
public double percentage;
public String grade;
}
public final class AppliedMathematics extends Mathematics {
public int marks;
public String grade;
public double percentage;
}
public non-sealed class Physics extends Subjects {
public int marks;
}

You might also like