0% found this document useful (0 votes)
0 views18 pages

UNIT-03 Java

The document discusses various Java concepts, including functional interfaces, lambda expressions, method references, and the Stream API. It explains how these features enhance code readability, maintainability, and support functional programming. Additionally, it covers default and static methods in interfaces, Base64 encoding, and resource management with try-with-resources, highlighting their significance in modern Java development.
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)
0 views18 pages

UNIT-03 Java

The document discusses various Java concepts, including functional interfaces, lambda expressions, method references, and the Stream API. It explains how these features enhance code readability, maintainability, and support functional programming. Additionally, it covers default and static methods in interfaces, Base64 encoding, and resource management with try-with-resources, highlighting their significance in modern Java development.
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/ 18

UNIT-03 JAVA

✅ Q1. What are Functional Interfaces in Java? Give some predefined functional interfaces
like java.lang.Runnable, java.util.Comparator, java.util.function.Predicate,
java.util.function.Function, java.util.function.Supplier.
Answer:
In Java, a functional interface is an interface that contains only one abstract method (also
called a Single Abstract Method or SAM interface). These interfaces are used primarily to
support functional programming concepts in Java and serve as the foundation for lambda
expressions and method references, introduced in Java 8.
A functional interface may also contain default and static methods in addition to the
abstract one. Java provides the @FunctionalInterface annotation to explicitly indicate that
the interface is intended to be functional, helping developers and compilers enforce the
single-method rule.
✳️Key Characteristics:
 Contains exactly one abstract method
 Can have multiple default and static methods
 Can be instantiated using lambda expressions
 Supports cleaner and more concise code structure
✳️Common Predefined Functional Interfaces:

Interface Package Method Purpose

Represents a task to be executed


Runnable java.lang void run()
(used in threading)

int compare(T o1,


Comparator<T> java.util Compares two objects for sorting
T o2)

Checks a condition and returns


Predicate<T> java.util.function boolean test(T t)
true/false

Function<T, R> java.util.function R apply(T t) Takes input of type T and returns R

Supplier<T> java.util.function T get() Supplies a value without input

✅ Q2. Explain lambda expressions in Java and provide examples of their usage.
Answer:
Lambda expressions are a powerful feature introduced in Java 8 that allow developers to
write concise, anonymous implementations of functional interfaces. They provide a clear
and simple way to represent a method using expressions, enabling functional programming
in Java.
Before lambda expressions, implementing a functional interface required writing verbose
anonymous inner classes. With lambdas, this is reduced to a single line, making the code
more readable and maintainable.
✳️Syntax of Lambda Expression:
(parameters) -> { expression or statements }

 No parameter: () -> System.out.println("Hello");


 One parameter: x -> x * x
 Multiple parameters: (a, b) -> a + b
✳️Key Features:
 Used to implement functional interfaces
 Enables inline behavior passing
 Supports clean and concise syntax
 Encourages functional-style operations (especially with Stream API)
✳️Use Cases:
 Threading (Runnable)
 Event handling
 Stream operations like map(), filter(), reduce()
 Functional interfaces like Predicate, Function, Consumer
Lambda expressions simplify development by replacing complex anonymous classes with
short and expressive code blocks, enhancing both performance and clarity.
✅ Q3. How do functional interfaces in Java relate to lambda expressions?
Answer:
Functional interfaces and lambda expressions are deeply connected in Java's functional
programming model. A lambda expression can only be used where a functional interface is
expected, making functional interfaces the backbone of lambda expressions.
✳️Relationship Explained:
 A lambda expression does not have a type by itself — it requires a context in which a
functional interface is used.
 The Single Abstract Method (SAM) of the functional interface becomes the target of
the lambda.
 The lambda implements that method at runtime.
✳️Summary of Relationship:
 Lambda expressions require a functional interface.
 The compiler uses the target functional interface to infer the parameter types and
return type of the lambda.
 Without functional interfaces, lambdas cannot be used.
