0% found this document useful (0 votes)
1 views15 pages

Oops3

This document outlines new features introduced in Java, particularly focusing on functional interfaces, lambda expressions, and the Stream API. It explains the concept of functional programming, the use of lambda expressions for concise code, and the capabilities of the Stream API for processing collections. Additionally, it covers default methods, static methods in interfaces, Base64 encoding, and enhancements in type annotations and the Java module system.
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)
1 views15 pages

Oops3

This document outlines new features introduced in Java, particularly focusing on functional interfaces, lambda expressions, and the Stream API. It explains the concept of functional programming, the use of lambda expressions for concise code, and the capabilities of the Stream API for processing collections. Additionally, it covers default methods, static methods in interfaces, Base64 encoding, and enhancements in type annotations and the Java module system.
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/ 15

Unit-3: Java New Features

Saturday, June 8, 2024 8:15 PM

Functional Interfaces
→ An Interface that contains exactly one abstract method is known as functional interface.
→ It represents a single action.
→ It can have any number of default, static methods but can contain only one abstract method.
→ It is known as Single Abstract Method Interfaces.
→ It helps in functional programming task
→ interface with an annotation called @FunctionalInterface
→ No need to use the abstract keyword, by default, method defined inside the interface is abstract only.

@FunctionalInterface
interface interface1{
void printm(String msg);
}
public class FInterfaceDemo1 implements interface1 {
public void printm(String msg){
System.out.println(msg);
}
public static void main(String[] args) {
FInterfaceDemo1 f = new FInterfaceDemo1();
f.printm("functional interface demo");
}
}

Java Predefined Functional Interfaces

→ Java provides predefined functional interfaces to deal with functional programming by using lambda
and method references.
→ You can also define your own custom functional interface. Following is the list of functional interface
which are placed in java.util.function package.

Lambda Expressions

→ It is a short block of code which takes in parameters and returns a value


→ A concise way to represent one method interface using an expression.
→ It helps to iterate, filter and extract data from collection.
→ Used to provide implementation of an interface which has functional interface.
→ It saves a lot of code.

Syntax:-

Page 1
Types of Lambda Expression
→ There are three Lambda Expression Parameters are mentioned below:
○ Zero Parameter
○ Single Parameter
○ Multiple Parameters
1. Lambda Expression with Zero parameter
() -> System.out.println("Zero parameter lambda");
2. Lambda Expression with Single parameter
(p) -> System.out.println("One parameter: " + p);
It is not mandatory to use parentheses if the type of that variable can be inferred from the context
3. Lambda Expression with Multiple parameters
(p1, p2) -> System.out.println("Multiple parameters: " + p1 + ", " + p2);

Example Problems

1. No Parameter Lambda Expression

interface HelloWorld {
void sayHello();
}

public class Main {


public static void main(String[] args) {
HelloWorld hello = () -> System.out.println("Hello, World!");
hello.sayHello();
}
}

2. Single Parameter Lambda Expression

interface Greeting {
void sayMessage(String message);
}

public class Main {


public static void main(String[] args) {
Greeting greet = message ->System.out.println("Hello, " + message);
greet.sayMessage("Alice");
}
}

3. Multiple Parameters Lambda Expression

interface Arithmetic {
int operation(int a, int b);
}
public class Main {
public static void main(String[] args) {
Arithmetic add = (a, b) -> a + b;
Arithmetic multiply = (a, b) -> a * b;

System.out.println("Addition: " + add.operation(5, 3));


System.out.println("Multiplication: " + multiply.operation(5, 3));
}
}

How to use Lambda Expression

→ A lambda operator or arrow operator → is used to define expression


→ It divides lambda expression in two parts
○ left side specifies any parameters
○ right side specifies lambda body/block of code

() → 123.45
(n) → (n%2)==0

Page 2
Example of Lambda Expression with one parameter

//functional interface
interface NumericTest{
boolean test(int n);
}
public class LambdaDemo1 {
public static void main(String args[]) {
NumericTest isEven= (n) -> (n%2)==0;
if(isEven.test(10)) System.out.println("10 is even");
if(!isEven.test(9)) System.out.println("9 is not even");
}
}

