Sunday, 26 July 2026

Unknown fields should be preserved, not destroyed - encoding json,avro,protobuff etc

 Excellent question. This is one of the most frequently asked Architect interview questions from DDIA.

The statement:

"Unknown fields should be preserved, not destroyed."

is true for Protocol Buffers (modern implementations) but not generally true for Avro. This is a key difference that interviewers often test.


First understand the problem

Suppose we have three services:

Order Service (V2)
        |
        |  orderId, amount, couponCode
        |
        V
Kafka
        |
        V
Inventory Service (V1)

V2 sends

{
  "orderId":101,
  "amount":1000,
  "couponCode":"NEW100"
}

Inventory Service V1 knows only

orderId
amount

It doesn't know couponCode.


What happens in Avro?

Assume the schemas are:

Producer Schema (V2)

{
  "type":"record",
  "name":"Order",
  "fields":[
    {"name":"orderId","type":"int"},
    {"name":"amount","type":"double"},
    {"name":"couponCode","type":["null","string"],"default":null}
  ]
}

Consumer Schema (V1)

{
  "type":"record",
  "name":"Order",
  "fields":[
    {"name":"orderId","type":"int"},
    {"name":"amount","type":"double"}
  ]
}

During deserialization,

Avro matches fields by name.

It reads

orderId ✔

amount ✔

couponCode ❌ Unknown

Unknown field is simply ignored.

The consumer object becomes

Order

orderId = 101

amount = 1000

couponCode never exists inside the Java object.


If Inventory republishes the message

Suppose

Producer

↓

Kafka

↓

Inventory

↓

Kafka Again

Inventory reads

orderId

amount

and writes again.

The new message becomes

{
  "orderId":101,
  "amount":1000
}

The field

couponCode

is lost.

This is because Avro does not automatically preserve unknown fields during normal deserialize → serialize cycles.


Why?

Avro is schema resolution based.

It creates an object using only fields present in the reader schema.

Unknown fields are discarded during deserialization.

So they cannot be written back later unless the application explicitly carries them along.


Protocol Buffers behave differently

Protocol Buffers internally stores unknown fields.

Imagine

Producer

↓

Protobuf Binary

↓

Consumer

Consumer understands

orderId

amount

Unknown

couponCode

is kept inside an internal UnknownFieldSet.

The object looks conceptually like:

Order

orderId

amount

UnknownFieldSet

     |

couponCode

If the consumer forwards the message,

serialize()

includes

couponCode

again.

Nothing is lost.


Visual Comparison

Avro

Producer V2

↓

orderId
amount
couponCode

↓

Consumer V1

↓

Reads

orderId

amount

↓

couponCode discarded ❌

↓

Writes again

↓

orderId

amount

Protocol Buffers

Producer V2

↓

orderId

amount

couponCode

↓

Consumer V1

↓

Reads

orderId

amount

↓

UnknownFieldSet

↓

couponCode preserved

↓

Serialize again

↓

orderId

amount

couponCode

How does Avro achieve compatibility then?

Avro's strength is schema evolution, not unknown field preservation.

It achieves compatibility using writer schema + reader schema resolution:

  1. The writer's schema (or its ID via a Schema Registry) is available.

  2. The reader uses its own schema.

  3. Avro resolves differences:

    • Matching fields are read.

    • New writer fields missing from the reader are ignored.

    • Reader fields missing from the writer use default values (if defined).

  4. The application works without errors, but unknown fields are not retained after deserialization.


Real-world Kafka Example

Order Service V2

↓

Kafka

↓

Payment Service V1

↓

Notification Service V2

If Payment Service only validates payment and republishes the event:

  • With Avro: If it deserializes into a V1 object and reserializes, couponCode is lost unless the application preserves it explicitly.

  • With Protocol Buffers: The unknown field is retained automatically and forwarded.


Architect Interview Answer ⭐

Question: How does Avro preserve unknown fields?

Answer:

Avro generally does not preserve unknown fields during a deserialize–serialize cycle. It resolves schema differences using the writer and reader schemas, ignoring fields that the reader doesn't know. This enables schema compatibility, but unknown fields are discarded unless the application explicitly carries them forward. In contrast, Protocol Buffers stores unknown fields internally (using an UnknownFieldSet in many implementations) so they can be reserialized without loss.