✅ Q4. Explain method references in Java with its types.
Answer:
Method references in Java are a shorthand form of lambda expressions that invoke existing
methods. They enhance code clarity by directly referencing a method without executing it,
using the double colon operator ::.
A method reference can be used whenever a lambda expression only calls an existing
method. This makes the code more concise and readable.
✳️Syntax:
ClassName::methodName
objectReference::methodName
✳️Types of Method References:
1. Reference to a Static Method:
o Syntax: ClassName::staticMethod

2.Reference to an Instance Method of a Particular Object:

Syntax: objectRef::instanceMethod

3.Reference to an Instance Method of an Arbitrary Object of a Particular Type:


 Syntax: ClassName::instanceMethod
4.Reference to a Constructor:
 Syntax: ClassName::new

✳️Advantages:

 Reduces boilerplate lambda code


 Improves code readability and structure
 Encourages declarative style of programming
✅ Q5. How do method references simplify code in Java? Provide examples like
readability, elimination of repugnant code, improved maintainability,
simplified constructor invocation.

Answer:

Method references greatly simplify Java code by providing a short, elegant way to refer to
already existing methods or constructors, instead of writing full lambda expressions. This
leads to improved code clarity, reduced verbosity, and enhanced maintainability,
especially when working with collections and functional interfaces.

✳️How They Simplify Code:

1. Improved Readability:
Method references directly state which method is being used without wrapping it in a
lambda.
2.  Eliminates Redundant Code:
When a lambda does nothing but call another method, a method reference removes
that duplication.
3.  Simplified Constructor Invocation:
Constructors can be referenced easily without creating a full factory method or
lambda.
4.  Enhanced Maintainability:
Since method references avoid anonymous class structures and complex lambdas, the
code becomes easier to maintain and refactor.
5.  Declarative Programming Style:
Encourages a declarative, functional style over imperative code, especially useful in
streams.

✅ Q6. Describe Stream API. Write down the features of a stream like declarative and
functional style, lazy evaluation, parallel execution, interoperability, pipelining, and common
operations.
Answer:
The Stream API, introduced in Java 8, is a powerful abstraction for processing sequences of
elements (like collections) using a declarative and functional programming approach.
Streams support operations like filtering, mapping, reducing, and collecting data efficiently
and in a chainable way.
✳️Key Features of Stream API:
1. Declarative and Functional Style:
o Allows writing SQL-like, high-level queries on data.
o Code becomes concise, readable, and easier to maintain.

 Lazy Evaluation:
 Intermediate operations are not executed immediately.
 Evaluation happens only when a terminal operation is invoked.
 Enhances performance.
 Parallel Execution:
 Streams can be executed in parallel using parallelStream().
 Utilizes multicore architectures for better speed.
 Interoperability with Collections and Arrays:
 Easily created from collections, arrays, or values using:
o collection.stream()
o Stream.of(...)
o Arrays.stream(...)
 Pipelining:
 Stream operations can be chained together.
 The result of one operation flows into the next like a pipeline.
 Common Operations:
 Intermediate: map(), filter(), sorted(), distinct()
 Terminal: collect(), forEach(), reduce(), count()
✅ Q7. Discuss the purpose and usage of the Stream API in Java, including creating streams,
intermediate operations, terminal operations, chaining operations, and concurrency.
Answer:
The primary purpose of the Stream API is to enable developers to process collections of data
in a functional, readable, and efficient manner. It abstracts away the complexity of iterating
over collections and allows chainable data operations, improving both performance and
clarity.
✳️Purpose:
 To provide a functional-style API for data processing.
 To reduce boilerplate code in for-loops and conditional logic.
 To support parallel processing and lazy evaluation.
 To enable clear chaining of data operations.
✳️Usage Overview:
1. Creating Streams:
o From Collections:
list.stream()
o From Arrays:
Arrays.stream(array)
o Using Stream.of():
Stream.of("A", "B", "C")
2. Intermediate Operations:
o Transform the data but return a stream.
o Examples: filter(), map(), sorted(), limit()
3. Terminal Operations:
o End the stream pipeline and produce a result.
o Examples: forEach(), collect(), reduce(), count()
4. Chaining Operations (Pipelining):
5. Concurrency (Parallel Streams):
o Use .parallelStream() for multi-threaded data processing.
o Enhances performance for large datasets.
The Stream API enables high-performance and expressive data processing in Java, moving
away from imperative loops to more elegant pipelines.

