unit 3 java
unit 3 java
A functional interface in Java is an interface that contains exactly one abstract method. It can have
any number of default or static methods, but only one abstract method.
Functional interfaces are the basis for lambda expressions and method references in Java.
Characteristics:
@FunctionalInterface
interface Calculator {
(parameters) -> {
// multiple statements
return result;
@FunctionalInterface
interface MyOperation {
Syntax:
ClassName::staticMethod
instance::instanceMethod
Example:
// Using lambda
names.forEach(System.out::println);
When to Use:
• Improves readability
The Stream API lets you perform complex operations on data collections (like List, Set, etc.) in a
declarative, functional manner.
import java.util.*;
import java.util.stream.*;
names.stream()
▶ Output:
ALICE
AMANDA
A default method is a method in an interface that has a body (implementation) and uses the default
keyword.
Purpose:
• Add new functionality to interfaces without breaking existing classes that implement them.
Syntax:
interface MyInterface {
Example:
interface A {
class B implements A {
⚠ Note on Conflict:
If two interfaces provide default methods with the same signature, the implementing class must
override it.
interface A {
interface B {
class C implements A, B {
A static method in an interface is associated with the interface itself — not the instance — and
cannot be overridden.
Syntax:
interface Utility {
}
Usage:
1. Statement
Definition:
Base64 encoding is a way to convert binary data (e.g., files, images, strings) into ASCII characters. It's
commonly used to transmit data over media that are designed to deal with textual data (e.g., email,
JSON, URLs).
Java 8 introduced the java.util.Base64 class to handle encoding and decoding operations.
2. forEach() Method
Definition:
The forEach() method is a default method introduced in Java 8 for the Iterable and Stream
interfaces. It allows performing an action on each element of a collection using lambda expressions
or method references.
import java.util.*;
}
3. Try-With-Resources
Definition:
The try-with-resources statement (introduced in Java 7) automatically closes resources such as files,
sockets, or database connections once they are no longer needed. Resources must implement the
AutoCloseable interface.
Example:
import java.io.*;
} catch (IOException e) {
e.printStackTrace();
Definition:
Type annotations are annotations that can be applied wherever a type is used — not just on
declarations like classes, methods, or variables.
They were introduced in Java 8 (JSR 308) to enable stronger type checking and more powerful
compile-time and runtime analysis.
• Allows frameworks like Checker Framework, FindBugs, or SpotBugs to validate code more
deeply
Example:
➤ Define a custom type annotation:
• import java.lang.annotation.*;
•
• @Target(ElementType.TYPE_USE)
• @Retention(RetentionPolicy.RUNTIME)
• @interface NonNull {}
➤ Apply it:
The @NonNull annotation here means the object should not be null — tools
can catch violations.
Definition:
Repeating annotations allow you to apply the same annotation multiple times to
the same declaration or type use.
This feature was introduced in Java 8 to improve clarity and support use cases where
multiple values of the same annotation are needed.
How It Works:
The Java Module System was introduced in Java 9 under the Jigsaw Project. It
allows you to define modules within your application, enabling better encapsulation,
modularization, and dependency management for large applications.
A module is a group of related packages that are treated as a single unit. It defines
its dependencies on other modules and can specify which of its packages should be
visible to other modules.
Definition:
An anonymous class in Java is a class without a name that is used to instantiate and
define a class that implements an interface or extends a class on the fly, often in a
single expression. These are commonly used for one-time implementations of
classes or interfaces, especially when you don't need to create a separate named class.
};
thread.start();
Explanation:
Here, an anonymous class implements the Runnable interface and overrides the run()
method.
The diamond syntax (<>) in Java was introduced in Java 7 and provides a simpler
way to define the type of a generic object without needing to specify the type on both
sides of the assignment. It works by letting the compiler infer the type on the right-
hand side based on the left-hand side.
Definition:
Local variable type inference was introduced in Java 10 with the var keyword. It
allows the compiler to infer the type of a local variable based on the context,
eliminating the need to explicitly specify the variable's type. The type of the variable
is determined at compile-time and cannot be changed later.
In simpler terms, you can use var to let the compiler figure out the type of a variable,
improving code readability and reducing verbosity
The switch statement has been a part of Java since its early versions, but Java 12
introduced switch expressions, which enhance the traditional switch statement by
providing more flexibility, conciseness, and safety.
Switch expressions allow returning a value from a switch block, using multiple
labels for a case, and provide the option for fall-through behavior to be controlled
more easily.
Before Java 12, the switch statement was used only for executing statements based
on a variable’s value, but now with switch expressions, you can return a value
directly from the switch.
int day = 3;
};
System.out.println(result); // Output: Wednesday
int day = 3;
case 3 -> {
// Multiple statements
};
Introduced in Java 13, Text Blocks provide a more readable and convenient way to
work with multi-line strings. Before text blocks, multi-line strings in Java were often
cumbersome and required handling escape sequences like \n for new lines and \t for
indentation. Text blocks offer a cleaner, more intuitive syntax for defining multi-line
string literals.
Text blocks in Java are defined using triple double quotes """, which allows for multi-
line strings to be written directly in the source code.
This is a
multi-line string
""";
Introduction to Records:
Introduced in Java 14 as a preview feature and finalized in Java 16, records are a
special kind of class in Java designed to model immutable data in a compact and
concise way. Records simplify the creation of data-carrier classes by automatically
generating several useful methods (e.g., toString(), equals(), hashCode(), and getters)
based on the fields of the class.
In traditional Java, for classes that were just used to hold data, developers had to
manually write boilerplate code for constructors, getters, toString(), equals(), and
hashCode() methods. With records, this repetitive task is automated, leading to more
readable and maintainable code.
A sealed class is a class that cannot be subclassed freely. Instead, you can define a
set of specific subclasses (or implementers) that are allowed to extend or implement
the sealed class.