This distinction between schema compatibility (Avro) and unknown field preservation (Protocol Buffers) is an important concept for distributed systems and frequently comes up in Senior Java Architect interviews.

SOLID principles with Design Patterns

 

SOLID + Design Patterns (Java Examples)

One of the most common Java interview questions is:

Which Design Patterns follow which SOLID Principle?

The answer is that design patterns are practical implementations of SOLID principles.


SOLID vs Design Patterns

SOLID PrincipleDesign PatternsWhy?
SRPFacade, DAO, Repository, Service LayerOne class = One responsibility
OCPStrategy, Decorator, Template MethodAdd new behavior without changing existing code
LSPFactory Method, Template MethodChild classes can replace parent classes
ISPAdapter, BridgeSmall focused interfaces
DIPFactory, Abstract Factory, Dependency Injection, BuilderDepend on interfaces, not implementations

1. SRP + DAO Pattern

❌ Bad Design

class Employee {

    void calculateSalary(){}

    void saveEmployee(){}

    void sendEmail(){}
}

Three responsibilities.


✅ Good Design

class EmployeeService {

    void calculateSalary(){}
}
class EmployeeRepository {

    void save(Employee e){}
}
class EmailService {

    void sendMail(){}
}

Pattern Used

Controller
      |
      V
Service
      |
      V
Repository (DAO)

Every class has one responsibility.


2. OCP + Strategy Pattern

Suppose Flipkart offers different payment methods.

Instead of:

if(payment.equals("UPI"))

if(payment.equals("CARD"))

if(payment.equals("NETBANKING"))

Use Strategy.


Strategy Interface

interface PaymentStrategy {

    void pay(double amount);

}

UPI Strategy

class UpiPayment implements PaymentStrategy {

    public void pay(double amount){

        System.out.println("UPI Payment");

    }

}

Card Strategy

class CardPayment implements PaymentStrategy {

    public void pay(double amount){

        System.out.println("Card Payment");

    }

}

Client

class PaymentService {

    private PaymentStrategy payment;

    PaymentService(PaymentStrategy payment){

        this.payment = payment;

    }

    void checkout(){

        payment.pay(1000);

    }

}

Adding Wallet Payment?

Just create

class WalletPayment implements PaymentStrategy{}

No existing code changes.

OCP achieved.


3. OCP + Decorator Pattern

Imagine Coffee Shop.

Base Coffee

interface Coffee {

    String getDescription();

}

Simple Coffee

class SimpleCoffee implements Coffee {

    public String getDescription(){

        return "Coffee";

    }

}

Decorator

class MilkDecorator implements Coffee{

    private Coffee coffee;

    MilkDecorator(Coffee coffee){

        this.coffee=coffee;

    }

    public String getDescription(){

        return coffee.getDescription()+" + Milk";

    }

}

Usage

Coffee coffee = new MilkDecorator(
                    new SimpleCoffee());

System.out.println(coffee.getDescription());

Output

Coffee + Milk

Want Sugar?

Create

SugarDecorator

No modification.

Only extension.


4. LSP + Factory Method

Vehicle example

abstract class Vehicle{

    abstract void start();

}
class Car extends Vehicle{

    void start(){

        System.out.println("Car Started");

    }

}
class Bike extends Vehicle{

    void start(){

        System.out.println("Bike Started");

    }

}

Client

Vehicle vehicle = VehicleFactory.create("CAR");

vehicle.start();

Client never worries whether it is Car or Bike.

Any subclass works.

LSP satisfied.


5. ISP + Adapter Pattern

Suppose Printer

Bad Interface

interface Printer{

    print();

    scan();

    fax();

}

Old Printer

Needs only print.

Forced to implement scan().

Violation.


Split Interfaces

interface Printable{

    void print();

}
interface Scannable{

    void scan();

}

Adapter

class OldPrinterAdapter implements Printable{

    OldPrinter printer;

    public void print(){

        printer.print();

    }

}

Only required methods implemented.


6. DIP + Factory Pattern

Bad

class NotificationService{

    EmailSender sender=new EmailSender();

}

Tightly coupled.


Better

interface MessageSender{

    void send();

}
class EmailSender implements MessageSender{}
class SmsSender implements MessageSender{}

Factory

class SenderFactory{