Java lambda expression is consisted of three components.


1) Argument-list: It can be empty or non-empty as well.
2) Arrow-token: It is used to link arguments-list and body of expression.
3) Body: It contains expressions and statements for lambda expression.

Passing Lambda Expressions as arguments


→ To pass a lambda expression as a method parameter in java, the type of method parameter that
receives must be of functional interface type.

Important
// Program to print factorial of a number using lambda block

@FunctionalInterface
public interface RecFunction {
Integer recursiveFunction(Integer n);
}
// Lambda Function
Integer Fact = (n)-> {
if (n == 0) return 1;
else return n * factorial.recursiveFunction ( n - 1 );
};

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.
→ Three types are there:-
○ Reference to a static method.
○ Reference to an instance method.
○ Reference to a constructor.

1. Reference to a static method

→ A static method reference refers to a static method in a specific class.


→ Its syntax is className::staticMethodName
→ Where classname identifies the class
→ staticMethodName identifies the method

Page 3
2. Reference to an instance method

→ like static methods, you can refer instance methods also


→ The syntax is---
containingObject::instanceMethodName

3. Reference to the Constructor

→ Refer a constructor by using the new


keyword.
→ we are referring constructor with the help
of functional interface.
→ The syntax is ---
ClassName::new

Stream API

Collection: It means single unit of objects.


Stream: If we want to process the object from a collection, then we should use a Stream.
Collection to Stream: Stream s = collection.stream();
Package: java.util.stream

→ Stream API is Introduced in Java 8, It is used to process collections of objects.


→ A stream in Java is a sequence of objects that supports various methods which can be pipelined to
produce the desired result.
→ A stream operates on a data source, such as an array or a collection.
→ A stream, itself, never provides storage for the data.

Uses of Stream API


→ Stream API is a way to express and process collections of objects.
→ Enable us to perform operations like filtering, mapping, reducing and sorting.

Stream API Features

→ Stream does not store elements.


→ It simply conveys elements from a source such as a data structure, an array, or an I/O channel,
through a pipeline of computational operations.
→ Stream is functional in nature. Operations performed on a stream does not modify it's source. For
example, filtering a Stream obtained from a collection produces a new Stream without the filtered
elements, rather than removing elements from the source collection.
→ Stream is lazy and evaluates code only when required.
→ The elements of a stream are only visited once during the life of a stream. Like an Iterator, a new
stream must be generated to revisit the same elements of the source.

Page 4
Stream Operations

→ Stream operations are divided into two types:-


○ Intermediate operations
○ Terminal operations

Intermediate- It returns a stream as the output and intermediate operations are only executed once a
terminal operation is invoked on the stream. This is called lazy evaluation. Intermediate operations produce
another stream. Thus, intermediate operations can be used to create a pipeline that performs a sequence of
actions

Terminal- Terminal operations in streams produce the final results of the stream after all intermediate
operations have been applied, marking the end of stream processing. Once a terminal operation is executed,
the stream cannot be further utilized.

Important Intermediate Operations


There are a few Intermediate Operations mentioned below:

1. 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());

2. filter()
The filter method is used to select elements as per the Predicate passed as an argument.
List names = Arrays.asList("Reflection","Collection","Stream");
List result = names.stream().filter(s->s.startsWith("S")).collect(Collectors.toList());

3. 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());

Important Terminal Operations


There are a few Terminal Operations mentioned below:

1. 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());

2. 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));

3. 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);

Reduction Operations

→ Many times, we need to perform operations where a stream reduces to single resultant value, for
example, maximum, minimum, sum, product, etc.

→ Reducing is the repeated process of combining all elements.

→ sum(), min(), max(), count() etc. are some examples of reduce operations.

Page 5
Example of Reduction Operations in Stream API

//Sum of list of Integers

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