✅ Q8. What are default methods in Java interfaces? Give key features of default methods.
Answer:
Default methods in Java were introduced in Java 8 to allow interfaces to have concrete
method implementations. This was a significant change, as interfaces earlier could only
have abstract methods. Default methods help evolve interfaces without breaking the
existing implementation classes.

FOR EX;
interface Vehicle {
default void start() {
System.out.println("Vehicle starting...");
}
}
✳️Key Features:
1. Concrete Implementation in Interface:
o Can provide reusable logic directly inside an interface.
2. Backward Compatibility:
o Allows adding new methods without breaking existing code.
3. Optional Override:
o Implementing classes can override the default method if needed.
4. Works with Multiple Inheritance:
✅ Q8. What are default methods in Java interfaces? Give key features of default methods.
Answer:
Default methods were introduced in Java 8 to allow interfaces to include method
implementations along with abstract methods. Before this, interfaces could only declare
method signatures. The main purpose was to ensure backward compatibility when new
methods are added to interfaces without affecting the classes that already implement them.
This became necessary when interfaces like List, Map, and Iterable had to be extended for
lambda expressions and the Stream API.
✳️Key Features:
 Declared using the default keyword in the interface.
 Can provide a method body inside the interface.
 Implementing classes can use them directly or override if needed.
 Do not break existing code when new methods are added.
 Help implement multiple inheritance of behavior in interfaces.
Example:
A default method like sort() was added to the List interface without breaking existing
implementations.
Default methods thus enable Java interfaces to evolve smoothly while preserving
compatibility and allowing behavior sharing.
✅ Q9. How do default methods enable backward compatibility?
Answer:
Backward compatibility means that existing code continues to work even when the
underlying interfaces evolve. In Java, before version 8, if a new method was added to an
interface, all implementing classes had to implement that new method, or they would break.
With default methods, interfaces can now provide a default implementation for new
methods, so existing implementing classes don't need to change unless they want to
override the default behavior.
✳️How it works:
 Interface methods with the default keyword come with a body.
 Any class that implements the interface will inherit the method automatically.
 If the class wants a custom version, it can override the default method.
Benefit:
Enables enhancement of widely-used interfaces like List or Collection without disturbing the
large codebases that rely on them.
Thus, default methods serve as a bridge between legacy code and modern features, making
Java more robust and flexible.

✅ Q10. Explain the concept of static methods in Java interfaces. What are the features of
static methods?
Answer:
Static methods in interfaces, introduced in Java 8, allow developers to define utility or
helper methods within the interface itself. Unlike default methods, static methods cannot
be inherited by implementing classes — they belong to the interface only and must be
called using the interface name.
This change helped to group related utility methods with the interfaces they operate on,
improving modularity and design.
✳️Features:
 Declared using the static keyword in the interface.
 Must be accessed using the interface name (not by implementing class or instance).
 Help organize utility methods closely with the interface they serve.
 Promote cleaner API design and encapsulation of behavior.
Example use-case:
The Comparator interface includes static methods like comparing() and naturalOrder() to
help create comparison logic.
In summary, static methods in interfaces offer a structured way to include related logic
without needing separate utility classes.
✅ Q11. Explain Base64 encode and decode in TTL.
Answer:
Base64 is a binary-to-text encoding scheme used to represent binary data in an ASCII string
format. It converts data into a radix-64 representation, making it safe for transmission across
networks that handle only textual data. In contexts like TTL (Time To Live) tokens or secure
API communications, Base64 encoding is used to represent encrypted payloads or
authentication tokens that often include TTL information inside.
Though Base64 itself does not define or enforce TTL, it is frequently used to encode data
structures that include expiry information, such as JWTs (JSON Web Tokens), signed URLs,
or temporary access keys. TTL refers to the valid time period after which the token or data is
considered expired.
✳️Why Base64 is used with TTL:
 Makes binary or sensitive data readable and transmittable over text protocols (like
HTTP).
 Helps secure and encode expiration-bound credentials or keys.
 Encapsulates metadata like issue time and expiry in a transport-safe string.
