[go: up one dir, main page]

0% found this document useful (0 votes)
47 views26 pages

UNIT 3 Part B

Uploaded by

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

UNIT 3 Part B

Uploaded by

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

UNIT 3

Java Lambda Expressions


Lambda expression is a new and important feature of Java which was included in Java SE 8.
It provides a clear and concise way to represent one method interface using an expression. It
is very useful in collection library. It helps to iterate, filter and extract data from collection.

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.

Java lambda expression is treated as a function, so compiler does not create .class file.

Functional Interface

Lambda expression provides implementation of functional interface. An interface which has


only one abstract method is called functional interface. Java provides an anotation
@FunctionalInterface, which is used to declare an interface as functional interface.

Why use Lambda Expression

1. To provide the implementation of Functional interface.


2. Less coding.

Java Lambda Expression Syntax

1. (argument-list) -> {body}

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.

No Parameter Syntax

1. () -> {
2. //Body of no parameter lambda
3. }

One Parameter Syntax


1. (p1) -> {
2. //Body of single parameter lambda
3. }

Two Parameter Syntax

1. (p1,p2) -> {
2. //Body of multiple parameter lambda
3. }

Let's see a scenario where we are not implementing Java lambda expression. Here, we are
implementing an interface without using lambda expression.

Without Lambda Expression

1. interface Drawable{
2. public void draw();
3. }
4. public class LambdaExpressionExample {
5. public static void main(String[] args) {
6. int width=10;
7.
8. //without lambda, Drawable implementation using anonymous class
9. Drawable d=new Drawable(){
10. public void draw(){System.out.println("Drawing "+width);}
11. };
12. d.draw();
13. }
14. }

Output:

Drawing 10

Java Lambda Expression Example

Now, we are going to implement the above example with the help of Java lambda expression.

1. @FunctionalInterface //It is optional


2. interface Drawable{
3. public void draw();
4. }
5.
6. public class LambdaExpressionExample2 {
7. public static void main(String[] args) {
8. int width=10;
9.
10. //with lambda
11. Drawable d2=()->{
12. System.out.println("Drawing "+width);
13. };
14. d2.draw();
15. }
16. }

Output:

Drawing 10

A lambda expression can have zero or any number of arguments. Let's see the examples:

Java Lambda Expression Example: No Parameter

1. interface Sayable{
2. public String say();
3. }
4. public class LambdaExpressionExample3{
5. public static void main(String[] args) {
6. Sayable s=()->{
7. return "I have nothing to say.";
8. };
9. System.out.println(s.say());
10. }
11. }

Output:

I have nothing to say.


Java Lambda Expression Example: Single Parameter

1. interface Sayable{
2. public String say(String name);
3. }
4.
5. public class LambdaExpressionExample4{
6. public static void main(String[] args) {
7.
8. // Lambda expression with single parameter.
9. Sayable s1=(name)->{
10. return "Hello, "+name;
11. };
12. System.out.println(s1.say("Sonoo"));
13.
14. // You can omit function parentheses
15. Sayable s2= name ->{
16. return "Hello, "+name;
17. };
18. System.out.println(s2.say("Sonoo"));
19. }
20. }

Output:

Hello, Sonoo
Hello, Sonoo

Java Lambda Expression Example: Multiple Parameters

1. interface Addable{
2. int add(int a,int b);
3. }
4.
5. public class LambdaExpressionExample5{
6. public static void main(String[] args) {
7.
8. // Multiple parameters in lambda expression
9. Addable ad1=(a,b)->(a+b);
10. System.out.println(ad1.add(10,20));
11.
12. // Multiple parameters with data type in lambda expression
13. Addable ad2=(int a,int b)->(a+b);
14. System.out.println(ad2.add(100,200));
15. }
16. }

Output:

30
300

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. In this tutorial, we are explaining
method reference concept in detail.

Types of Method References


There are following types of method references in java:

1. Reference to a static method.


2. Reference to an instance method.
3. Reference to a constructor.
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.

Syntax

1. ContainingClass::staticMethodName

Example 1

In the following example, we have defined a functional interface and


referring a static method to it's functional method say().

1. interface Sayable{
2. void say();
3. }
4. public class MethodReference {
5. public static void saySomething(){
6. System.out.println("Hello, this is static method.");
7. }
8. public static void main(String[] args) {
9. // Referring static method
10. Sayable sayable = MethodReference::saySomething;
11. // Calling interface method
12. sayable.say();
13. }
14. }
Test it Now

Output:

Hello, this is static method.

Example 2

In the following example, we are using predefined functional interface


Runnable to refer static method.