    static MessageSender getSender(String type){

        if(type.equals("EMAIL"))
            return new EmailSender();

        return new SmsSender();

    }

}

Client

MessageSender sender =
        SenderFactory.getSender("EMAIL");

sender.send();

NotificationService depends only on

MessageSender

DIP achieved.


7. DIP + Spring Dependency Injection ⭐

Without Spring

class OrderService{

    MySqlRepository repo =
            new MySqlRepository();

}

Coupled.


With Spring

interface OrderRepository{

    void save();

}
@Repository
class MySqlRepository
implements OrderRepository{

}
@Service
class OrderService{

    private final OrderRepository repo;

    OrderService(OrderRepository repo){

        this.repo=repo;

    }

}

Spring injects implementation automatically.

This is Dependency Inversion in action.


8. SRP + Builder Pattern

Instead of

Employee e = new Employee(
    "Ramesh",
    30,
    "Architect",
    "Bangalore",
    true,
    150000,
    "Java");

Use Builder

Employee employee = Employee.builder()
        .name("Ramesh")
        .age(30)
        .city("Bangalore")
        .designation("Architect")
        .salary(150000)
        .build();

Builder focuses only on object creation.

Employee focuses only on business data.

SRP improved.


SOLID + Spring Boot Mapping

Spring Boot FeatureSOLID PrinciplePattern
@ServiceSRPService Layer
@RepositorySRPRepository
Dependency InjectionDIPIoC
@Autowired ConstructorDIPDependency Injection
Strategy Bean SelectionOCPStrategy
JpaRepositoryISPRepository Interface
Bean PolymorphismLSPFactory
RestTemplateBuilderSRPBuilder
ResponseEntityOCPBuilder

Complete Mapping

Design PatternSOLID Principle
StrategyOCP
DecoratorOCP
Factory MethodDIP + LSP
Abstract FactoryDIP
BuilderSRP
AdapterISP
BridgeISP + DIP
ObserverOCP
CommandOCP + DIP
Template MethodOCP + LSP
ProxyOCP
FacadeSRP
RepositorySRP
Singleton(Not directly tied to SOLID; often overused and can violate SRP/DIP if misapplied)

Interview Cheat Sheet

Interview QuestionBest Answer
Which pattern best demonstrates OCP?Strategy and Decorator
Which pattern demonstrates DIP?Factory, Abstract Factory, Dependency Injection
Which pattern uses LSP?Factory Method, Template Method
Which pattern follows ISP?Adapter, Bridge
Which pattern improves SRP?Repository, Facade, Builder, Service Layer

Tip for Senior Java Architect Interviews

Rather than memorizing mappings, explain the reasoning:

  • Strategy supports OCP because you add new algorithms without modifying existing client code.

  • Decorator supports OCP by extending behavior dynamically instead of changing the original class.

  • Factory and Dependency Injection support DIP by ensuring clients depend on interfaces rather than concrete implementations.

  • Repository and Service Layer encourage SRP by separating persistence, business logic, and presentation concerns.

  • Adapter supports ISP by exposing only the operations a client actually needs.

  • Template Method supports LSP because subclasses provide specialized behavior while preserving the base class contract.

This explanation demonstrates a deeper understanding than simply listing patterns against SOLID principles, which is often what interviewers for Senior Architect roles look for.

Saturday, 20 June 2026

Blocking IO vs Non-Blocking IO Concepts

1. CPU Internal Model & Thread Context Switching

How CPU Executes Instructions

A CPU continuously performs:

+---------+    +---------+    +---------+
| Fetch   | -> | Decode  | -> | Execute |
+---------+    +---------+    +---------+

Fetch

CPU fetches instructions from memory/cache.

Decode

CPU understands what operation must be performed.

Execute

CPU executes the instruction.


What is a Thread Context Switch?

Assume CPU is executing Thread-A.

CPU
 |
 +--> Thread-A Running

Suddenly a higher-priority thread arrives.

CPU
 |
 +--> Save Thread-A State
 |
 +--> Load Thread-B State
 |
 +--> Execute Thread-B

The CPU must save:

  • Program Counter (PC)

  • Registers

  • Stack Pointer

  • Thread State

Then load another thread's state.

Cost of Context Switching

Context Switch

Save Current Thread
        +
