Skip to main content

Command Palette

Search for a command to run...

Interface Segregation Principle (ISP) in Java

Published
β€’5 min read
Interface Segregation Principle (ISP) in Java

SOLID Design Principle

"Clients should not be forced to depend on interfaces they do not use."

The Interface Segregation Principle (ISP) is one of the five SOLID principles that helps developers design flexible, maintainable, and scalable software systems.

This principle focuses on designing small, specific interfaces instead of large, general-purpose ones.


Why Interface Segregation Principle Matters

In real-world applications, not every class needs every method.

When we create large interfaces, classes are often forced to implement methods they don't need.

This leads to:

Unnecessary code
Runtime exceptions
Hard-to-maintain systems
Poor scalability

ISP solves this by encouraging:

Smaller interfaces
Focused responsibilities
Better modular design


🚨 Problem Scenario β€” Without ISP (Bad Design)

Let's start with a common mistake.

Suppose we create a Worker interface.

interface Worker {
    void work();
    void eat();
}

Now we create a Human worker.

class HumanWorker implements Worker {

    @Override
    public void work() {
        System.out.println("Human is working");
    }

    @Override
    public void eat() {
        System.out.println("Human is eating");
    }
}

So far, everything looks fine.


πŸ€– Now Add Robot Worker

Robots don't eat.

But because of the large interface, they are forced to implement eat().

class RobotWorker implements Worker {

    @Override
    public void work() {
        System.out.println("Robot is working");
    }

    @Override
    public void eat() {
        // Robots don't eat
        throw new UnsupportedOperationException(
            "Robot does not eat"
        );
    }
}

❗ What's Wrong Here?

This design causes:

πŸ”΄ Forced Implementation

Robot must implement eat() even though it doesn't need it.

πŸ”΄ Runtime Risk

Throwing exceptions like:

UnsupportedOperationException

creates unstable systems.

πŸ”΄ Maintenance Problems

If more worker types are added, the interface becomes messy.


Solution β€” Apply Interface Segregation Principle

Instead of one large interface,
we split it into smaller, specific interfaces.


Step 1 β€” Create Small Interfaces

interface Workable {
    void work();
}

interface Eatable {
    void eat();
}

Now each interface represents one responsibility.


Step 2 β€” Implement Only What Is Needed

πŸ‘€ Human Worker

Human works and eats.

class HumanWorker implements Workable, Eatable {

    @Override
    public void work() {
        System.out.println("Human is working");
    }

    @Override
    public void eat() {
        System.out.println("Human is eating");
    }
}

πŸ€– Robot Worker

Robot only works.

class RobotWorker implements Workable {

    @Override
    public void work() {
        System.out.println("Robot is working");
    }
}

Now:

βœ” Robot doesn't implement unused methods

βœ” No exceptions

βœ” Clean design


Step 3 β€” Test the Program

public class ISPExample {

    public static void main(String[] args) {

        Workable human = new HumanWorker();
        human.work();

        Workable robot = new RobotWorker();
        robot.work();
    }
}

Code Flow Explanation

Let's understand the execution flow.

Step-by-step flow:

1️⃣ HumanWorker implements:

  • Workable

  • Eatable

So it can:

  • Work

  • Eat


2️⃣ RobotWorker implements:

  • Workable only

So it can:

  • Work

  • (No eat method exists)


3️⃣ In main():

Workable human = new HumanWorker();
human.work();

Only required behavior is used.


Real-World Example β€” Printer System

This is one of the most popular ISP examples.

❌ Bad Design

interface Machine {
    void print();
    void scan();
    void fax();
}

Problem:

Not all machines support all features.

Example:

  • Basic Printer β†’ print only

  • Scanner β†’ scan only

But both must implement all methods.

Bad design.


βœ… ISP-Based Design

Split into smaller interfaces.

interface Printer {
    void print();
}

interface Scanner {
    void scan();
}

interface Fax {
    void fax();
}

πŸ–¨οΈ Multi-Function Printer

Supports all features.

class MultiFunctionPrinter 
        implements Printer, Scanner, Fax {

    public void print() {
        System.out.println("Printing...");
    }

    public void scan() {
        System.out.println("Scanning...");
    }

    public void fax() {
        System.out.println("Faxing...");
    }
}

πŸ–¨οΈ Simple Printer

Supports only printing.

class SimplePrinter implements Printer {

    public void print() {
        System.out.println("Simple printing...");
    }
}

Now every class implements only what it needs.

Perfect ISP usage.


Benefits of Interface Segregation Principle

Using ISP leads to:

βœ… Cleaner interfaces
βœ… Better code readability
βœ… Flexible system architecture
βœ… Easier testing
βœ… Reduced coupling
βœ… Improved scalability


Signs That ISP Is Being Violated

Look for:

🚩 Interfaces with too many methods
🚩 Classes implementing unused methods
🚩 Frequent use of:

UnsupportedOperationException

🚩 Difficult-to-maintain interfaces


🧠 ISP in Real Java Frameworks

Many Java APIs follow ISP.

Example:

Java Collections Framework:

List
Set
Queue
Map

Instead of one huge interface.

Each interface serves specific behavior.


Summary

The Interface Segregation Principle helps developers create:

βœ” Modular systems
βœ” Clean interfaces
βœ” Flexible architecture
βœ” Maintainable applications

Instead of:

❌ Large bloated interfaces
❌ Forced method implementations
❌ Runtime failures


Final Thought

"Many small interfaces are better than one large interface."

Following ISP leads to cleaner Java code, better design, and future-proof systems.


Design Principles for Java Developers

Part 2 of 10

This series explains core Java design principles and SOLID principles with simple examples, real-world use cases, and interview-focused explanations to help developers write clean, maintainable, and scalable code.

Up next

Liskov Substitution Principle (LSP) in Java

Introduction When designing software using inheritance, a common mistake developers make is creating subclasses that change expected behavior. This leads to: Unexpected bugsBroken polymorphismDifficul