0% found this document useful (0 votes)
862 views19 pages

JAVA NEW FEATURES Unit-3

unit 3 notes java aktu

Uploaded by

ashmakhan8855
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd
0% found this document useful (0 votes)
862 views19 pages

JAVA NEW FEATURES Unit-3

unit 3 notes java aktu

Uploaded by

ashmakhan8855
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd
You are on page 1/ 19

Unit - 3

JAVA NEW FEATURES


There are many new features that have been added in java. There are major
enhancement made in Java5, Java6, Java7,Java8, Java 9 etc.
Java 8 is the most awaited release of Java programming language development
because, in the entire history of Java, it never releases that many major
features. It consists of major features of Java. It is a new version of Java and
was released by Oracle on 18 March 2014. Java provided support for functional
programming, new Java 8 APIs, a new JavaScript engine, new Java 8 streaming
API, functional interfaces, default methods etc.

Java 8 Features
• Lambda Expressions
• Functional Interfaces
• Method Reference
• Streams
• Default method
• Static method
• ForEach method

Lambda Expression: Java Lambda Expression is a way to define an


anonymous function or method that can be passed around as a value. It allows
you to write code that is more concise, flexible, and easier to read.
Lambda expressions in Java have the following syntax:
(parameters) -> expression
Or
(parameters) -> { statements; }
Here, the “parameters” specify the input arguments for the anonymous
function, and the “expression” or “statements” specify the behavior of the
function.
The arrow symbol “->“ separates the parameters from the body of the
function.
Note: A lambda expression in Java can take any number of arguments. So, the
above syntax could also look like below:
For zero parameters: () -> expression
For single parameters: (parameters) -> expression
For multiple parameters: (parameter1, parameter2,…,parameterN) ->
expression
Example 1
Using Lambda Expression
Public void m1(){
System.out.println(“Hello”); () -> System.out.println(“Hello”);
}
Example 2:

Public void m1(int a, int b ){ (a, b) -> System.out.println(a+b);


System.out.println(a+b);
}

Example 3:
(n)->{ return n*n; }
public int square(int a){ Or
return n*n; (n)-> n*n;
} n-> n*n;

Functional Interfaces
An interface with exactly one abstract method is called Functional Interface.
@FunctionalInterface annotation is added so that we can mark an interface as
functional interface. It is not mandatory to use it, but it’s best practice to use it
with functional interfaces to avoid addition of extra methods accidentally.
If the interface is annotated with @FunctionalInterface annotation and we try
to have more than one abstract method, it throws compiler error. you can have
n number of default and static methods inside a functional interface.
Example:
@FunctionalInterface
Interface A { public void m1(); }
Lambda Expression with Functional Interface: The Lambda expression is used
to provide the implementation of an interface which has functional interface. It
saves a lot of code. In case of lambda expression, we don't need to define the
method again for providing the implementation. Here, we just write the
implementation code.
Example:
interface Interf{
public void add(int a, int b); }
class Test{
public static void main(String[] args){
// lambda Expression implementation
Interf i = (a,b)->System.out.println("Sum is-----"+ (a+b));
i.add(10,20); } }

Method Reference
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: You can refer to static method defined in
the class. Following is the syntax and example which describe the
process of referring static method in Java.
interface Sayable{
void say(); }
public class MethodReference {
public static void saySomething(){
System.out.println("Hello, this is static method."); }
public static void main(String[] args) {
// Referring static method
Sayable sayable = MethodReference::saySomething;
// Calling interface method
sayable.say(); } }

2. Reference to an instance method: like static methods, you can refer