Load New Thread
        +
CPU Cache Disturbance
        +
Scheduler Overhead

Result:

More Threads
      ↓
More Context Switches
      ↓
CPU Wastage
      ↓
Lower Throughput

This is why high-performance systems try to minimize unnecessary threads.


2. Why Redis Uses Single Thread

Redis is famous for using a mostly single-threaded event loop.

Traditional Multi-thread Model

Request-1 --> Thread-1
Request-2 --> Thread-2
Request-3 --> Thread-3
Request-4 --> Thread-4

Problem:

Many Threads
      ↓
Many Context Switches
      ↓
CPU Overhead

Redis Model

Request-1
Request-2
Request-3
Request-4
      |
      v
+----------------+
| Single Event   |
| Loop Thread    |
+----------------+

Benefits:

  • No thread synchronization

  • Minimal context switching

  • Predictable latency

  • Better CPU cache utilization


CPU Cache Locality

Linked List

Node-A --> Node-B --> Node-C --> Node-D

Memory:

A ----- far ----- B ----- far ----- C

CPU keeps jumping in RAM.


Array-Based Structure

[A][B][C][D][E]

Memory is contiguous.

CPU Fetch
     ↓
Cache Line Loaded
     ↓
Multiple Elements Available

Advantages:

  • Better cache hit rate

  • Less RAM access

  • Faster execution

This principle is used heavily in Redis internals. (rameshvanka.blogspot.com)


3. Blocking I/O Architecture

What is Blocking I/O?

A thread waits until data becomes available.

Flow

Client
   |
   v
Socket Created
   |
   v
Dedicated Thread Assigned
   |
   v
Waiting For Data
   |
   v
Thread Blocked
   |
   v
Data Arrives
   |
   v
Process Request
   |
   v
Response

Example

Suppose 10,000 clients connect.

10,000 Clients
      ↓
10,000 Sockets
      ↓
10,000 Threads

Most threads are doing:

Waiting...
Waiting...
Waiting...
Waiting...

CPU is not busy.

Memory is wasted.


Blocking I/O Diagram

Client-1 ---> Thread-1 ---> Waiting
Client-2 ---> Thread-2 ---> Waiting
Client-3 ---> Thread-3 ---> Waiting
Client-4 ---> Thread-4 ---> Waiting

Problems:

  • High memory usage

  • Context switching overhead

  • Limited scalability

Traditional Tomcat thread-per-request model largely follows this pattern. (rameshvanka.blogspot.com)


4. Non-Blocking I/O Architecture

Core Idea

Don't dedicate a thread per socket.

Instead:

One Thread
      ↓
Monitor Many Sockets
      ↓
Process Only Ready Sockets

Event Loop Model

            +----------------+
Socket-1 -->|                |
Socket-2 -->| Event Loop     |
Socket-3 -->| (Poller)       |
Socket-4 -->|                |
            +----------------+
                     |
                     v
          Ready Socket Found
                     |
                     v
             Worker Executes

Detailed Flow

Client Request
       |
       v
Socket Registered
       |
       v
Selector/Poller
       |
       v
Data Available?
   |
   +-- No --> Continue Monitoring
   |
   +-- Yes
          |
          v
    Worker Thread
          |
          v
    Business Logic
          |
          v
      Response

5. Selector Pattern (Java NIO)

Java NIO introduced:

Selector
Channel
Buffer

Architecture:

SocketChannel-1
SocketChannel-2
SocketChannel-3
SocketChannel-4
       |
       v
    Selector
       |
       v
Ready Events
       |
       v
Worker Pool

One selector can monitor thousands of connections.


6. Blocking vs Non-Blocking Comparison

FeatureBlocking IONon-Blocking IO
Thread per socketYesNo
Memory usageHighLow
Context switchingHighLow
ScalabilityLimitedVery High
Idle thread wastageHighVery Low
Suitable forSmall systemsLarge-scale systems
ExampleTraditional Servlet/TomcatNetty, Node.js, Vert.x

7. Where Non-Blocking IO Fails

Your note is correct but can be explained better.

Non-blocking IO is excellent for:

IO Bound Work

Examples:

  • Database calls

  • Network calls

  • API calls

  • Messaging


Problem: CPU Intensive Tasks