Conclusion:
Base64 encoding helps encode TTL-bound data structures securely and efficiently, enabling
safer communication between systems while maintaining the integrity of data lifespan.

✅ Q12. How can you perform Base64 encoding and decoding in Java? Give algorithm.
Answer:
Java provides built-in support for Base64 operations through the java.util.Base64 class,
introduced in Java 8. This class provides static methods to encode and decode data using
MIME, basic, and URL-safe encoding schemes.
✳️Algorithm for Encoding:
1. Convert the input string or file content into a byte[].
2. Use Base64.getEncoder() to get an encoder instance.
3. Call encodeToString(byte[]) or encode(byte[]).
✳️Algorithm for Decoding:
1. Use Base64.getDecoder() to get a decoder.
2. Call decode(String) on the encoded string to get the byte array.
3. Convert the bytes back to the original string if needed.
✳️Steps in Java:
 Encoding:
Input → byte[] → encode → Base64 String
 Decoding:
Base64 String → decode → byte[] → Original String
Conclusion:
Using Base64 in Java is simple, efficient, and well-suited for handling sensitive data or
temporary tokens where secure encoding is necessary.

✅ Q13. Describe the forEach method in Java and its significance in collections processing.
Answer:
The forEach() method is a default method introduced in the Iterable interface in Java 8. It
allows iteration over a collection using lambda expressions or method references, enabling
a functional approach to processing elements.
✳️Significance in Collections Processing:
1. Improved Readability: Eliminates boilerplate for loops.
2. Functional Style: Works well with lambda expressions.
3. Cleaner Code: Encourages inline processing logic.
4. Stream Compatibility: Integrates seamlessly with Stream API pipelines.
✳️Functional Usage:
The method accepts a Consumer<T> functional interface, which takes an element and
performs an action on it.
✳️Where It’s Commonly Used:
 Processing items in lists, sets, or queues
 Inline data transformations
 Logging or debugging collection elements
 Updating UI or sending output to external systems
Conclusion:
The forEach() method simplifies and modernizes collection processing, encouraging
declarative, concise, and expressive Java code.

✅ Q14. What is the try-with-resources statement in Java? How does it simplify resource
management?
Answer:
The try-with-resources statement, introduced in Java 7, is a special form of the try block
designed for working with resources like files, streams, sockets, or database connections. It
ensures that resources are automatically closed after the operation, preventing resource
leaks and exceptions during cleanup.
✳️How It Works:
 A resource must implement the AutoCloseable or Closeable interface.
 The resource is declared inside the try block.
 It is automatically closed once the block completes — whether normally or via an
exception.
✅ Q15. Explain Type Annotations and their role in Java.
Answer:
Type Annotations, introduced in Java 8 through JSR 308, extend Java's annotation system to
allow annotations to be written wherever a type is used, not just on declarations. This
allows developers and tools to analyze and enforce additional constraints on types.
✳️Examples of Use:
 Annotating generic types: List<@NonNull String>
 Casting: (@NonNull Object) obj
 Method return types: @Readonly String getValue()
 Method parameters or array elements
✳️Role and Benefits:
1. Static Analysis and Error Detection: Tools can catch null-pointer issues, immutability
violations, etc., at compile time.
2. Improved Documentation: Indicates developer intent more clearly.
3. Better Tooling Support: Enhances support for frameworks that enforce safety or
design constraints.
4. Increased Type Safety: Helps in developing critical or secure applications.
Conclusion:
Type annotations improve type precision, validation, and documentation, making Java code
more robust and reliable, especially in combination with static analysis tools.
✅ Q16. What are Repeating Annotations and how are they used in Java?
Answer:
Repeating annotations, introduced in Java 8, allow the same annotation to be applied
multiple times to the same declaration or type. Earlier in Java, an annotation could only be
applied once at a given location. Repeating annotations solve this limitation by providing a
container annotation that holds multiple instances of the same annotation.
✳️How Repeating Annotations Work:
 A container annotation holds an array of the repeating annotation.
 The repeating annotation must be marked with @Repeatable, and the container