public class ReductionExample {


public static void main(String[] args) {
List<Integer> numbers = Arrays.asList(1, 2, 3, 4, 5);

// Using reduce to sum the list of numbers


Optional<Integer> sum = numbers.stream().reduce((a, b) -> a + b);

sum.ifPresent(result -> System.out.println("Sum: " + result));

// Alternatively, with an identity value


int sumWithIdentity = numbers.stream().reduce(0, (a, b) -> a + b);
System.out.println("Sum with identity: " + sumWithIdentity);
}
}

//Finding the Maximum Value in a List of Integers

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

public class MaxValueExample {


public static void main(String[] args) {
List<Integer> numbers = Arrays.asList(1, 2, 3, 4, 5);

// Using reduce to find the maximum value


Optional<Integer> max = numbers.stream().reduce((a, b) -> a > b ? a : b);

max.ifPresent(result -> System.out.println("Max: " + result));


}
}

Default Methods

→ Before Java 8, interfaces could have only abstract methods.


→ The implementation of these methods has to be provided in a separate class.
→ So, if a new method is to be added in an interface, then its implementation code has to be provided in
class implementing the same interface.
→ To overcome this issue, Java 8 has introduced the concept of default methods which allow the
interfaces to have methods with implementation without affecting the classes that implement the
interface.
→ Default methods are also known as defender methods or virtual extension methods.

Default Method: Example

Page 6
Static Method in Interface

→ Java 8 also allows us to define and


implement static methods in interfaces.
→ Since static methods don’t belong to a
particular object, they’re not part of the API
of the classes implementing the interface
→ they have to be called by using the interface
name preceding method name.

Base64: Encode and Decode

→ Java 8 has finally added Base64 capabilities to the standard API, via the java.util.Base64 utility class.
→ There are 3 types of encoding and decoding capabilities as standard.
→ All of the classes are related to this are in java.util.base64 package.
○ Base or Simple Type
○ URL Encoding/Decoding
○ MIME Encoding/Decoding

Java 8 Base64 Encoding Without Padding

→ In Base64 encoding, the length of an output-encoded String must be a multiple of four. If necessary, the
encoder adds one or two padding characters (=) at the end of the output as needed in order to meet this
requirement.
→ Upon decoding, the decoder discards these extra padding characters.
→ we need to skip the padding of the output. For instance, the resulting String will never be decoded back.
So, we can simply choose to encode without padding.

Java 8 URL Encoding and decoding

→ URL encoding is very similar to the basic encoder. Also, it uses the URL and Filename Safe Base64
alphabet.
→ In addition, it does not add any line separation:
→ Decoding happens in much the same way. The getUrlDecoder() utility method returns
a java.util.Base64.Decoder. So, we use it to decode the URL:

Page 7
Example: Base 64 Simple Encoding and Decoding

ForEach Method

→ Introduced in Java 8, the forEach loop provides programmers with a new, concise and interesting way
to iterate over a collection.
→ with forEach, we can iterate over a collection and perform a given action on each element, like any
other Iterator.

The forEach() method has been added in following places:


1. Iterable interface - This makes Iterable.forEach() method available to all collection classes except Map
2. Map interface - This makes forEach() operation available to all map classes.
3. Stream interface - This makes forEach() and forEachOrdered() operations available to all types of stream.

Example