Image Processing
Video Encoding
AI Inference
Complex Calculations
Encryption

If a single event-loop thread does this:

Event Loop
     |
     +--> Heavy CPU Task

Then:

Event Loop Blocked
      ↓
Cannot Accept New Requests
      ↓
Performance Collapse

Correct Modern Architecture

            Event Loop
                 |
                 v
          Ready Request
                 |
                 v
        Worker Thread Pool
                 |
                 v
         CPU Intensive Work
                 |
                 v
             Response

This is exactly what frameworks like Netty, Spring WebFlux, Vert.x, and Node.js ecosystems follow.


Interview Summary (One-Line Version)

Blocking IO:
One Socket -> One Thread -> Wait For Data

Non-Blocking IO:
Many Sockets -> One Event Loop -> Process Only Ready Events
Blocking IO optimizes programming simplicity.

Non-Blocking IO optimizes scalability and resource utilization.

This version would be more accurate for senior Java Architect/System Design interviews and aligns with modern Java NIO, Netty, Spring WebFlux, and Redis architecture concepts.

In multi thread env, thread context switch will be take more time for the cpu.

   

Reference:





Instead of multi thread, single thread is best for we wil save time and fast due to saving time of thread context switch

Redis

Redis using internally arraylist, datastructure which will store content side by side, instead of linkedlist, due to this cpu will fetch set of instructions fetch phase, store them those instructions instruction cache, due to this CPU will save cycle times.due to cpu will not goes to RAM instead it will fetch instructiosn from instruction cache only.
------------


Above diagram clearly explain the when request comes, one socket will be created, then for that corresponding socket tomcat will create the thread, thread will wait until the socket will have data, thread is blocked until the socket fulled, due to this - threads wasting the user space due to blocking nature.



In the Single Thread Model with Non-block IO with event loop, it will reads the sockets full, it will handle multple requests, where as tomcat instance can't handle multiple requests.


Note: Single Thread IO - if CPU intension task this single thread model will fail.

Wednesday, 18 February 2026

Cache Layers

In this topic talking about 

Requet Level Cache - HashMap

Application Level Cache - Caffeine Cache

Cluster Level Cache - Redis


DoorDash standardized caching across its microservices to address fragmentation and performance issues. Their new multi-layered system boosts scalability while simplifying adoption for engineering teams.

Problems Faced

Teams used varied tools like Caffeine, Redis Lettuce, and HashMaps, leading to repeated issues such as cache staleness, Redis overload, and inconsistent key schemas. This fragmented approach complicated observability and debugging, especially under high traffic in services like DashPass.

Core Solution

Engineers created a shared Kotlin-based library with two key interfaces: CacheManager for cache creation and fallbacks, and CacheKey for abstracting keys. This enables uniform API calls via dependency injection and polymorphism, hiding backend details from business logic.

Cache Layers

  • Request Local Cache: HashMap-bound to a single request's lifecycle for ultra-fast access.

  • Local Cache: Caffeine-powered, shared across workers in one JVM.

  • Redis Cache: Distributed via Lettuce, accessible across pods in a Redis cluster.

Data flows from fastest (local) to slowest (Redis), populating upper layers on misses.

Key Features

Runtime controls let operators toggle layers, adjust TTLs, or enable shadow mode (sampling cache vs. source-of-truth for validation). Built-in metrics track hits/misses, latency, and staleness, with logging for observability



Client Request

       |

       v

+--------------------+

| 1. Request Local   |  (HashMap, request-lifetime)

|    Cache (Fastest) |

+--------------------+

       | Miss?

       v Yes

+--------------------+

| 2. Local Cache     |  (Caffeine, JVM-wide)

+--------------------+

       | Miss?

       v Yes

+--------------------+

| 3. Redis Cache     |  (Lettuce, Cluster-wide)

+--------------------+

       | Miss?

       v Yes

+--------------------+

| Source of Truth    |  (DB/Service)

+--------------------+

       ^

       | Populate all layers on hit


Sunday, 15 February 2026

Resilience4J - SlidingWindow Protocal with CircuitBreaker

 In previous articel discussed about the BulkHead Pattern, Now we are discussing on Sliding Window.

Good πŸ‘ this is core internal logic of CircuitBreaker in Resilience4j.

Most developers use @CircuitBreaker but don’t understand how sliding window actually calculates failure rate.