instance methods also. In the following example, we are describing the
process of referring the instance method.
interface Sayable{
void say(); }
public class InstanceMethodReference {
public void saySomething(){
System.out.println("Hello, this is non-static method."); }
public static void main(String[] args) {
InstanceMethodReference methodReference = new
InstanceMethodReference(); // Creating object
// Referring non-static method using reference
Sayable sayable = methodReference::saySomething;
// Calling interface method
sayable.say(); } }
3. Reference to a constructor: You can refer a constructor by using the new
keyword. Here, we are referring constructor with the help of functional
interface.
interface Messageable{
Message getMessage(String msg); }
class Message{
Message(String msg){
System.out.print(msg); } }
public class ConstructorReference {
public static void main(String[] args) {
Messageable hello = Message::new;
hello.getMessage("Hello constructor ref...."); } }
Interface Default and Static Methods
Interface in Java is a concept that is used to achieve abstraction. It contains
only abstract methods and does not provide any implementation but In Java 8,
Interface is improved by adding default and static methods.
For example, if several classes such as A, B, C and D implements an interface
Test (Interface name is Test) then if we add a new method to the Test, we have
to change the code in all the classes(A, B, C and D) that implements this
interface. In this example we have only four classes that implements the
interface which we want to change but imagine if there are hundreds of classes
implementing an interface then it would be almost impossible to change the
code in all those classes. This is why in java 8, we have a new concept "default
methods". These methods can be added to any existing interface and we do
not need to implement these methods in the implementation classes
Default Methods
Methods that are declared using the default keyword inside the interface are
known as default methods. These methods are non-abstract methods. The
reason behind adding the default method is to allow the developers to add
new methods to the interfaces without affecting the classes that implement
these interfaces.
interface Printable{
// Default method
default void print() {
System.out.println("Printing..."); }
// Abstract methods
void print3D(); }
public class Demo implements Printable {
public void print3D() {
System.out.println("Printing 3D...");
}
public static void main(String[] args){
Demo demo = new Demo();
// Calling Default Methods
demo.print();
// Calling Abstract Methods
demo.print3D(); }}
Static Methods
Like default methods interface allows adding static methods to it. We can
define static methods inside the interface using the static keyword.
interface Printable{
// Static method
static void print() {
System.out.println("Printing...");
}
// Abstract Method
void getInfo(); }
public class Demo implements Printable {
public void getInfo() {
System.out.println("This is new style Java 8 Interface");
}
public static void main(String[] args){
Demo demo = new Demo();
// Calling static Methods
Printable.print();
// Calling Abstract Methods
demo.getInfo(); }}
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.
Encode simple String into Basic Base 64 format
The Basic encoder uses the Base64 Alphabet for encoding and decoding. It will
not add any line separators to the encoded string. We will use the getEncoder()
method that returns a simple Base64.Encoder.

As discussed, this encoder uses the Basic type base64 encoding scheme. Next,
we will use the encodeToString() method. It takes a byte array as input and
returns an encoded string
String BasicBase64format=
Base64.getEncoder().encodeToString(“actualString”.getBytes());
Decode Basic Base 64 format to String
To decode an encoded string, we will use Base64.Decoder returned by the
getDecoder() method. Then, we will use the decode() method of the decoder. It
will take an encoded string as input and returns the decoded string.
byte[] actualByte= Base64.getDecoder().decode(encodedString);
String actualString= new String(actualByte);
Example
import java.util.Base64;
public class Demo{
public static void main(String args[]) {
String strToEncode = "Hello World";
//encoding
byte[] bytesToEncode = strToEncode.getBytes();
String encodedStr = Base64.getEncoder().encodeToString(bytesToEncode);
System.out.println("Encoded String: " + encodedStr);
//decoding
byte[] decodedByteArr = Base64.getDecoder().decode(encodedStr);
String decodedStr = new String(decodedByteArr);
System.out.println("Decoded String: " + decodedStr);
}}

Try-with-resources Try-with-resources is a feature introduced in Java 7 (JDK


1.7) to handle resource management automatically. It simplifies code and
ensures that resources are properly closed after use, preventing potential
resource leaks.
Resource Management: A resource is any object that must be closed after its
operations are completed. Common examples include file I/O streams,
database connections.
AutoCloseable Interface: For a resource to be used within a try-with-resources
statement, it must implement the AutoCloseable interface, which includes the
close() method.
import java.io.BufferedReader;
import java.io.FileReader;
import java.io.IOException;
public class TestBufferedReader {
public static void main(String[] args) {
try (FileReader fr = new FileReader("abc.txt");
BufferedReader br = new BufferedReader(fr) ) {
String line = br.readLine();
while (line !=null) {
System.out.println(line);
line = br.readLine(); }}
catch (IOException e) {
System.out.println("exception...."); } }}

Multiple resources can be managed within a single try-with-resources


statement, separated by semicolons.

Java 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.
Creating Java module required the following steps.
1. Create a directory structure
2. Create a module declarator
3. Java source code
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.
module com.Test{
}
Leave module body empty, if it does not has any module dependency. Save this
file inside src/com.Test with module-info.java name.
create a Java file to compile and execute module. In our example, we have a
Hello.java file that contains the following code.
class Hello{
public static void main(String[] args){
System.out.println("Hello from the Java module");
}
}