class must be specified.
✳️Benefits:
 More expressive and readable.
 Useful in scenarios like scheduling, tagging, logging, role-based access, etc.
 Better organized metadata for frameworks and tools.
✅ Q17. Discuss the Java Module System and its advantages.
Answer:
The Java Module System, introduced in Java 9 (Project Jigsaw), is a structural improvement
to organize large Java applications. It provides a way to modularize code, clearly defining
which parts are exposed and which are internal.
It introduces the module-info.java descriptor file, which specifies:
 What packages the module exports
 What other modules it requires
✳️Advantages:
1. Strong Encapsulation: Only exported packages are accessible outside the module.
2. Better Maintainability: Clear structure and separation of concerns.
3. Custom Runtime Images: Enables building small, custom runtimes with jlink.
4. Avoids Classpath Conflicts: Replaces the error-prone classpath with module paths.
5. Enhanced Security: Internal packages cannot be accessed unless explicitly exported.
6. Improved Performance: Reduces runtime footprint and optimizes dependency
loading.

✅ Q18. What is Diamond Syntax in Java?

Answer:

The Diamond Syntax (<>) was introduced in Java 7 to simplify the declaration of generic
types. It allows the compiler to infer type parameters on the right-hand side of an object
creation expression, reducing code duplication and improving readability.

✳️Example (Before Java 7):

List<String> list = new ArrayList<String>();

✳️With Diamond Syntax:

List<String> list = new ArrayList<>();

✳️Benefits:

1. Less Verbose Code: Avoids repeating type parameters.


2. Type Safety: Compiler ensures correctness via type inference.
3. Improved Readability: Cleaner and simpler declarations.
4. Supports Anonymous Classes (Java 9+):
From Java 9, diamond syntax is also allowed with anonymous inner classes.

✅ Q19. What do you mean by Inner Anonymous Classes in Java?


Answer:
An inner anonymous class in Java is a class without a name, declared and instantiated at
the same time. It is used to override or implement methods of a class or interface in a
concise manner, typically when the class is needed only once.
Anonymous inner classes are often used in:
 GUI event handling
 Thread creation
 Callbacks and listeners
✳️Key Features:
 Can access final or effectively final variables from the enclosing scope.
 Cannot have a constructor since it's unnamed.
 Can extend a class or implement an interface, but not both at the same time.
✳️Use Cases:
 Reducing boilerplate for one-time implementations.
 Inline logic for event-driven code.
 Improving encapsulation in limited-scope code.

✅ Q20. How does the Diamond Syntax work with Inner Anonymous Classes in
Java?

Answer:

Prior to Java 9, the diamond operator (<>) could not be used when creating anonymous
inner classes with generics because type inference did not work correctly with unnamed
classes.

From Java 9 onward, Java supports diamond syntax with anonymous inner classes as
long as the compiler can infer the type based on the context. This improvement reduces
verbosity even in anonymous class instantiations.

Map<String, Integer> map = new HashMap<>() {


{
put("A", 1);
put("B", 2);
}
};

✳️Benefits:
 Cleaner code with reduced redundancy.
 Retains full functionality of anonymous classes.
 Works well in one-time use utility structures.

✅ Q21. What is local variable type inference and how does it improve code readability?
Answer:
Local Variable Type Inference was introduced in Java 10 through the var keyword. It allows
the compiler to infer the type of local variables at compile-time, eliminating the need for
developers to explicitly declare the type when it is already clear from the right-hand side.
✳️Key Benefits:
1. Improved Readability: Reduces clutter in complex type declarations like:
2. Less Verbosity: Reduces boilerplate when types are obvious from context.
3. Consistent Naming Style: Encourages meaningful variable names since the type is
not written explicitly.
4. Maintains Type Safety: Despite implicit declaration, Java is still strongly typed; types
are inferred, not dynamic.
✳️Restrictions:
 Can’t be used for fields, method parameters, or return types.
 Must be initialized at the point of declaration.