1. public class MethodReference2 {


2. public static void ThreadStatus(){
3. System.out.println("Thread is running...");
4. }
5. public static void main(String[] args) {
6. Thread t2=new Thread(MethodReference2::ThreadStatus);
7. t2.start();
8. }
9. }
Test it Now

Output:

Thread is running...

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.

Syntax

1. containingObject::instanceMethodName

Example 1
In the following example, we are referring non-static methods. You can
refer methods by class object and anonymous object.

1. interface Sayable{
2. void say();
3. }
4. public class InstanceMethodReference {
5. public void saySomething(){
6. System.out.println("Hello, this is non-static method.");
7. }
8. public static void main(String[] args) {
9. InstanceMethodReference methodReference = new InstanceMethod
Reference(); // Creating object
10. // Referring non-static method using reference
11. Sayable sayable = methodReference::saySomething;
12. // Calling interface method
13. sayable.say();
14. // Referring non-static method using anonymous object
15. Sayable sayable2 = new InstanceMethodReference()::saySo
mething; // You can use anonymous object also
16. // Calling interface method
17. sayable2.say();
18. }
19. }

Output:

Hello, this is non-static method.


Hello, this is non-static method.

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.

Syntax

1. ClassName::new

Example
1. interface Messageable{
2. Message getMessage(String msg);
3. }
4. class Message{
5. Message(String msg){
6. System.out.print(msg);
7. }
8. }
9. public class ConstructorReference {
10. public static void main(String[] args) {
11. Messageable hello = Message::new;
12. hello.getMessage("Hello");
13. }
14. }

Output:

Hello

Java 8 Stream



Java 8 introduces Stream, which is a new abstract layer, and some new
additional packages in Java 8 called java.util.stream. A Stream is a
sequence of components that can be processed sequentially. These
packages include classes, interfaces, and enum to allow functional-style
operations on the elements.
The stream can be used by importing java.util.stream package. Stream
API is used to process collections of objects. Streams are designed to be
efficient and can support improving your program’s performance by
allowing you to avoid unnecessary loops and iterations. Streams can be
used for filtering, collecting, printing, and converting from one data
structure to another, etc.

This Java 8 Stream Tutorial will cover all the basic to advanced concepts
of Java 8 stream like Java 8 filter and collect operations, and real-life
examples of Java 8 streams.
Prerequisites for Java Stream
Before proceeding to Java 8, it’s recommended to have a basic knowledge
of Java 8 and its important concepts such as lambda expression, Optional,
method references, etc.
Note:
 If we want to represent a group of objects as a single entity then we
should go for collection.
 But if we want to process objects from the collection then we should go
for streams.
If we want to use the concept of streams then stream() is the method to
be used. Stream is available as an interface.
Syntax:
Stream s = c.stream();
In the above pre-tag, ‘c’ refers to the collection. So on the collection, we
are calling the stream() method and at the same time, we are storing it
as the Stream object. Henceforth, this way we are getting the Stream
object.
Note: Streams are present in java’s utility package
named java.util.stream
Let us now start with the basic components involved in streams. They as
listed as follows:
 Sequence of Elements
 Source
 Aggregate Operations
 Pipelining
 Internal iteration
Features of Java Stream
 A stream is not a data structure instead it takes input from
the Collections, Arrays, or I/O channels.
 Streams don’t change the original data structure, they only provide the
result as per the pipelined methods.
 Each intermediate operation is lazily executed and returns a stream as
a result, hence various intermediate operations can be pipelined.
Terminal operations mark the end of the stream and return the result.
Before moving ahead in the concept consider an example in which we are
having ArrayList of integers, and we suppose we apply a filter to get only
even numbers from the object inserted.

How does Stream Work Internally?


In streams,
 To filter out from the objects we do have a function named filter()
 To impose a condition we do have a logic of predicate which is nothing
but a functional interface. Here function interface can be replaced by a
random expression. Hence, we can directly impose the condition
check-in our predicate.
 To collect elements we will be using Collectors.toList() to collect all
the required elements.
 Lastly, we will store these elements in a List and display the outputs on
the console.
Example
Java

// Java Program to illustrate FILTER


// & COLLECT Operations
import java.io.*;
import java.util.*;
import java.util.stream.*;

// Main class
public class GFG {

// Main driver method


public static void main(String[] args)
{
// Creating an ArrayList object of integer type
ArrayList<Integer> al = new ArrayList<Integer>();

// Inserting elements to ArrayList class object


// Custom input integer numbers
al.add(2);
al.add(6);
al.add(9);
al.add(4);
al.add(20);

// First lets print the collection


System.out.println("Printing the collection : "
+ al);

// Printing new line for better output readability


System.out.println();

// Stream operations
// 1. Getting the stream from this collection
// 2. Filtering out only even elements
// 3. Collecting the required elements to List
List<Integer> ls
= al.stream()
.filter(i -> i % 2 == 0)
.collect(Collectors.toList());
// Print the collection after stream operation
// as stored in List object
System.out.println(
"Printing the List after stream operation : "
+ ls);
}
}

