Unit-13 Complete
Unit-13 Complete
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;
displayPrivate(); }
@Override
System.out.println("My Message");}
d.printMsg();
d.display();
Message.displayStatic();
}
}
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
@FunctionalInterface annotation is optional but recommended — it tells the compiler to ensure the interface has only one
abstract method.
Program:2
@FunctionalInterface
interface Calculator {
@Override
return n1+n2;
};
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 {
class Sum{
return n1+n2; }
class Mul{
return n1*n2; }
Calculato c = s::mysum;
int abc=c.add(10,20);
System.out.println("Sum is"+abc);
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");
}
}
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.
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 {
names.stream()
.map(String::toUpperCase)
.distinct()
.forEach(System.out::println);
Collecting Results
.collect(Collectors.toList());
.filter(n -> n % 2 == 0)
.map(n -> n * n)
.collect(Collectors.toList());
import java.util.List;
import java.util.OptionalInt;
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);
System.out.println(evensum);
import java.util.List;
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);
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;
// super();
// this.age = age;
// this.name = name;
// Marks = marks;
// }
// return age;
// }
// this.age = age;
// }
// return name;
// }
// this.name = name;
// }
// return Marks;
// }
// Marks = marks;
// }
// @Override
// return this.name;
// }
//}
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:
System.out.println(p.name()); // Getter
Output:
Alice
Person[name=Alice, age=30]
import java.util.function.Consumer;
import java.util.function.Function;
import java.util.function.Predicate;
//1
System.out.println("Square: "+square.apply(10));
//2
System.out.println(Evenodd.apply(10));
//3
if(n%2==0)
System.out.println("Even");
else
System.out.println("Odd");
};
Evenodd1.accept(21);
//4
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;
// Encode
// Decode
Output:
Encoded: SGVsbG9Xb3JsZDEyMw==
Decoded: HelloWorld123
Method Description
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:
} catch (Exception e) {
e.printStackTrace();
Program:
import java.io.File;
import java.io.FileNotFoundException;
import java.util.Scanner;
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.
1. On variable declarations
3. On casts
7. On array types
import java.lang.annotation.*;
import java.util.List;
@Target(ElementType.TYPE_USE)
@Retention(RetentionPolicy.RUNTIME)
@interface NonNull {}
this.name = name;
}
public void processList() {
// Annotated variable
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.*;
@Override
};
list.sort(comp);
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 num=10;
System.out.println(num);
System.out.println(var);
String name1="KIET";
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.
/*int value=25;
switch(value) {
default->System.out.println("Not Found");
}*/
/*int value=25;
String result=switch(value) {
default->"Not Found";
};
System.out.println(result);*/
int value=25;
String result=switch(value) {
};
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.).
String 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:
Syntax Overview:
Example:
// Final subclass
double radius;
}
Program:
// File: ShapeDemo.java
return 0.0;
@Override
@Override
@Override
public double area() {
Shape shape = new Tring(); // You can change this to new Circle(), etc.
String type;
type = "Circle";
type = "Rectangle";
type = "Triangle";
} else {
}
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