import java.util.ArrayList;
import java.util.List;
public class ForEachExample {
public static void main(String[] args) {
List<String> gamesList = new ArrayList<String>();
gamesList.add("Football");
gamesList.add("Cricket");
gamesList.add("Chess");
gamesList.add("Hocky");
System.out.println("- --Iterating by passing lambda expression---");
gamesList.forEach(games -> System.out.println(games));
}

Output:
---Iterating by passing lambda expression---
Football
Cricket
Chess
Hocky

Try-with-resources

→ This feature 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.
→ The resources declared need to implement the AutoCloseable interface.
→ Simply put, to be auto-closed, a resource has to be both declared and initialized inside the try:

Page 8
Try-with-resources can replace try-catch-finally block.

try-with-resources With Multiple Resources


We can declare multiple resources just fine in a try-with-resources block by separating them with a
semicolon:

Type Annotations

→ As of the Java SE 8 release, annotations can also be applied to any type use.
→ This means that annotations can be used anywhere you use a type.
→ Type annotations were created to support improved analysis of Java programs way of ensuring
stronger type checking.
→ For example, if you want to avoid NullPointerException in your code, you can declare a string variable
like this:
@NonNull String str;

Repeating Annotations

→ 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.
→ These 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.

Declare a repeatable annotation type

→ Declaring of repeatable annotation type must be marked with the @Repeatable meta-annotation.
→ A custom annotations is defined @Game repeatable annotation type.

1. @Repeatable(Games.class)
2. @interfaceGame{
3. String name();
4. String day();
5. }

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.
→ Example- declaring Games containing annotation type:

1. @interfaceGames{
2. Game[] value();
3. }

Page 9
Java Module System

→ Originally proposed in 2005 for Java 7.


→ Java modules, introduced in Java 9, are a game-changing feature that revolutionizes the way
developers organize and manage their code.
→ They promote better code reusability, maintainability, and separation of concerns, empowering you to
build scalable and efficient applications.
→ As our code size increased, packages in java also got increased. Imagine working on a very large
program using hundreds of packages, in such case it is very difficult to understand which classes is
using what. Packages are great way of organizing classes but there needs to be way to organize
packages when we need to use several of them in our code.
→ It’s a “package of Java Packages” abstraction that allows us to make our code even more reusable.
→ Packages inside a module are identical to Java packages
→ To create a module, organize the code internally in packages just like we previously did with any other
project.
→ Aside from organizing our code, packages are used to determine what code is publicly accessible
outside of module.
→ Each module is responsible for its resources, like media or configuration files.

What is a module?

→ Modularity adds a higher level of aggregation above packages. The key new language element is
the module—a uniquely named, reusable group of related packages, as well as resources (such as
images and XML files) and a module descriptor specifying
-module’s name
-module’s dependencies (other modules this module depends on)
-packages it explicitly makes available to other modules
-services it offers
-services it consumes
-to what other modules it allows reflection

Java Module Types


4 types are:-

1. System Modules – These are modules listed when we run the list-modules command, include Java SE
and JDK modules.
2. Application Modules – These modules are what we usually want to build when we decide to use
Modules. They are named and defined in the compiled module-info.class file included in the assembled
JAR.
3. Automatic Modules – include unofficial modules by adding existing JAR files to the module path. The
name of module will be derived from the name of the JAR. Automatic modules will have full read
access to every other module loaded by the path.
4. Unnamed Module – When a class or JAR is loaded onto the classpath, but not the module path, it’s
automatically added to the unnamed module. It’s a catch-all module to maintain backward compatibility
with previously-written Java code.
Create and use module in Eclipse

1. Creating a Java Project


2. Create module-info.java file
3. Create a package and a class
4. Export the package that we have created
5. Create another module
6. Create a class in second module
7. Final step(run)

Page 10
Diamond Syntax (<>)

→ Diamond syntax, sometimes known as diamond operator, It was added to Java 7 as just a new feature.
→ Purpose of diamond operator is to avoid redundant code by leaving the generic type in the right side of
the expression.
→ The diamond operator makes it easier to employ generics while building an object. By allowing implicit
duplicate parameter type specification

Diamond Syntax with Inner Anonymous Class

→ 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.
→ Data types that can be written in Java program like int, String etc are called denotable types.

Local Variable Type Inference(LVTI)

What is type inference?


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

What is Local Variable type inference?


Local variable type inference is a feature in Java 10 that allows the developer to skip the type declaration
associated with local variables (those defined inside method definitions, initialization blocks, for-loops, and
other blocks like if-else), 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.

→ In JDK 10 and later, you can declare local variables with non-null initializers with the var identifier,
which can help writing code that is easier to read.

Rewriting above code using var type inference----


var is reserved type name not a
keyword meaning that existing
code that used var as a
variable , method or package
name is not affected.

Page 11
LVTI Guidelines

→ Local variable declarations can make code more readable by eliminating redundant information.
→ It can also make code less readable by omitting useful information.
→ Use this feature with judgment; no strict rule exists about when it should and shouldn't be used.
→ Local variable declarations don't exist in isolation

Traditional switch and issues

→ Default fall through due to missing


breaks.
→ Multiple values per case is not supported

○ Use of break statement in each


case, work as expected.
○ But in case you miss to include
break statement switch fall
through.

Switch Expressions

→ Java 12 and 13 improved the traditional switch statement and made it more useful.
→ Like all expressions, this expression evaluate to a single value and can be used in statements
→ They contain “ case L ->” labels that eliminate the need for break statements to prevent fall through.
→ Use a yield statement to specify the value of a switch expression

Advantage of switch expression

→ Support multiple values per case


→ Switch does not fall through
→ yield is used to return a value
→ switch can be used as an expression
→ Switch with arrow (->) symbol
→ Variables declared in traditional switch exists until end of the switch statement . If you need variable
level scope , use {} introduced in Java 13.

Example Java Program 1

Example Java program (New vs Old)

Page 12
Text Blocks

→ 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 can be used anywhere a string literal can be used.
→ Text blocks may be used as a method argument

Need for Text Blocks

→ 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.
→ It provide clarity by way of minimizing the Java syntax required to render a string that spans multiple
lines.

Text Block Syntax

→ A text block begins with three double-quote characters followed by a line terminator.
→ You can't put a text block on a single line, nor can the contents of the text block follow the three opening
double-quotes without an intervening line terminator.
→ Reason for this is that text blocks are primarily designed to support multi-line strings, and requiring
initial line terminator simplifies the indentation handling rules

Records

→ Records are immutable data classes that require only the type and name of fields.
→ The record is a new type of class in Java that makes it easy to create immutable data objects.
→ Introduced in Java 14 as an early preview, Java 15 aims to refine a few aspects before becoming an
official product feature.

EXAMPLE-
Consider a class Employee, objective is to contain employee’s data like ID and name and act as a data carrier
to be transferred across modules.
To create such a simple class, you need to define its constructor, getter, and setter methods, if you want to use
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().

Page 13
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.
→ Record objects have an implicit sensible implementation of hashCode(), equals(), and toString() methods.
→ With Java 15, native methods cannot be declared in records.
→ With Java 15, implicit fields of record are not final and modification using reflection will throw
IllegalAccessException.

Purpose/Advantage of Records

→ purpose of a record is to create a data object or a POJO which is used to carry data in application
program flow.
→ In a multi-tier program, Domain/Model objects store the data captured from the data source and then
these model objects are passed further to the application/UI layer to process the data and vice versa
where UI/Application stores data in data objects and then pass these objects to Data layer to populate
data sources.
→ As these data objects contain a lot of fields, developers are required to write a lot of setter/getter
methods, parameterized constructors, overridden equals methods, and hashcode methods.
→ In such a scenario, record comes to the rescue as it provides most of the boilerplate code and the
developer can focus on required functionalities only.

Declaring and Using Java Record

To declare a record, use the record keyword, followed by the record name and the state description enclosed
in parenthesis.

To use this record, you can create a new instance of Employee

Example code record

Record Vs Traditional classes vs Abstract classes

Page 14
Sealed Classes

→ Sealed classes are a feature introduced in Java 16 and finalized in Java 17.
→ It allow developers to restrict the inheritance hierarchy of a class or interface.
→ They provide more control over how a class can be extended or implemented.
→ A class or an interface can now define which classes can implement or extend it.
→ It is a useful feature for domain modeling and increasing the security of libraries.
→ We can seal classes by applying the same sealed modifier.
→ The permits clause should be defined after any extends or implements clauses

Declaring Sealed Classes

→ To seal a class, add sealed modifier to its declaration.


→ Then, after any extends and implements clauses ,add the permits clause.
→ This clause specifies the classes that may extend the sealed class.

Example-
Shape specifies three permitted subclasses , Circle, Square, Rectangle

Define Circle.java

Define Square.java

Define Rectangle.java

public sealed class Rectangle extends Shape permits FilledRectangle {


public double length, width;
}

Define FilledRectangle.java

Example Sealed Classes

Page 15

You might also like

pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy