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

OOPs Unit 3 Notes

The document discusses various new features in Java, including abstract methods, interfaces, functional interfaces, method references, and the Stream API. It also covers enhancements like default and static methods in interfaces, Base64 encoding, try-with-resources, type annotations, and the Java Module System. Additionally, it highlights features introduced in recent Java versions, such as diamond syntax, local variable type inference, switch expressions, text blocks, records, and sealed classes.

Uploaded by

Anil Kaushik
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)
2 views24 pages

OOPs Unit 3 Notes

The document discusses various new features in Java, including abstract methods, interfaces, functional interfaces, method references, and the Stream API. It also covers enhancements like default and static methods in interfaces, Base64 encoding, try-with-resources, type annotations, and the Java Module System. Additionally, it highlights features introduced in recent Java versions, such as diamond syntax, local variable type inference, switch expressions, text blocks, records, and sealed classes.

Uploaded by

Anil Kaushik
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

OOPs With Java

Unit: - 3
Java New Features

 Abstract Methods
An abstract method in Java is a method declared without a
body (i.e., no implementation). It only defines the method
signature and must be implemented by subclasses.
The class containing the abstract method must be abstract.
Abstract methods act like placeholders for methods that must
be implemented in the child classes.

Syntax
abstract class Animal {
abstract void makeSound(); // abstract method
}

 Interfaces in Java

An interface in Java is a reference type, similar to a class,


that can contain:
 Abstract methods (methods without a body),
 Default methods (with implementation),
 Static methods, and
 Constants (public static final variables).
Interfaces are used to define a contract that classes must
follow, without dictating how the methods are
implemented.

Key Features of Interfaces


 Cannot be instantiated directly.
 All fields are public, static, and final by default.
 All abstract methods are public and abstract by default.
 A class can implement multiple interfaces, enabling
multiple inheritance (not possible with classes).

Syntax
interface Vehicle {
void start(); // abstract method
}

 Functional Interfaces
A functional interface in Java is an interface that contains
exactly one abstract method.
These interfaces are used primarily in lambda
expressions and method references, enabling more
concise and readable code, especially for functional-
style programming introduced in Java 8.

Key Characteristics
 Has exactly one abstract method.
 Can have default and static methods.
 Annotated with @FunctionalInterface (optional but
recommended).
 Used with lambda expressions, method references, and
streams API.

Example
@FunctionalInterface
interface MyFunction {
void execute();
}

Functional Interfaces in Java Related to Lambda


Expressions

Functional interfaces and lambda expressions in Java are


closely related—in fact, lambda expressions are only
allowed in contexts where a functional interface is
expected.

Example Without Lambda:


@FunctionalInterface
interface Greeting {
void sayHello();
}

class Hello implements Greeting {


public void sayHello() {
System.out.println("Hello!");
}
}

Example With Lambda:

Greeting greet = () -> System.out.println("Hello!");


greet.sayHello(); // Output: Hello!

 Method References in Java

Method references in Java are a shorthand alternative to


lambda expressions.
They allow you to refer to a method directly by its name,
when that method already matches the signature of a
functional interface method.

Syntax

ClassName::methodName

Types of Method References

1. Reference to a Static Method

@FunctionalInterface
interface Calculator {
int compute(int a, int b);
}

class MathOperations {
static int add(int x, int y) {
return x + y;
}
}

public class Test {


public static void main(String[] args) {
Calculator calc = MathOperations::add; // method
reference
System.out.println(calc.compute(5, 3)); //
Output: 8
}
}

2. Reference to an Instance Method of a Particular


Object

class Printer {
void print(String msg) {
System.out.println(msg);
}
}

public class Test {


public static void main(String[] args) {
Printer printer = new Printer();
Consumer<String> printRef = printer::print; //
instance method reference
printRef.accept("Hello"); // Output: Hello
}
}

3. Reference to an Instance Method

List<String> names = Arrays.asList("Alice", "Bob",


"Charlie");

// Equivalent lambda: s -> s.toUpperCase()


names.stream().map(String::toUpperCase).forEach(Sy
stem.out::println);

4. Reference to a Constructor

@FunctionalInterface
interface PersonFactory {
Person create(String name);
}

class Person {
String name;
Person(String name) {
this.name = name;
}
}

public class Test {


public static void main(String[] args) {
PersonFactory factory = Person::new; //
constructor reference
Person p = factory.create("John");
System.out.println(p.name); // Output: John
}
}

 Stream API

The Stream API in Java (introduced in Java 8) is used to


process collections of data in a functional and
declarative way—that means you can perform
operations like filtering, mapping, and reducing without
writing boilerplate code like loops.

What is a Stream?
A Stream is a sequence of elements that supports
various operations to process data:
 It does not store data itself.
 It is not a data structure (like List or Set).
 It works with Collections, arrays, or I/O channels.

 Default and Static Methods

Java 8 introduced default and static methods in