Let’s break it clearly.



πŸ”₯ What is Sliding Window in Resilience4j?

Sliding window is the statistical window used by CircuitBreaker to decide:

Should we OPEN the circuit or keep it CLOSED?

It calculates:

  • Failure rate %

  • Slow call rate %

  • Total calls count

Based on last N calls or last N seconds.


πŸ“Œ Two Types of Sliding Windows

1️⃣ COUNT_BASED Sliding Window

Based on number of calls.

Example:

CircuitBreakerConfig config = CircuitBreakerConfig.custom()
.slidingWindowType(SlidingWindowType.COUNT_BASED)
.slidingWindowSize(10)
.failureRateThreshold(50)
.build();

Meaning:

  • Observe last 10 calls

  • If more than 50% fail

  • Circuit goes OPEN


Example Scenario:

Last 10 calls:

S F S F F S F F S F

Failures = 6
Failure rate = 60%

If threshold = 50% → Circuit OPEN


2️⃣ TIME_BASED Sliding Window

Based on time duration.

Example:

.slidingWindowType(SlidingWindowType.TIME_BASED)
.slidingWindowSize(10)

Meaning:

  • Observe calls in last 10 seconds

  • Calculate failure rate

  • If threshold crossed → OPEN


🧠 How Sliding Window Internally Works

Internally it maintains:

  • Circular array (ring buffer)

  • Buckets for time-based

  • Atomic counters

Every new call:

  1. Old data expires

  2. New result added

  3. Failure rate recalculated

  4. Decision made

This is O(1) time complexity per update.

Very efficient.


🎯 Important Configurations (Architect Level)

πŸ”Ή Minimum Number of Calls

.minimumNumberOfCalls(5)

Circuit will not evaluate failure rate unless at least 5 calls happen.

This avoids false positives in low traffic systems.


πŸ”Ή Failure Rate Threshold

.failureRateThreshold(50)

If failure % > threshold → OPEN


πŸ”Ή Slow Call Rate Threshold

.slowCallRateThreshold(60)
.slowCallDurationThreshold(Duration.ofSeconds(2))

If 60% calls take > 2 seconds → OPEN

This protects against latency spikes.


🏦 Real Banking Example (APS Context)

Let’s say:

Loan SOR:

  • Sliding window size = 20 calls

  • Failure threshold = 40%

  • Minimum calls = 10

If last 20 calls:

  • 8 failures

  • Failure rate = 40%

Circuit remains CLOSED.

But if 9 failures:

  • 45%

  • Circuit OPEN


πŸ”„ Difference Between Count vs Time Based

FeatureCOUNT_BASEDTIME_BASED
Best ForStable trafficVariable traffic
Banking Core APIs✅ Good⚠️ Depends
High burst systems❌ Risky✅ Better
PredictabilityHighMedium

Saturday, 14 February 2026

Bulkhead Pattern – Every SOR Should Have a Separate Thread Pool/Executor Service

Resilence4J Patterns - These patterns will focus only on threads.

Bulkhead Pattern – Every SOR Should Have a Separate Thread Pool/Executor Service

In enterprise banking systems, a single application often communicates with multiple Systems of Record (SORs) — such as Customer SOR, Loan SOR, Payment SOR, or Core Banking.

If one SOR becomes slow or unavailable, it should not impact other SOR integrations.

This is where the Bulkhead Pattern becomes critical.




Ex:

APS Service

   ├── Customer SOR

   ├── Loan SOR

   ├── Payment SOR

   └── Notification SOR

All SOR calls share the same thread pool.

❌ What happens if Loan SOR becomes slow?

  • Threads get blocked

  • Thread pool gets exhausted

  • Customer SOR calls start waiting

  • Entire APS system becomes unresponsive

  • Production incident

This is called resource starvation.


✅ Solution: Separate Thread Pool Per SOR

Each SOR should have:

  • Dedicated thread pool

  • Dedicated timeout

  • Dedicated circuit breaker

  • Dedicated monitoring metrics

Architecture becomes:

Customer SOR → ThreadPool-A
Loan SOR → ThreadPool-B
Payment SOR → ThreadPool-C
Notification → ThreadPool-D

Now:

  • Loan SOR failure affects only ThreadPool-B

  • Other SORs continue working normally

  • System stability increases dramatically