Output

Printing the collection : [2, 6, 9, 4, 20]

Printing the List after stream operation : [2, 6, 4, 20]

Explanation of the above program:


In our collection object, we were having elements entered using the add()
operation. After processing the object in which they were stored through
streams we impose a condition in the predicate of streams to get only
even elements, we get elements in the object as per our requirement.
Hence, streams helped us this way in processing over-processed
collection objects.
Various Core Operations Over Streams
There are broadly 3 types of operations that are carried over streams
namely as follows as depicted from the image shown above:
1. Intermediate operations
2. Terminal operations
3. Short-circuit operations
Let us do discuss out intermediate operations here only in streams to a
certain depth with the help of an example in order to figure out other
operations via theoretical means.
1. Intermediate Operations:
Intermediate operations transform a stream into another stream. Some
common intermediate operations include:
1. filter(): Filters elements based on a specified condition.
2. map(): Transforms each element in a stream to another value.
3. sorted(): Sorts the elements of a stream.
All three of them are discussed below as they go hand in hand in nearly
most of the scenarios and to provide better understanding by using them
later by implementing in our clean Java programs below. As we already
have studied in the above example of which we are trying to filter
processed objects can be interpreted as filter() operation operated over
streams.
2. Terminal Operations
Terminal Operations are the operations that on execution return a final
result as an absolute value.
1. collect(): It is used to return the result of the intermediate operations
performed on the stream.
2. forEach(): It iterates all the elements in a stream.
3. reduce(): It is used to reduce the elements of a stream to a single
value.
3. Short Circuit Operations
Short-circuit operations provide performance benefits by avoiding
unnecessary computations when the desired result can be obtained early.
They are particularly useful when working with large or infinite streams.
1. anyMatch(): it checks the stream if it satisfies the given condition.
2. findFirst(): it checks the element that matches a given condition and
stops processing when it finds it.
Note: They are lazy, meaning they are not executed until a terminal
operation is invoked.
Later on from that processed filtered elements of objects, we are
collecting the elements back to List using Collectors for which we have
imported a specific package named java.util.stream with the help of
Collectors.toList() method. This is referred to as collect() operation in
streams so here again we won’t be taking an example to discuss them out
separately.
Example:
Java

// Java program to illustrate Intermediate Operations


// in Streams

// Importing required classes


import java.io.*;
import java.util.*;
import java.util.stream.*;

// Main class
class Test {

// Main driver method


public static void main(String[] args)
{

// Creating an integer Arraylist to store marks


ArrayList<Integer> marks = new ArrayList<Integer>();

// These are marks of the students


// Considering 5 students so input entries
marks.add(30);
marks.add(78);
marks.add(26);
marks.add(96);
marks.add(79);

// Printing the marks of the students before grace


System.out.println(
"Marks of students before grace : " + marks);

// Now we want to grace marks by 6


// using the streams to process over processing
// collection

// Using stream, we map every object and later


// collect to List
// and store them
List<Integer> updatedMarks
= marks.stream()
.map(i -> i + 6)
.collect(Collectors.toList());

// Printing the marks of the students after grace


System.out.println(
"Marks of students after grace : "
+ updatedMarks);
}
}

Output

Marks of students before grace : [30, 78, 26, 96, 79]


Marks of students after grace : [36, 84, 32, 102, 85]

Note: For every object if there is urgency to do some operations be it


square, double or any other than only we need to use map() function
operation else try to use filter() function operation.

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.

Nested Classes of Base64


Class Description

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

Base64.Enco This class implements an encoder for encoding byte data using the Bas
der 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


getDecoder() Basic type base64 encoding scheme.

public static Base64.Encoder It returns a Base64.Encoder that encodes using


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

public static Base64.Decoder It returns a Base64.Decoder that decodes using


getMimeDecoder() MIME type base64 decoding scheme.

public static Base64.Encoder It Returns a Base64.Encoder that encodes using


getMimeEncoder() MIME type base64 encoding scheme.

public static Base64.Encoder It returns a Base64.Encoder that encodes using


getMimeEncoder(int lineLength, byte[] MIME type base64 encoding scheme with specified
lineSeparator) length and line separators.

public static Base64.Encoder It returns a Base64.Encoder that encodes using the


getUrlEncoder() and Filename safe type base64 encoding scheme.

Base64.Decoder Methods
Methods Description

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

