[go: up one dir, main page]

0% found this document useful (0 votes)
3 views24 pages

Unit-13 Complete

The document outlines new features in Java, including functional interfaces, lambda expressions, method references, and the Stream API, among others. It provides examples of how to implement these features, such as using functional interfaces for cleaner code and utilizing the Stream API for efficient data processing. Additionally, it discusses records, type annotations, and the Java Module System, highlighting their benefits and usage in modern Java programming.
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)
3 views24 pages

Unit-13 Complete

The document outlines new features in Java, including functional interfaces, lambda expressions, method references, and the Stream API, among others. It provides examples of how to implement these features, such as using functional interfaces for cleaner code and utilizing the Stream API for efficient data processing. Additionally, it discusses records, type annotations, and the Java Module System, highlighting their benefits and usage in modern Java programming.
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/ 24

III.

Java New Features: Functional Interfaces, Lambda Expression, Method References, Stream API, Default Methods, Static
Method, Base64 Encode and Decode, ForEach Method, Try-with-resources, Type Annotations, Repeating Annotations, Java
Module System, Diamond Syntax with Inner Anonymous Class, Local Variable Type Inference, Switch Expressions, Yield
Keyword, Text Blocks, Records, Sealed Classes.

Program:1

interface Message{

void printMsg();

float PI=3.14f;

default void display() {

System.out.println("Display Default Message");

displayPrivate(); }

static void displayStatic() {

System.out.println("Display Static Message");}

private void displayPrivate() {

System.out.println("Display Private Message");}

class MessageDisplay implements Message{

@Override

public void printMsg() {

// TODO Auto-generated method stub

System.out.println("My Message");}

public class Display {

public static void main(String[] args) {

// TODO Auto-generated method stub

MessageDisplay d=new MessageDisplay();

d.printMsg();

d.display();

Message.displayStatic();

}
}

Functional Interface in Java

A Functional Interface in Java is an interface that contains exactly one abstract method. It can have multiple default or
static methods, but only one abstract method.

Functional Interfaces are the basis for lambda expressions and method references in Java, introduced in Java 8.

Syntax:

@FunctionalInterface

public interface MyFunctionalInterface {

void performAction(); // Single abstract method

@FunctionalInterface annotation is optional but recommended — it tells the compiler to ensure the interface has only one
abstract method.

Why Use Functional Interfaces?

 To write cleaner and concise code using lambda expressions.

 To implement functional programming in Java.