Wednesday, 12 October 2022

JAVA 8 - Lambads,Streams - Very Simple Manner

Lambda - Nameless methods we are calling as lambda,

We heard anonymous class as nameless class, What is nameless function ?

Lambda are advanced short cut version of anonymous class.

Usecase: Convertion of Method as Nameless Method (Lambda)

public void fan() {
      System.out.println("Ramesh is megastar fan");
}

As I told lambda means nameless function/method, Now I am going to remove the method name "public void fan"

()  -> {
             System.out.println("Ramesh is megastar fan");
         }

For the single statement we don't require curly brackets {,} and then

() -> System.out.println("Ramesh is megastar fan");


2nd Ex: methods with arguments .

public void add(int a,int b) {
        System.out.println(a+b);
}

As I told lambda means nameless function/method, Now I am going to remove the method name "public void add"

(int a,int b) -> {
                          System.out.println(a+b);
                      }

For the single statement we don't require curly brackets {,} and then

(int a,int b) ->  System.out.println(a+b);
                      
 If the type of the parameter can be decided by compiler automatically based on the context then we can remove types also. 

(a,b) ->  System.out.println(a+b);


3rd Ex: method with arguments and return type

public String str(String str) { 
                return str;
 }

As I told lambda means nameless function/method, Now I am going to remove the method name "public String str"

(String str) -> { return str };

 If the type of the parameter can be decided by compiler automatically based on the context then we can remove types also. 

(str) -> { str };

(str) ->  str ;


Hope you understand lambda secret, As I told lambda is advanced version of anonymous class, Now we will see the scenario.

Concept: Functional Interface.
If an interface contain only one abstract method, such type of interfaces are called functional interfaces and the method is called functional method or single abstract method (SAM). 

Ex: 
1) Runnable -> It contains only run() method 
2) Comparable ->  It contains only compareTo() method 
3) ActionListener -> It contains only actionPerformed() 
4) Callable ->  It contains only call() method 

Inside functional interface in addition to single Abstract method (SAM) we write any number of default and static methods.


Usecase: Convertion of Anonymous Class as Lambda (Anonymous method)

class Test { 
    public static void main(String[] args) { 
        Thread t = new Thread(new Runnable() {
                                                                            public void run() { 
                                                                                 for(int i=0; i<10; i++) { 
                                                                                    System.out.println("Child Thread"); 
                                                                                } 
                                                                           }  
                                              }); 
          t.start(); 
         for(int i=0; i<10; i++) 
                System.out.println("Main thread");  
        }  
}  

In the above example anonymous (Nameless class) -> 

new Runnable() {
           public void run() { 
                  for(int i=0; i<10; i++) { 
                          System.out.println("Child Thread"); 
                  } 
           }  
 }

Converting above one into Lambda (Nameless Function/Method)

For the nameless Function - we only focus on function or method, here function/method is run() method.

 public void run() { 
           for(int i=0; i<10; i++) { 
                     System.out.println("Child Thread"); 
           } 
 }

Remove the function name -> 

 ()  ->  { 
           for(int i=0; i<10; i++) { 
                     System.out.println("Child Thread"); 
           } 
 }

We successfully converted the Anonymous class into Lambda.

Few more scenarios:

interface Calculator { 
        public void sum(int a,int b); 
}

 class Demo implements Calculator { 
        public void sum(int a,int b) { 
             System.out.println("The sum:"+(a+b)); 
        } 


public class Test { 
    public static void main(String[] args) { 
       Calculator  cal = new Demo(); 
        cal .sum(20,5); 
    } 
}


Convert into anonymous class approach

public class Test { 
    public static void main(String[] args) { 
       //Calculator cal = new Demo();
 Calculator cal = new Calculator() {
            public void sum(int a,int b) { 
                                  System.out.println((a+b)); 
                            }
                 };
        cal .sum(20,5); 
    } 
}

Now Converting anonymous class into anonymous function/method (Lambda approach)

public class Test { 
    public static void main(String[] args) { 
       //Calculator cal = new Demo();
  Calculator cal = (a,b) -> { 
                                                 System.out.println(a+b); 
                                               };
        cal .sum(20,5); 
    } 
}

Hope you understand lambda alias nameless function/method concept.