✅ Q22. Explain switch expressions in Java and how they differ from traditional switch
statements.
Answer:
Switch expressions, introduced in Java 14 (preview in Java 12), are an enhanced version of
traditional switch statements. They allow the switch block to return a value, making them
more concise and expressive.
✳️Differences in Tabular Format:

Feature Traditional Switch Switch Expression

Syntax Verbose with break Concise with ->

Return Value Cannot return values directly Can return values using yield or expression

Fall-through Possible if break is missed No fall-through by default

Safety Error-prone due to missing breaks Safer, no accidental fall-through

✅ Q23. What is the yield keyword in Java? Provide examples of its usage.
Answer:
The yield keyword was introduced along with switch expressions in Java 13 to return a value
from a case block within a switch expression. It replaces the need for return inside multi-
statement case blocks when using switch expressions.
✳️Usage:
 Inside a switch expression (not statement).
 Used when a case has multiple lines of code.

✅ Q24. Discuss text blocks in Java and their benefits in string manipulation.
Answer:
Text Blocks, introduced in Java 15, are a new syntax for writing multi-line string literals in a
more readable and structured format. They eliminate the need for escape characters like \n,
and improve the formatting of JSON, SQL, HTML, or XML content embedded in strings.
✳️Syntax:
String json = """
{
"name": "Vishakha",
"age": 22
}
""";
✳️Benefits:
1. Improved Readability: No need for escape sequences; maintains the layout of
structured text.
2. Cleaner Code: Removes the clutter of + signs and \n in long strings.
3. Better Maintenance: Easy to read, edit, and copy-paste structured data.
4. Safer Formatting: Supports automatic indentation normalization.
✳️Use Cases:
 Writing SQL queries
 Embedding JSON or XML
 HTML templates
 Long descriptions or documentation strings
Conclusion:
Text blocks make Java more suitable for working with multi-line or formatted strings,
resulting in cleaner, easier-to-read code that matches the structure of the original data.

✅ Q25. What are records in Java and how do they simplify the creation of immutable data?
Answer:
Records, introduced in Java 16, are a special kind of class designed to model immutable
data. They act as data carriers, automatically generating boilerplate code such as
constructors, equals(), hashCode(), and toString().
✳️Syntax:
java
CopyEdit
public record Student(String name, int age) {}
✳️How They Simplify Immutable Data:
 Declaring a record automatically creates:
o Constructor
o Getters (no get prefix)
o equals() and hashCode()
o toString() method
 Fields are final and private — no setters, ensuring immutability.
✳️Benefits:
 Eliminates boilerplate code.
 Enhances code clarity and intent.
 Ideal for DTOs, API responses, or data modeling.
Conclusion:
Records promote a clean and concise way to create immutable, value-based classes, making
Java better aligned with functional programming and modern design practices.

✅ Q26. Explain sealed classes in Java and their role in controlling inheritance hierarchies.
Answer:
Sealed classes, introduced in Java 17, provide a mechanism to restrict which classes or
interfaces can extend or implement them. They allow developers to control the type
hierarchy more precisely, which is helpful for domain modeling and pattern matching.
✳️Role in Controlling Inheritance:
 Only the specified permits classes can extend the sealed class.
 Helps in defining closed hierarchies, useful in modeling known types.
 Improves pattern matching and exhaustiveness checking in switch expressions
(future-proofing Java).
✳️Subclasses must be explicitly marked as:
 final – cannot be extended further
 sealed – can be extended with permission
 non-sealed – open for extension
✳️Benefits:
 Enforces better control over type design.
 Enhances maintainability and security.
 Supports future pattern matching features in Java.

You might also like