 To pass behavior as a parameter (functional-style programming).

Program:2

@FunctionalInterface

interface Calculator {

int add(int n1, int n2);

public class FunctionalInterEx {

public static void main(String[] args) {

// TODO Auto-generated method stub

/*Calculator c = new Calculator() {

@Override

public int add(int n1, int n2) {


// TODO Auto-generated method stub

return n1+n2;

};

System.out.println("Sum ="+c.add(10, 20));*/

Calculator c1=(n1,n2)-> n1+n2;

System.out.println("Sum ="+c1.add(10, 20));

Method References in Java

Method Reference is a shorthand notation of a lambda expression to call a method. It allows referencing an existing
method by name instead of writing a full lambda.

Introduced in Java 8, method references make code more readable and concise.

Syntax:

ClassName::methodName

or

object::methodName

Program:3

@FunctionalInterface

interface Calculato {

int add(int n1, int n2); }

class Sum{

int n1, n2;

int mysum(int n1, int n2) {

return n1+n2; }

class Mul{

int n1, n2;


int mymul(int n1, int n2) {

return n1*n2; }

public class FunIntCal {

public static void main(String[] args) {

// TODO Auto-generated method stub

Sum s = new Sum();

Calculato c = s::mysum;

int abc=c.add(10,20);

System.out.println("Sum is"+abc);

Mul ss = new Mul();

Calculato cc = ss::mymul;

int abcd=cc.add(10,20);

System.out.println("Sum is"+abcd); }

Program:4

@FunctionalInterface

interface Display1{

void msg();

class PrintDisplay

PrintDisplay(){

System.out.println("Constructor Referencing");

static void myMsg() {

System.out.println("Static Method Referencing");

}
}

public class MethoRefEx {

public static void main(String[] args) {

// TODO Auto-generated method stub

Display1 d= PrintDisplay::myMsg;

d.msg();

Display1 d1=PrintDisplay::new;

d1.msg();

Stream API:

The Stream API was introduced in Java 8 to process collections of data (like lists, sets, etc.) in a declarative and functional
style. It helps you write clean, efficient, and concise code for filtering, mapping, sorting, and reducing data.

What is a Stream?

A Stream is not a data structure; it is a sequence of elements supporting sequential and parallel aggregate operations.

Why Use Stream API?

 Simplifies operations on collections (like filtering, mapping, etc.).

 Promotes functional programming.

 Supports parallel execution for performance.

 Eliminates boilerplate code using method chaining.

 Key Concepts

Concept Description
Stream Sequence of elements from a collection
Intermediate Operations Transform a stream (e.g., filter, map, sorted)
Terminal Operations Produce a result or side-effect (e.g., collect, forEach, count)

Basic Example:

import java.util.*;

import java.util.stream.*;
public class StreamExample {

public static void main(String[] args) {

List<String> names = Arrays.asList("Alice", "Bob", "Charlie", "David", "Bob");

// Print names that start with 'B', in uppercase, no duplicates

names.stream()

.filter(name -> name.startsWith("B"))

.map(String::toUpperCase)

.distinct()

.forEach(System.out::println);

Collecting Results

List<String> filtered = names.stream()

.filter(n -> n.length() > 3)

.collect(Collectors.toList());

Stream with Numbers Example:

List<Integer> numbers = Arrays.asList(1, 2, 3, 4, 5);

// Square even numbers and collect

List<Integer> squares = numbers.stream()

.filter(n -> n % 2 == 0)

.map(n -> n * n)

.collect(Collectors.toList());

System.out.println(squares); // [4, 16]


Example:

import java.util.List;

import java.util.OptionalInt;

public class StreamExp2 {

public static void main(String[] args) {

// TODO Auto-generated method stub

List<Integer> values6=List.of(1,2,3,4,5,6,7,8);

OptionalInt max=values6.stream().mapToInt(num->num).max();

System.out.println(max);

int sum=values6.stream().mapToInt(num->num).sum();

System.out.println(sum);

int evensum=values6.stream().filter(num->num%2==0).mapToInt(num->num).sum(); //sum of even numbers

System.out.println(evensum);

Program to find sum and product of Arraylist elements.

import java.util.List;

public class StreamAPIEx {

public static void main(String[] args) {

// TODO Auto-generated method stub

List<Integer> values2=List.of(1,2,3,4,5,6,7,8,9,10);

//List<Integer> values2=Arrays.asList(20,30,40,50);

System.out.println(values2);

values2.stream().filter(num->num%2==0).forEach(System.out::print); //Even odd

List<Integer> values5=values2.stream().map(num->num*5).toList();

System.out.println(values5);
int sum=values2.stream().reduce(0,(num,prev)->num+prev);

System.out.println(sum);

int mul=values2.stream().reduce(1,(num,prev)->num*prev);

System.out.println(mul);

Record in Java: A record in Java is a special kind of class introduced in Java 14 (as a preview feature) and officially added in
Java 16. It is used to model immutable data and is a concise way to create data carrier classes without having to write
boilerplate code like constructors, getters, toString(), equals(), and hashCode() methods.

import java.util.List;

//class Student{

// int age;

// String name;

// int Marks;

// public Student(int age, String name, int marks) {

// super();

// this.age = age;

// this.name = name;

// Marks = marks;

// }

// public int getAge() {

// return age;

// }

// public void setAge(int age) {

// this.age = age;

// }

// public String getName() {

// return name;
// }

// public void setName(String name) {

// this.name = name;

// }

// public int getMarks() {

// return Marks;

// }

// public void setMarks(int marks) {

// Marks = marks;

// }

// @Override

// public String toString() {

// // TODO Auto-generated method stub

// return this.name;

// }

//}

record Student(int age, String name, int marks) {

public class Stream2Ex {

public static void main(String[] args) {

// TODO Auto-generated method stub

List<Student> student=List.of(

new Student(20,"Ravi",70),

new Student(40,"Raju",80),

new Student(30,"Akash",90),

new Student(24,"Amit",95),

new Student(36,"Anit",30)

);

// System.out.println(student);
student.stream().filter(s->s.age()>30).forEach(System.out::println);

student.stream().filter(s->s.age()>30).forEach(s->System.out.println(s.name()));

Another Example:

public class RecordExample {

public static void main(String[] args) {

Person p = new Person("Alice", 30);

System.out.println(p.name()); // Getter

System.out.println(p); // toString() auto-generated

record Person(String name, int age) {}

Output:

Alice

Person[name=Alice, age=30]

Functional Interface Purpose Used As Example

Function<T, R> Takes input T, returns R Mapping Square, Even/Odd (String)

Consumer<T> Takes input T, returns void Consuming Print Even/Odd

Predicate<T> Takes input T, returns bool Testing Check if number is even

import java.util.function.Consumer;

import java.util.function.Function;

import java.util.function.Predicate;

public class FunPack {

public static void main(String[] args) {


// TODO Auto-generated method stub

//1

Function<Integer,Integer> square=(n)-> n*n;

System.out.println("Square: "+square.apply(10));

//2

Function<Integer, String> Evenodd=(n)-> n%2==0?"Even":"Odd";

System.out.println(Evenodd.apply(10));

//3

Consumer <Integer> Evenodd1=(n)-> {

if(n%2==0)

System.out.println("Even");

else

System.out.println("Odd");

};

Evenodd1.accept(21);

//4

Predicate <Integer> Evenodd2=(n)-> n%2==0? true:false;

if(Evenodd2.test(27)) {

System.out.println("Even");

else

System.out.println("Odd");

}
Base64 Encode and Decode in Java

Java provides built-in support for Base64 encoding and decoding through the java.util.Base64 class (introduced in Java 8).

import java.util.Base64;

public class Base64Example {

public static void main(String[] args) {

String originalInput = "HelloWorld123";

// Encode

String encodedString = Base64.getEncoder().encodeToString(originalInput.getBytes());

System.out.println("Encoded: " + encodedString);

// Decode

byte[] decodedBytes = Base64.getDecoder().decode(encodedString);

String decodedString = new String(decodedBytes);

System.out.println("Decoded: " + decodedString);

Output:

Encoded: SGVsbG9Xb3JsZDEyMw==

Decoded: HelloWorld123

Types of Base64 Encoders/Decoders in Java

Java provides 3 variants under Base64:

Method Description

Base64.getEncoder() Basic Base64 encoding (single-line)

Base64.getUrlEncoder() URL and Filename safe encoding

Base64.getMimeEncoder() MIME-friendly encoding (with line breaks)


Try-with-resources: Try-with-resources in Java is a feature introduced in Java 7 that helps automatically close resources
such as files, sockets, database connections, etc., once they are no longer needed. This eliminates the need for writing
explicit finally blocks to close these resources.

Key Points

 Works with classes that implement the AutoCloseable interface (or Closeable, which extends AutoCloseable).

 Resources are closed automatically, regardless of whether the try block completes normally or abruptly.

Syntax:

try (ResourceType resource = new ResourceType()) {

// Use the resource

} catch (Exception e) {

e.printStackTrace();

Program:

import java.io.File;

import java.io.FileNotFoundException;

import java.util.Scanner;

public class TrywithResource {

public static void main(String[] args) {

// try with resource

File file = new File("C:\\Users\\hp\\eclipse-workspace\\JAVAFDP\\src\\SwitchExp.java");

try (Scanner scanner = new Scanner(file)) {

while (scanner.hasNextLine()) {

System.out.println(scanner.nextLine());

} catch (FileNotFoundException e) {

e.printStackTrace();

}
Type annotations in Java were introduced with Java 8 (JSR 308) to allow annotations to be placed anywhere a type is used,
not just on declarations. This makes annotations more powerful, especially for tools that analyze or verify code such as
static analyzers, frameworks, or compilers.

Where You Can Use Type Annotations

You can now place annotations in these places:

1. On variable declarations

2. On generic type arguments

3. On casts

4. On implements and extends clauses

5. On method return types

6. On parameters and constructor references

7. On array types

import java.lang.annotation.*;

import java.util.List;

// Define a custom annotation for type use

@Target(ElementType.TYPE_USE)

@Retention(RetentionPolicy.RUNTIME)

@interface NonNull {}

public class TypeAnnotationDemo {

// Field with a type annotation

private @NonNull String name;

// Constructor with type annotation on parameter

public TypeAnnotationDemo(@NonNull String name) {

this.name = name;

// Method with annotated return type and parameter

public @NonNull String greet(@NonNull String greeting) {

return greeting + ", " + name + "!";

}
public void processList() {

// Annotated variable

List<@NonNull String> items = List.of("Apple", "Banana", "Cherry");

for (@NonNull String item : items) {

System.out.println("Item: " + item);

public static void main(String[] args) {

TypeAnnotationDemo demo = new TypeAnnotationDemo("Alice");

System.out.println(demo.greet("Hello"));

demo.processList();

The Java Module System: It 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

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
Diamond Syntax with Inner Anonymous Class: The diamond operator (<>) allows the compiler to infer generic types,
reducing boilerplate code. However, when it comes to anonymous inner classes, support for the diamond operator was not
available before Java 9.

import java.util.*;

public class DiamondAnonymousExample {

public static void main(String[] args) {

// Diamond operator with anonymous inner class (Java 9+)

Comparator<String> comp = new Comparator<>() {

@Override

public int compare(String a, String b) {

return a.length() - b.length();

};

List<String> list = new ArrayList<>(List.of("banana", "apple", "cherry"));

list.sort(comp);

System.out.println(list); // Output: [apple, banana, cherry]

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) {

// Local Variable type inference

var num=10;

System.out.println(num);

var name=new String("KIET");


System.out.println(name);

var var=5;// var is not a keyword

System.out.println(var);

String name1="KIET";

if(name1 instanceof String s)

System.out.println(s);

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.

public class SwitchExp {

public static void main(String[] args) {

// TODO Auto-generated method stub

/*int value=25;

switch(value) {

case 1,2,3,4-> System.out.println("1-4");

case 5,6,7-> System.out.println("5-7");

case 10-> System.out.println("10");

default->System.out.println("Not Found");

}*/

/*int value=25;

String result=switch(value) {

case 1,2,3,4-> "1-4";

case 5,6,7-> "5-7";


case 10-> "10";

default->"Not Found";

};

System.out.println(result);*/

int value=25;

String result=switch(value) {

case 1,2,3,4: yield "1-4";

case 5,6,7:yield "5-7";

case 10: yield "10";

default: yield"Not Found";

};

System.out.println(result);

TextBlock: Text Blocks were introduced in Java 13 (preview) and standardized in Java 15. They provide a clean and concise
way to write multi-line strings without using escape characters (\n, \", etc.).

public class TextBlockEx {

public static void main(String[] args) {

// Text Block Example....

String data="""

This is my original Data

My data is good

Another line""";

System.out.println(data);}}

Sealed Classes in java: Sealed classes and interfaces were introduced in Java 15 (as a preview) and became standard in Java
17. They allow you to restrict which classes can extend or implement a class or interface.
Sealed classes are useful when you want controlled inheritance — only specific subclasses are allowed. This is especially
helpful in modeling fixed hierarchies, like:

 Shape types (Circle, Rectangle, etc.)

 Domain models (User, Admin, Guest)

Syntax Overview:

public sealed class Shape permits Circle, Rectangle, Triangle {

// common shape code

Subclasses must be:

 final (no further subclassing), or

 sealed (continued restriction), or

 non-sealed (removes the restriction)

Example:

// Sealed parent class

public sealed class Shape permits Circle, Rectangle { }

// Final subclass

public final class Circle extends Shape {

double radius;

// Another final subclass

public final class Rectangle extends Shape {

double length, width;

}
Program:

// File: ShapeDemo.java

sealed class Shape permits Circle, Rectangle, Triangle {

public double area() {

return 0.0;

// Final class — cannot be extended further

final class Circle extends Shape {

double radius = 5.0;

@Override

public double area() {

return Math.PI * radius * radius;

// Final class — cannot be extended further

final class Rectangle extends Shape {

double length = 10.0;

double width = 4.0;

@Override

public double area() {

return length * width;

// Non-sealed class — can be extended further

non-sealed class Triangle extends Shape {

double base = 6.0;

double height = 3.0;

@Override
public double area() {

return 0.5 * base * height; }}

// A subclass of non-sealed Triangle

class RightAngledTriangle extends Triangle {

// Inherits area() method from Triangle

public class SealedClassExp {

public static void main(String[] args) {

Shape shape = new Tring(); // You can change this to new Circle(), etc.

String type;

if (shape instanceof Circle) {

type = "Circle";

} else if (shape instanceof Rect) {

type = "Rectangle";

} else if (shape instanceof RightAng) {

type = "Right-Angled Triangle";

} else if (shape instanceof Tring) {

type = "Triangle";

} else {

throw new IllegalArgumentException("Unexpected shape type");

System.out.println("Shape Type: " + type);

System.out.println("Area: " + shape.area());

}
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

You might also like