public byte[] It decodes a Base64 encoded String into a newly-allocated byte a


decode(String src) using the Base64 encoding scheme.

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

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

public InputStream It returns an input stream for decoding Base64 encoded byte stream
wrap(InputStream is)
Base64.Encoder Methods
Methods Description

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

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

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

public ByteBuffer It encodes all remaining bytes from the specified byte buffer in
encode(ByteBuffer newly-allocated ByteBuffer using the Base64 encoding scheme. U
buffer) return, the source buffer's position will be updated to its limit; its
will not have been changed. The returned output buffer's position
be zero and its limit will be the number of resulting encoded bytes.

public OutputStream It wraps an output stream for encoding byte data using the Bas
wrap(OutputStream os) encoding scheme.

public Base64.Encoder It returns an encoder instance that encodes equivalently to this


withoutPadding() but without adding any padding character at the end of the enco
byte data.

Java Base64 Example: Basic Encoding and Decoding


1. import java.util.Base64;
2. publicclass Base64BasicEncryptionExample {
3. publicstaticvoid main(String[] args) {
4. // Getting encoder
5. Base64.Encoder encoder = Base64.getEncoder();
6. // Creating byte array
7. bytebyteArr[] = {1,2};
8. // encoding byte array
9. bytebyteArr2[] = encoder.encode(byteArr);
10. System.out.println("Encoded byte array: "+byteArr2);
11. bytebyteArr3[] = newbyte[5]; // Make sure it has enough size to st
ore copied bytes
12. intx = encoder.encode(byteArr,byteArr3); // Returns number of bytes writt
en
13. System.out.println("Encoded byte array written to another array: "+byteArr
3);
14. System.out.println("Number of bytes written: "+x);
15.
16. // Encoding string
17. String str = encoder.encodeToString("JavaTpoint".getBytes());
18. System.out.println("Encoded string: "+str);
19. // Getting decoder
20. Base64.Decoder decoder = Base64.getDecoder();
21. // Decoding string
22. String dStr = new String(decoder.decode(str));
23. System.out.println("Decoded string: "+dStr);
24. }
25.}

Output:

Encoded byte array: [B@6bc7c054


Encoded byte array written to another array: [B@232204a1
Number of bytes written: 4
Encoded string: SmF2YVRwb2ludA==
Decoded string: JavaTpoint

Sealed Class in Java




In Java, we have the concept of abstract classes. It is mandatory


to inherit from these classes since objects of these classes cannot
be instantiated. On the other hand, there is a concept of a final
class in Java, which cannot be inherited or extended by any other
class. What if we want to restrict the number of classes that can
inherit from a particular class? The answer is sealed class. So, a
sealed class is a technique that limits the number of classes that
can inherit the given class. This means that only the classes
designated by the programmer can inherit from that particular
class, thereby restricting access to it. when a class is declared
sealed, the programmer must specify the list of classes that can
inherit it. The concept of sealed classes in Java was introduced in
Java 15.
Steps to Create a Sealed Class
 Define the class that you want to make a seal.
 Add the “sealed” keyword to the class and specify which
classes are permitted to inherit it by using the “permits”
keyword.
Example
sealed class Human permits Manish, Vartika, Anjali
{
public void printName()
{
System.out.println("Default");
}
}
non-sealed class Manish extends Human
{
public void printName()
{
System.out.println("Manish Sharma");
}
}
sealed class Vartika extends Human
{
public void printName()
{
System.out.println("Vartika Dadheech");
}
}
final class Anjali extends Human
{
public void printName()
{
System.out.println("Anjali Sharma");
}
}
Explanation of the above Example:
 Human is the parent class of Manish, Vartika, and Anjali. It is a
sealed class so; other classes cannot inherit it.
 Manish, Vartika, and Anjali are child classes of
the Human class, and it is necessary to make them
either sealed, non-sealed, or final. Child classes of a sealed
class must be sealed, non-sealed, or final.
 If any class other than Manish, Vartika, and Anjali tries to
inherit from the Human class, it will cause a compiler error.
Code Implementation

 Java

import java.lang.*;

sealed class Human permits Manish, Vartika, Anjali

public void printName()

System.out.println("Default");

non-sealed class Manish extends Human

public void printName()

System.out.println("Manish Sharma");

}
sealed class Vartika extends Human

public void printName()

System.out.println("Vartika Dadheech");

final class Anjali extends Human

public void printName()

System.out.println("Anjali Sharma");

public class Main

public static void main(String[] args)

{
Human h1 = new Anjali();

Human h2 = new Vartika();

Human h3 = new Manish();

h1.printName();

h2.printName();

h3.printName();

}
Output:

You might also like