Declaring a Module:
module com.example.myapp {
requires java.logging; // Module dependency
requires com.example.util; // Another module dependency
exports com.example.myapp.api; // Exported package
}
requires: Specifies module dependencies.
exports: Makes a package accessible to other modules.
Benefits of JPMS
Explicit Dependencies: Dependencies between modules are explicitly declared,
making the module relationships clear and maintainable.
Enhanced Encapsulation: Internal implementation details can be hidden,
exposing only the necessary APIs.This reduces the risk of unintended
dependencies and enhances security.
Improved Performance: Smaller and more efficient runtime images can be
created by including only required modules.Faster startup times and reduced
memory footprint.
For example, modules like java.base (mandatory), java.sql, java.xml, etc.

Diamond Operator
Diamond operator ‘<>’ was introduced in JDK 7. The main objective of Diamond
Operator is to instantiate generic classes very easily.
Prior to Java 7, Programmer compulsory should explicitly include the Type of
generic class in the Type Parameter of the constructor.
ArrayList<String> l = new ArrayList<String>();
Whenever we are using Diamond Operator, then the compiler will consider the
type automatically based on context, Which is also known as Type inference.
We are not required to specify TypeParameter of the Constructor explicitly.
ArrayList<String> l = new ArrayList<>();
Hence the main advantage of Diamond Operator is we are not required to
speicfy the type parameter in the constructor explicitly,length of the code will
be reduced and readability will be improved.
Eg 2:
List<Map<String,Integer>> l = new ArrayList<Map<String,Integer>>();
can be writtern with Diamond operator as follows
List<Map<String,Integer>> l = new ArrayList<>();

Usage of Diamond Operator for Anonymous Classes


In JDK 9, Usage of Diamond Operator extended to Anonymous classes also.
Anonymous class:
Sometimes we can declare classes without having the name, such type of
nameless classes are called Anonymous Classes.
Eg 1:
Thread t = new Thread()
{
};
ArrayList<String> l = new ArrayList<>()
{
};
Local variable type inference
Local variable type inference is a feature in Java 10 that allows the type of a
variable to be automatically determined by the compiler based on the value
assigned to it. This feature simplifies code by reducing the need for explicit
type annotations, making it more readable and maintainable.
var variableName = initializer;
var number = 10; // The compiler infers that 'number' is of type int
var text = "Hello"; // The compiler infers that 'text' is of type String
Example:
public class LocalVariableTypeInferenceExample {
public static void main(String[] args) {
// Simple types
var i = 42; // Inferred as int
var text = "Hello, World!"; // Inferred as String
var j = 43;
var result = i+j;
System.out.println("Integer: " + i);
System.out.println("Text: " + text);
System.out.println("sum : " + result);
System.out.println("length: " + text.length()); }}

Switch Expression
Java 12 improved the traditional switch statement and made it more useful.
Java 13 further introduced new features. Utilizes case and -> for mapping
values, eliminating the need for break statements and reducing boilerplate
code and supports multiple values per case. Before going into the details of
new features, let’s have a look at the drawbacks faced by the traditional Switch
statement.
switch (item) {
case 001 :
System.out.println("It's a laptop!");
break;
case 002 :
System.out.println("It's a desktop!");
break;
default :
System.out.println("Unknown device!");
}
The above code works by matching the corresponding case and executing the
particular code block. As long as you provide the necessary break statements, it
works fine.
But what happens if we forget any of the required break statements:
switch (itemCode) {
case 001 :
System.out.println("It's a laptop!");
// missed out break here
case 002 :
System.out.println("It's a desktop!");
}
Here, if we pass 001, the first case matches, and the code block executes. But
due to missing break, execution falls through and continues for case 002. We
get the following wrong output:
Output: It's a laptop!
It's a desktop!
Multiple values per case not supported: There may be situations where similar
processing is required for multiple case values. But the traditional switch makes
to follow the fall through behaviors.
Upgraded Switch in Java 13
Enhancements to switch statements were introduced by Java 12 and then
further modified by Java 13.
1. Supports multiple values per case: With multiple values being specified
per case, it simplifies the code structure and eliminates the need for
using fall through.
The values need to be separated by commas and break should follow the
case block.
switch (itemCode) {
case 001, 002, 003 :
System.out.println("It's an electronic gadget!");
break;
case 004, 005:
System.out.println("It's a mechanical device!");
}
2. yield is used to return a value:
A new keyword yield has been introduced. It returns values from a
switch branch only. We don’t need a break after yield as it automatically
terminates the switch expression.
int val = switch (code) {
case "x", "y" :
yield 1;
case "z", "w" :
yield 2;
};
3. Switch can be used as an expression:
The switch can now be used as an expression. This means the switch can
now return values based on our input. There is a slight change in switch
syntax to accommodate this change. A switch block needs to be
delimited by a semicolon. The yield keyword is used to return values. No
break required with the yield statement.
4. Scope: The variables declared in the traditional switch exists until the
end of the switch statement. If we want the variables to have a case level
scope, we can use {} introduced by the enhanced switch in Java 13.
5. Switch with arrows: The new arrow ⇾ syntax has been introduced for
the switch. It can be used with the switch as an expression as well as a
statement. The statements on the right side of an ⇾ are executed if an
exact case matches on the left side.
On the right side of ⇾ we can have any of the following –
• Statement / expression
• throw statement
• {} block
public class SwitchExpressionExample {
public static void main(String[] args) {
int day = 6;
String dayName = switch (day) {
case 1 -> "Monday";
case 2 -> "Tuesday";
case 3 -> "Wednesday";
case 4 -> "Thursday";
case 5 -> "Friday";
case 6 -> "Saturday";
case 7 -> "Sunday";
default -> "Invalid day";
};
System.out.println("Day " + day + " is " + day Name); }}