interfaces, which allowed interfaces to have concrete
(non-abstract) methods for the first time.
1. Default Methods
A default method is a method in an interface that
has a default implementation. It allows you to add
new methods to interfaces without breaking
existing implementations.

Syntax

interface Vehicle {
default void start() {
System.out.println("Vehicle is starting");
}
}

Why Use Default Methods?


 To extend interfaces without affecting classes that
implement them.
 To provide a common implementation shared across
multiple classes.

2. Static Methods in Interfaces

A static method in an interface belongs to the


interface itself, not to the implementing classes.
It can only be called using the interface name.
Syntax

interface Vehicle {
static void fuelType() {
System.out.println("Petrol or Diesel");
}
}

 Base64
Base64 is used to encode binary data (like images or files)
into a text string made up of ASCII characters. It's especially
useful when transmitting data over media that are designed
to deal with text (like JSON, XML, or HTML).

import java.util.Base64;

public class Base64Example {


public static void main(String[] args) {
String original = "Hello, World!";

// Encode
String encoded =
Base64.getEncoder().encodeToString(original.getBytes())
;
System.out.println("Encoded: " + encoded);

// Decode
byte[] decodedBytes =
Base64.getDecoder().decode(encoded);
String decoded = new String(decodedBytes);
System.out.println("Decoded: " + decoded);
}
}

 For each Method

In java, the forEach method is a terminal operation


provided by stream API.
It allows you to perform a specified action for each
element in a stream, iterating over the elements
sequentially.
The forEach method accepts a functional interface as an
argument, which defines the action to be performed on
each element of the stream.

 try-with-resources statement in java

The try-with-resources statement is a feature introduced


in Java 7 to simplify the management of resources like
files, sockets, streams, etc., that need to be closed after
use.

Features of Try-With-Resources
Feature Description
Automatic closing No need for finally to close
resources.
Supports multiple Declare multiple resources
resources. in try().
Cleaner Syntax Less boilerplate code
Exception Suppression. Handles exceptions
through during both try
and close.

 Type Annotations

Type annotations are annotations that can be applied


directly to types — not just declarations like classes,
methods, or fields.

Before Java 8, annotations could only be used on


declarations like:
 Classes
 Methods
 Fields
 Parameters

But now, you can annotate any use of a type, for


example:
 Inside generics
 In type casts
 On new expressions
 In throws clauses
 In method references

 Repeating Annotations
Repeating annotations in Java, introduced in Java 8 through
JSR 308, allow developers to apply the same annotation more
than once to a single program element such as a class,
method, or field.

This is done by marking the annotation with @Repeatable


and creating a corresponding container annotation that holds
an array of the repeated annotation.

This feature eliminates the need for grouping annotations


manually in a container, improving code readability and
reducing boilerplate.

It is especially useful in scenarios like defining multiple roles,


permissions, constraints, or event handlers where repeating
the same annotation type with different values is necessary.

Reflection APIs can retrieve these annotations easily using


getAnnotationsByType(), making it powerful and efficient for
metadata handling in large applications.
 Java Module System

The java module system provides a way to modularize java


applications by encapsulating code into discrete units called
modules.

This allows developers to organize codebase into logical units


with well-designed dependencies and boundaries.

The java module system offers significant advantages for


developing and maintaining large scale java applications.

Advantages
1. Modularization
2. Encapsulation
3. Improved Performance
4. Isolation and Security
5. Scalability

 Diamond Syntax

Diamond syntax in Java, introduced in Java 7, simplifies


the use of generics by allowing the compiler to infer
type parameters automatically.
Before this feature, programmers had to explicitly
specify the generic types on both sides of the
assignment, which was verbose and repetitive.

With diamond syntax, you write the generic type only


once on the left side, and the compiler fills in the rest,
making the code cleaner and easier to read.

This reduces boilerplate and potential errors in


specifying types.
Diamond syntax works with most generic classes like
collections (e.g., ArrayList, HashMap), enhancing code
maintainability and clarity.

 Inner Anonymous classes in java

Inner anonymous classes in Java are special types of


inner classes without a name, declared and instantiated
in a single expression.

They are often used to provide quick implementations of


interfaces or abstract classes, especially for event
handling, callbacks, or threading, without creating
separate named classes.

Because they are defined inside methods or expressions,


they can access final or effectively final variables from
the enclosing scope.
Anonymous inner classes simplify code by enabling
inline behaviour definitions. For example, when creating
a thread, you can override the run() method using an
anonymous inner class, allowing concise and readable
code.

Example: -

Without use of anonymous class

interface Person{
void show();
}

class Student implements Person


{
public void show()
{
System.out.println(“show”);
}
}

