0% found this document useful (0 votes)
2 views

unit-3 JAVA

The document discusses new features in Java 8, including default methods in interfaces, functional interfaces, lambda expressions, method references, and the Stream API. It highlights how these features enhance code readability, maintainability, and enable functional programming paradigms. Additionally, it covers the use of the java.util.function package and Base64 encoding/decoding functionalities.

Uploaded by

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

unit-3 JAVA

The document discusses new features in Java 8, including default methods in interfaces, functional interfaces, lambda expressions, method references, and the Stream API. It highlights how these features enhance code readability, maintainability, and enable functional programming paradigms. Additionally, it covers the use of the java.util.function package and Base64 encoding/decoding functionalities.

Uploaded by

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

Unit-3

Java New Features


Introduction to Default Methods
• Default methods are methods defined in
interfaces with a default implementation.
Introduced in Java 8 with the Purpose To allow
interfaces to have methods with concrete
implementations.
• Backward Compatibility: Allow adding new
methods to interfaces without breaking existing
implementations.
• Enhanced Functionality: Provide common
functionality to all implementing classes.
interface MyInterface {
//default method Use default keyword
default void myDefaultMethod() {
System.out.println("This is a default
method");
} public class Demo5 {
void testAbstract();//abstract method public static void main(String[] args) {
static void testStatic() {//static method MyInterface mi=new Temp();
System.out.println("This is static mi.testAbstract();
method"); mi.myDefaultMethod();
} MyInterface.testStatic();
} }
class Temp implements MyInterface }
{
@Override
public void testAbstract() {
System.out.println("This is abstract
method");
}
}
FUNCTIONAL INTERFACES
• Functional interfaces a new and important feature included in Java
SE 8.
• A functional interface is an interface that contains exactly one
abstract method.
• They enable the use of lambda expressions and method references.
• Annotation: @FunctionalInterface annotation (optional but
recommended).
• Examples of Functional Interfaces
Java Built-in Functional Interfaces
1. Runnable (single run method)
2. Callable<V> (single call method)
3. Comparator<T> (single compare method)
@FunctionalInterface //optinal but recommended
Using functional interfaces
interface Inf
{
Example 1:
public void test(String s);//only one abstract method
}
public class Demo1 {
public static void main(String[] args) {
// USE-CASES OF Functional interfaces
//1. Using for anonymous class
Inf inf1=new Inf() {
@Override
public void test(String s) {
System.out.println("Hello "+s);
}
};
inf1.test("Rinki");
//2. Using for lambda expressions Only one method in interface
Inf inf2=(s)->System.out.println("Namaste "+s);
inf2.test("Rinki ke papa");
}
}
import java.util.*; Using functional interfaces
class Job{
int jobNo; Example 2:
String jobName;
public Job(int jobNo, String jobName) {
super(); Lambda on comparator interface
this.jobNo = jobNo;
this.jobName = jobName;
}
@Override
public String toString() {
return "Job [jobNo=" + jobNo + ", jobName=" + jobName + "]";
}}
public class Demo2 {
public static void main(String[] args) {
List<Job> list=List.of(new Job(11,"Cleaning"),new Job(3,"Dusting"), new Job(5,
"Washing"));
ArrayList<Job> al=new ArrayList<Job>(list);
al.sort((a,b)-> a.jobNo-b.jobNo);
System.out.println(al);
}
}
public class Demo3 {
public static void main(String[] args) {
//First thread(anonymous class)
new Thread(new Runnable() {
@Override
public void run() {
for(int i=0;i<10;i++)
{
System.out.println(Thread.currentThread().getName());
}
}
}).start();;
//Using lambda expression
Runnable runner=()->{
for(int i=0;i<10;i++)
{
System.out.println(Thread.currentThread().getName());
}};
new Thread(runner).start();
}
}
public class Demo3 {
public static void main(String[] args) {
//First thread(anonymous class)
new Thread(new Runnable() {
@Override
public void run() {
for(int i=0;i<10;i++)
{
System.out.println(Thread.currentThread().getName());
try {
Thread.sleep(300);
} catch (InterruptedException e) {
e.printStackTrace();
}}}
}).start();;
//Using lambda expression
Runnable runner=()->{
for(int i=0;i<10;i++){
System.out.println(Thread.currentThread().getName());
try {
Thread.sleep(300);
} catch (InterruptedException e) {
e.printStackTrace();
}}};
new Thread(runner).start();
}}
Lambda Expressions
• Lambda expressions are a new and important feature included in Java
SE 8.
• A lambda expression is a concise way to represent an anonymous
function.
• They enable functional programming in Java, simplifying the code.
• Lambda expressions also improve the Collection libraries making it
easier to iterate through, filter, and extract data from a Collection .
• Reduce code length
Benefits of Using Lambda Expressions
• Conciseness: Reduces boilerplate code.
• Readability: Improves code readability and maintainability.
• Functional Programming: Enables functional programming paradigms.
Syntax
Basic syntax
(parameters) -> expression
Syntax Breakdown
No Parameters:
() -> System.out.println("Hello World")

Single Parameter:
x -> x * x

Multiple Parameters:
(a, b) -> a + b
Method References
• Introduced In: Java 8
• Method references provide a way to refer to methods
directly by their names.
• Purpose: They simplify lambda expressions by reducing
boilerplate code.
Types of Method References
• Four Main Types:
• Reference to a static method
• Reference to an instance method of a particular object
• Reference to an instance method of an arbitrary object of a
particular type
• Reference to a constructor
Method References
• Basic Syntax:
1. Static methods: ClassName::methodName
2. Instance methods of a particular object:
instance::methodName
3. Instance methods of an arbitrary object:
ClassName::methodName
4. Constructors: ClassName::new
import java.util.Arrays;
import java.util.Arrays; import java.util.List;
import java.util.List;
class Show
{
1 2
class Show
public static void display(String s) {
{ public void display(String s)
System.out.println(s); {
} System.out.println(s);
} }
public class Demo6 { }
public static void main(String...strings) public class Demo6 {
{ public static void main(String...strings)
List<String> list = Arrays.asList("Alex", {
"Brian", "Charles"); List<String> list = Arrays.asList("Alex",
list.forEach(Show::display); "Brian", "Charles");
} Show s=new Show();
} list.forEach(s::display);
}
}
import java.util.Arrays; @FunctionalInterface

3
import java.util.List; interface MyInf {
class Show{ public Student get(String str);
String msg;
Show(String s){msg=s;}
}
class Student {
4
public void display() private String str;
{ public Student(String str) {
System.out.println(this.msg); this.str = str;
} System.out.println("The name of the student
} is: " + str);
public class Demo6 { }
public static void main(String...strings) }
{ public class Demo7 {
List<Show> list = Arrays.asList(new public static void main(String[] args) {
Show("Alex"),new Show("Brian"),new MyInf constructorRef = Student :: new; //
Show("Charles")); constructor reference
list.forEach(Show::display); constructorRef.get("Aditya");
} }
} }
Use of Package java.util.function
• This java.util.function package provides
standard library-based functional interfaces
for common requirements with their
corresponding lambda expression, which
can be used by the programmer in his code
instead of creating brand new functional
interfaces.
Function
• This interface has one function apply (), this function takes
one input parameter as T and
• return value as R after performing some kind of operation
on the input parameter.
• Structure of Function interface:
@FunctionalInterface
public interface Function <T, R> {
R apply (T t);
}
This T and R may have any type of value like Integer, Float,
Double, String, etc.
import java.util.List;//CODE 1 EXAMPLE
import java.util.function.Function;
public class Demo8 {
public static void main(String[] args) {
List<Float> ls=List.of(34.0f,42.6f,66.5f, 40.5f);
Function<Float, Float> fn=(f)->f/2;
ls.forEach((s)->System.out.println(fn.apply(s)));
}
}

//CODE 2 EXAMPLE
List<String> list=Arrays.asList("Hello ","Hi ","Welcome ");
System.out.println(list);
Function<String, String> msg=s->s+"Rinki";
list.forEach(s->System.out.println(msg.apply(s)));
BiFunction
• This interface also has one function apply (), this function
takes two input parameters as T and
• U and returns a value as R after performing some kind of
operation on given input parameters.
• Structure of BiFunction interface:
@FunctionalInterface
public interface BiFunction <T, U, R> {
R apply (T t, U u);
}
• This T, U, and R may have any type of value like Integer,
Float, Double, String, etc.
import java.util.Set;//EXAMPLE 1
import java.util.function.BiFunction;
public class Demo9 {
public static void main(String...strings)
{
BiFunction<String, String, String> bi=
(s1,s2)->s1+":"+s2.toUpperCase();
Set<String> set=Set.of("Lion","Tiger","Jagaur");
set.forEach((s)->System.out.println(bi.apply(s,
s)));
}
}

BiFunction<Integer, Integer, Integer> bi1=(a1,a2)->a1*a2; //EXAMPLE 2


System.out.println(bi1.apply(5, 6));
Java Stream API
• Stream API is another new feature of Java 8.
• All the classes and interfaces of this Stream API is in the
java.util.stream package. By using this package, the
programmer can perform various aggregate operations
on the data returned from collections, arrays, and I/O
operations.
• The Stream API provides a functional approach to
processing collections of objects.
• To perform complex data processing operations in a
concise and readable manner.
Key Concepts of Streams
• Streams: Sequences of elements supporting sequential
and parallel aggregate operations.
• Not a Data Structure: Streams do not store elements;
they convey elements from a source through a pipeline
of operations.
• Functional Programming: Emphasizes operations such
as map-reduce transformations.
• Simplifies data processing
• Enhances code readability and maintainability
• Supports parallel processing
• Efficient performance with lazy evaluation
Stream API Components
Stream Interface: The main interface for stream
operations
Source: Where streams originate (collections,
arrays, I/O channels)
Intermediate Operations: Transform a stream
into another stream (e.g., filter, map)
Terminal Operations: Produce a result or a side-
effect (e.g., collect, forEach)
Creating Streams
• from Collections: collection.stream()
• From Arrays: Arrays.stream(array)
• From Files: Files.lines(path)
• Using Stream.of(), Stream.iterate(),
Stream.generate()
Intermediate Operations
•filter(): Select elements based on a condition
•map(): Transform elements
•flatMap(): Flatten nested structures
•distinct(): Remove duplicates
•sorted(): Sort elements
•peek(): Perform an action on each element
•limit(): Truncate the stream to a specified size
•skip(): Skip the first N elements
Terminal Operations
•forEach(): Perform an action for each element
•collect(): Gather the elements into a collection
•reduce(): Aggregate elements
•toArray(): Convert the stream to an array
•min(), max(): Find the minimum or maximum value
•count(): Count the elements
•anyMatch(), allMatch(), noneMatch(): Test elements
against a predicate
•findFirst(), findAny(): Find elements
import java.util.Arrays;
import java.util.List;
import java.util.stream.Collectors;
public class Demo10 {
public static void main(String[] args) {
List<Integer> list = Arrays.asList(12, 10, 30, 3,70,-30);
List<Integer> li=list.stream().filter(x->x>10).collect(Collectors.toList());
System.out.println(li);
}
}

List<String> al=Arrays.asList("Bob","Alex","Cloe","Ethen","Astor");
al.stream().map((s)->s+" thomason").forEach(System.out::println);
A map operation applies a function to each element of the input stream to produce another output
stream. The number of elements in the input and output streams is the same. The operation does
not modify the number of elements of the input stream.

Filter : Lesser number Map : Same number Reduce: One element


of elements of elements
import java.util.List;
public class SimpleMapReduceDemo {
public static void main(String[] args) {
List<Integer> li=List.of(1,2,3,4,5,6,7,8,9,10,11,12,13,12,12,13,14,15);
//sum of odd numbers
int sum=li.stream().filter(x->x%2!=0). reduce(0, (x,y)->x+y);
System.out.println(sum);
//sum of all numbers greater than 10 and less than 14
int sum1=li.stream().filter(x->x>10).filter(x->x<14).reduce(0, (x,y)->x+y);
System.out.println(sum1);
}
}
import java.util.*;
class Person{ //REMEMBER THIS CLASS FOR FUTURE PROGRAMS
int age; String name;
public Person(int age, String name) {
super(); Program To sort the list using
this.age = age;
stream api(order=age of
this.name = name;
} person)
@Override
public String toString() {
return "Person [age=" + age + ", name=" + name + "]";
}
}
public class Demo {
public static void main(String[] args) {
List<Person> people = List.of(new Person(26,"Shiva"),new Person(32,"Amit"),new
Person(32,"Amit"),
new Person(23,"Sanjay"),new Person(24,"Vinod"),new Person(32,"Narendra"));
List<Person> list=people.stream()
.sorted((a,b)->(a.age-b.age))
.collect(Collectors.toList());
System.out.println(list);
}
}
Find the sum of all the Person having their names
starting With “S”

import java.util.Comparator;
import java.util.List; Output:49
public class Demo11 {
public static void main(String[] args) {
List<Person> people = List.of(new Person(26,"Shiva"),new Person(32,"Amit"),new
Person(32,"Amit"),
new Person(23,"Sanjay"),new Person(24,"Vinod"),new Person(32,"Narendra"));

int age=people.stream().filter(p->(p.name).startsWith("S")).map(p-
>p.age).reduce(0,Integer::sum);
System.out.println(age);
}}

Method referencing
import java.util.*;
import java.util.stream.Collectors; Program to group the Persons according to
public class Demo11 { age
public static void main(String[] args) {
List<Person> people = List.of(new Person(26,"Shiva"),new Person(32,"Amit"),new
Person(32,"Amit"),new Person(23,"Sanjay"),new Person(24,"Vinod"),new
Person(32,"Narendra"));
Map<Integer, List<Person>> peopleByAge = people.stream()
.filter(p -> p.age > 20)//INTERMEDIATE
.sorted(Comparator.comparing(p->p.age)) //INTERMEDIATE
.collect(Collectors.groupingBy(p->p.age));//TERMINAL
peopleByAge.forEach((k,v)->System.out.println(k+" "+v));
}}
Base64 Encode and Decode
• Java SE provides built-in support for Base64 encoding
and decoding
• java.util.Base64 class in Java 8 and later versions.
Real-world applications of Base64 encoding in Java:
• Integrating with web services.
• Storing binary data in databases.
• Handling attachments in email clients.

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.
import java.util.Base64;
public class Base64Ex {
public static void main(String[] args) {
// Java 8 and later
//Encoding
String originalInput = "Hello";
String encodedString = Base64.getEncoder().encodeToString(originalInput.getBytes());
System.out.println("Encoded string: " + encodedString);
//Decoding
String encodedStringnow = "SGVsbG8=";
byte[] decodedBytes = Base64.getDecoder().decode(encodedStringnow);
String decodedString = new String(decodedBytes);
System.out.println("Decoded string: " + decodedString);
}
}
forEach Method in Java
• in Java 8 forEach was introduced as a method for
iterating over collections.
• It simplifies iteration and enhances code readability.
• Iterates over each element in the collection.
• Executes the specified action (lambda expression or
method reference) for each element.
•Advantages: •Limitations
•Cleaner and more expressive code. •Performance implications
•Encourages functional programming
with heavy computations.
style.
•Suitable for use with lambdas and
•Limited control over
method references. iteration (e.g., cannot break
out of the loop).
public class ForEachDemo {
public static void main(String[] args) {
Consumer<Integer> consumer=(x)->System.out.print(x+" ");
List<Integer> list=List.of(3,5,1,6,7,8,7);
list.forEach(consumer);//with java.util.Consumer
List.forEach((x)->System.out.print(x+" "));
list.forEach(System.out::print);//method referencing
}
}
Try-with-resources
• Simplifies resource management by automatically closing
resources.
• Resources declared in the try block are automatically closed
at the end of the block.(For example, a File resource or a
Socket connection resource.)
• No explicit finally block needed for resource cleanup.
• any object as a resource that implements java.lang.AutoCloseable, which
includes all objects which implement java.io.Closeable can be passed to try
import java.io.BufferedWriter;
import java.io.FileWriter;
import java.io.IOException;
public class Demo {
public static void main(String[] args) {
try(FileWriter fw=new FileWriter("temp.txt"); BufferedWriter bw=new
BufferedWriter(fw))
{
bw.write("try with resource demo");
System.out.println("written successfully");
}
catch(IOException io)
{
io.printStackTrace();
}
}
}

Pass single or multiple resources to try


Type Annotations
• Type Annotations were introduced in Java 8.
• Type Annotations purpose is to extend the Java type
system to provide additional type information.
• Improved readability, Reduced errors, Improved IDE
support
• Examples of Type Annotations are: (Inbuilt)
@Repeatable, @FunctionalInterface
@SuppressWarnings: Suppress warnings at specific
code locations.
@Deprecated: Marks that a method or class is
deprecated.
Type annotations can be used to annotate a variety of
different elements in a Java program, including:
Classes: Type annotations can be used to annotate the
fields and methods of a class.
Methods: Type annotations can be used to annotate the
parameters and return type of a method.
Variables: Type annotations can be used to annotate the
type of a variable.
import java.util.ArrayList;
import java.util.List;
@Deprecated
class OldClass {// Example 1 #class type annotation
// Class implementation
//Mark classes, methods, or fields as deprecated.
//Encourage developers to migrate to alternative solutions.
}
public class TypeAnnoDemo {
public static void main(String[] args) {
@SuppressWarnings("unchecked") //Example 2 #variable annotation
List<String> list = new ArrayList<String>();
//Suppress specific compiler warnings at a local scope.
}
}
CREATE CUSTOM TYPE ANNOTATIONS IN JAVA
• Use the @interface keyword followed by the annotation
name.
• Define the elements or attributes of the annotation.
• Use the annotation on the program elements, such as
constructors, methods, variables, and more.
//Example 1 //Example 2
@interface MyMessage//User defined @interface MyMessage//User defined
Annotation Annotation
{ {
String msg(); String msg();
} }
@MyMessage(msg = "Hello There") class Speaker
class Speaker {
{ void speak(@MyMessage(msg = "hello")
void speak() String s)
{ {
System.out.println("Welcome"); System.out.println(s);
} }
} }
public class TypeAnnoSimpleExample { public class TypeAnnoSimpleExample {
public static void main(String[] public static void main(String[] args)
args) { {
Speaker s=new Speaker(); Speaker s=new Speaker();
s.speak(); s.speak("Welcome");
} }
} }
Repeating Annotations
• Repeating annotations in Java allow you to apply the
same annotation to a declaration or type use more than
once.
• @Repeatable meta-annotation indicates that the
marked annotation can1 be applied
@Repeatable(Roles.class)//Example more than once to
import java.lang.annotation.Repeatable;
import java.lang.annotation.RetentionPolicy;
the same
@interface Role {
String value();
declaration or type use.
import java.lang.annotation.Retention;
@Repeatable(Colors.class)
} @interface Color {
@interface Roles { String name();
}
Role[] value(); @Retention(RetentionPolicy.RUNTIME)
} @interface Colors {
@Role("admin") Color [] value();
}
@Role("manager") @Color(name="Red")//repeat @Color
class AccountResource @Color(name="Green")
{ public class TypeAnnotationEx {//Example 2
} public static void main(String[] args) {
}
}
Java Module System
• The Java Module System is a feature introduced in Java
9 that allows developers to create modular applications.
• A Java module is a set of related Java packages that can
be used by other Java modules.
• Modules can be used to encapsulate code, data, and
resources, and to control how they are accessed by
other modules.
• Improved encapsulation
• Reduced dependencies
• Increased flexibility
Java Module System
• Module is a collection of Java programs or softwares. To
describe a module, a Java file module-info.java is
required. This file also known as module descriptor and
defines the following
• Module name
• What does it export
• What does it require

package abc;//CALLING MODULE


public class Call {
public void call() {
System.out.println("i am called");
}
}
package cdf;//CALLER MODULE
import abc.Call;
public class Caller {
public static void main(String[] args) {
new Call().call();
}
}
Diamond Syntax with Inner Anonymous Class
• Introduced in Java 7.
• It simplifies the instantiation of generic classes by
omitting redundant type declarations.
List<String> list = new ArrayList<>();
Benefits:
• Improves code readability by reducing verbosity.
• Reduces potential errors in type declarations.
• Enhances maintainability by focusing on intent rather than
implementation details.
Inner Anonymous Class
• A nested class without a named type.
• It is instantiated inline where it is defined. For example
Runnable runnable = new Runnable() {
@Override
public void run() {
System.out.println("Executing runnable");
}
};
Diamond Syntax with Inner Anonymous Class
Example

List<String> names = new ArrayList<>() {


{
add("Alice");
add("Bob");
add("Charlie");
}
};
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.
• var is not a keyword
public class VarEx {
//var num=10; not allow
public static void main(String[] args) throws IOException {
// Local Variable type inference
var num=10;
System.out.println(num);
var name=new String("KIET");
System.out.println(name);
var var=5.0f;// var is not a keyword
System.out.println(var);
}
}
Switch expressions
Switch expressions are an extension of switch statements
that allow developers to return values.
Break and yield statements
Switch statements can be targeted by break statements,
while switch expressions can be targeted by yield
statements.
Switch expression cases must be exhaustive(must have
default), meaning there must be a matching switch label
for all possible values.
Switch expression Switch Statement
int value = 3; int n=5;
String result = switch (value) { switch (n) {//EXAMPLE 3
case 1, 2, 3, 4:
yield "i will not tell you"; case 1:
case 5, 6, 7: System.out.println("do");
yield "5-7"; //EXAMPLE 1 break;
case 10: case 2:
yield "10"; System.out.println("don't");
default://required break;
yield "Not Found"; }
};
System.out.println(result); //DEFAULT-CASE not necessary
//does not return anything
int value=25; //EXAMPLE 2
String result=switch(value) {
case 1,2,3,4-> "1-4";
case 5,6,7-> "5-7";
Yield keyword
case 10-> "10";
default->"Not Found"; //required
};
System.out.println(result);
Text Block
• To get pre- public class TextBlockEx {
public static void main(String[] args) {
formatted text in // Text Block Example....
output.(similar String data="""
to <pre> tag This is my original Data
My data is good
inhtml) Another line""";
System.out.println(data);
• Use triple }
quotes ""“text""“ }
Sealed Classes
• Sealed classes were introduced in Java 15.
• They are a new feature that allows developers to control
which classes can extend a particular class.
• Enforcing a particular type hierarchy
abstract sealed class Shape permits Circle, Rectangle{
abstract void getArea();
}
final class Rectangle extends Shape
{
void getArea() {
System.out.println("Rectangle");
}
}
non-sealed class Circle extends Shape
{
void getArea() {
System.out.println("Circle");
}
}
public class SealedEx {
public static void main(String[] args) {
Circle c = new Circle();
c.getArea();
Rectangle r=new Rectangle();
r.getArea();
}
}

You might also like