Text Blocks
Java 15 Text Blocks are a new kind of string literal in Java that makes it easier to
write multi-line strings. They are enclosed in triple double-quotes ("""), which
allows developers to write strings that span multiple lines without the need for
escape sequences for special characters or new lines.
Multi-line Support: Traditional string literals require concatenation of multiple
strings or the use of escape characters for new lines. Text Blocks allow for
natural and readable multi-line strings.
Improved Readability: Text Blocks make the code more readable by preserving
the structure and indentation of the text.
Automatic Formatting: The leading and trailing whitespaces are automatically
managed. Leading whitespace on each line is removed based on the minimum
indentation level across all lines.
Text Blocks in Java provide a more readable and maintainable way to handle
multi-line strings. They are particularly useful for embedding structured data
like JSON, XML, HTML, and SQL queries within Java code. This feature enhances
the developer experience by reducing the need for escape sequences and
preserving the natural format of the text.

Example:
public class TestTextBlocks {
public static void main(String[] args) {
String textBlock = """
This is a text block.
It spans multiple lines.
No need for concatenation or escape sequences.
""";
System.out.println(textBlock);

String json = """


{
"name": "John",
"age": 30,
"city": "New York"
}
""";
System.out.println(json);

String example = """


This is a "text block" example.
To include triple quotes, use \"""
""";
System.out.println(example);
}
}

Output:
This is a text block.
It spans multiple lines.
No need for concatenation or escape sequences.

{
"name": "John",
"age": 30,
"city": "New York"
}

This is a "text block" example.


To include triple quotes, use """

Records
Record classes are a feature introduced in Java 14 as a preview and became a
standard feature in Java 16. They provide a concise way to create classes that
are primarily used to store data.
Record classes reduce boilerplate code by automatically generating common
methods such as constructors, getters, equals(), hashCode(), and toString().
Record fields are implicitly final, meaning once a record instance is created, its
fields cannot be changed.
equals(), hashCode(), and toString() methods are generated automatically,
based on the record's fields.
Example
public record Person(String name, int age) {
}
public class Main {
public static void main(String[] args) {
Person person = new Person("Alice", 30);
System.out.println(person.name()); // Alice
System.out.println(person.age()); // 30
System.out.println(person); // Person[name=Alice, age=30]
}
}
The Person record is defined with two fields: name and age. The Person record
automatically includes getter methods, a constructor, and toString(), equals(),
and hashCode() methods.
Record classes in Java provide a simplified and efficient way to create data-
carrying classes. By focusing on immutability and reducing boilerplate code,
they enhance code readability and maintainability. This feature is especially
useful for modeling simple data structures and value types.

Sealed classes
Sealed classes, introduced in Java 15 as a preview feature and finalized in Java
17, enhance the language's capability for modeling restricted class hierarchies.
This feature allows you to define a class or interface that specifies which other
classes or interfaces may extend or implement it. Sealed classes help in
providing more controlled and predictable inheritance structures, making the
code easier to maintain and understand.
//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;
}

You might also like