public class AnonymousEx {


public static void main(String args[])
{
Person p=new Students();
p.show();
}
With use of anonymous class

interface Person{
void show();
}
public class AnonymousEx {
public static void main(String args[])
{
Person p = Person(){
Public void show(){
System.out.println(“show”);
}
};

 Local Variable Type Inference

Local Variable Type Inference is a feature in


programming languages (like Java, introduced in Java 10)
that allows the compiler to automatically infer the data
type of a local variable based on the value it is initialized
with.
Instead of explicitly declaring the type, you use a
keyword like var:

Example in Java:

// Before Java 10
String message = "Hello, World!";
int count = 10;
// With local variable type inference (Java 10+)
var message = "Hello, World!";
var count = 10;

Benefits for Code Readability

1. Focuses on logic, not syntax:


o Helps the reader concentrate on what the code is

doing rather than the types.

2. Improves maintainability:
o If you change the right-hand side type, you don’t

need to update the left-hand declaration.

3. Enhances readability in complex generic types:


o Especially helpful when working with deeply nested

generics or lambda expressions.

 Switch Statement in Java

A switch statement in Java is a control flow statement


that allows a variable to be tested for equality against a
list of values, called cases.
It's often used as an alternative to a series of if-else
statements.
Syntax (Traditional Switch Statement):

int day = 3;
switch (day) {
case 1:
System.out.println("Monday");
break;
case 2:
System.out.println("Tuesday");
break;
case 3:
System.out.println("Wednesday");
break;
default:
System.out.println("Invalid day");
}

Key Points:
 break prevents fall-through to the next case.
 default is optional and executed when no case matches.
 Works with int, char, enum, String (since Java 7), etc.

 Switch Expression
A switch expression enhances the traditional switch
statement by:
 Allowing it to return a value.
 Using arrow (->) syntax to avoid fall-through.
 Being more concise and readable.

Syntax:
int day = 3;
String dayName = switch (day) {
case 1 -> "Monday";
case 2 -> "Tuesday";
case 3 -> "Wednesday";
default -> "Invalid day";
};
System.out.println(dayName);
Features:
 No need for break.
 Returns a value (assignable to a variable).
 Allows block bodies with yield:

 yield Keyword in Java

The **yield** keyword was introduced in Java 13 (as a


preview) and became a standard part of switch
expressions in Java 14.
It is used inside a switch expression to return a value
from a case block when using block syntax (i.e., {}).
Why is yield needed?
In switch expressions, when you use a code block {}
inside a case, you can’t just use return or an expression;
instead, you use yield to specify the value to return from
that block.

Example:
int day = 2;
String dayType = switch (day) {
case 1, 7 -> "Weekend";
case 2, 3, 4, 5, 6 -> {
System.out.println("Weekday logic here");
yield "Weekday";
}
default -> "Invalid day";
};
System.out.println(dayType);

 Text Blocks in Java

A Text Block is a feature introduced in Java 13 (preview)


and standardized in Java 15 that allows you to create
multi-line string literals more easily and readably using
triple double-quotes """.

Syntax of Text Block

String html = """


<html>
<body>
<h1>Hello, World!</h1>
</body>
</html>
""";

Benefits of Text Blocks for String Manipulation

 Improved Readability
 Less Escaping
 Automatic Formatting
 Easier Maintenance

 Records in Java

Records are a special type of class introduced in Java 14


(preview) and standardized in Java 16 that make it easier
to create immutable data objects.
They are designed to model data carriers—objects
whose main purpose is to hold data, like DTOs (Data
Transfer Objects).

Syntax of a Record

public record Person(String name, int age) {}

This single line automatically generates:


 A final class
 Private final fields: name and age
 A constructor
 Getters: name() and age()
 equals(), hashCode(), and toString() methods

How Records Simplify Immutable Data Creation

1. Concise Syntax
Records provide a concise syntax for declaring classes
that the primarily used to hold data.

2. Implicit Finality
By default all components of a record are implicitly final.
This ensures that instances if the record are immutable.

3. Compact Initialization
Records generate a compact constructor to initialize the
record’s components. This allows you to create instances
of the record using a concise syntax.

 Sealed Classes in Java

Sealed classes (introduced in Java 15 as a preview and


finalized in Java 17) are a powerful feature that lets you
control which classes can extend or implement a given
class or interface.
Purpose of Sealed Classes

Sealed classes provide fine-grained control over


inheritance, improving:
 Security: Prevents unexpected or unauthorized
subclasses.
 Maintainability: Helps document and enforce an
intended class hierarchy.
 Exhaustiveness: Improves compiler checks, especially
with switch expressions over class types.

Syntax of a Sealed Class

public sealed class Vehicle permits Car, Truck {


// common vehicle code
}

Role in Controlling Inheritance Hierarchies

Benefit Explanation
Explicit control Only the classes you list in
permits can extend your
sealed class.
Improved reasoning When you use sealed
classes in pattern
matching or switch
expressions, the compiler
can check for
exhaustiveness —
meaning you handled all
permitted types.
Better encapsulation Limits the number of
subclasses, helping keep
the code predictable and
maintainable.
Useful with pattern Works well with instanceof
matching and future enhancements
in pattern matching for
deconstructing types.

You might also like