Static and Private Methods of Interfaces

Introduction

Java 8+ allows static methods in interfaces. Java 9+ allows private methods in interfaces.


Static Methods in Interfaces

Static methods belong to the interface, not implementing classes.

Syntax:

interface MyInterface {
    static returnType methodName() {
        // Method body
    }
}

Simple Static Method Example

interface MathUtils {
    // Static method
    static int add(int a, int b) {
        return a + b;
    }

    static int multiply(int a, int b) {
        return a * b;
    }
}

public class Main {
    public static void main(String[] args) {
        // Call using interface name
        int sum = MathUtils.add(10, 20);
        int product = MathUtils.multiply(5, 6);

        System.out.println("Sum: " + sum);          // 30
        System.out.println("Product: " + product);  // 30
    }
}

Key Features of Static Methods

  1. Belongs to interface, not implementing class
  2. Called using interface name: InterfaceName.method()
  3. Cannot be overridden by implementing classes
  4. Must have body (not abstract)
  5. Can be inherited but not overridden

Static Method Rules

interface Example {
    static void staticMethod() {
        System.out.println("Static method");
    }
}

class MyClass implements Example {
    // Cannot override static method
    // static void staticMethod() { }  // Not overriding!
}

public class Main {
    public static void main(String[] args) {
        // ✓ Correct - call with interface name
        Example.staticMethod();

        // ✗ Wrong - cannot call with object
        // MyClass obj = new MyClass();
        // obj.staticMethod();  // Error

        // ✗ Wrong - cannot call with class name
        // MyClass.staticMethod();  // Error
    }
}

Private Methods in Interfaces

Private methods (Java 9+) help avoid code duplication in default/static methods.

Syntax:

interface MyInterface {
    // Private method
    private returnType methodName() {
        // Method body
    }

    // Private static method
    private static returnType staticMethodName() {
        // Method body
    }
}

Private Method Example

interface Calculator {
    // Private method - helper for default methods
    private void log(String message) {
        System.out.println("LOG: " + message);
    }

    // Default methods using private method
    default int add(int a, int b) {
        log("Adding " + a + " and " + b);
        return a + b;
    }

    default int subtract(int a, int b) {
        log("Subtracting " + b + " from " + a);
        return a - b;
    }
}

class MyCalculator implements Calculator { }

public class Main {
    public static void main(String[] args) {
        Calculator calc = new MyCalculator();
        System.out.println(calc.add(10, 5));       // LOG: Adding 10 and 5 \n 15
        System.out.println(calc.subtract(10, 5));  // LOG: Subtracting 5 from 10 \n 5
    }
}

Private Static Methods

Private static methods help static methods avoid code duplication.

interface StringUtils {
    // Private static helper method
    private static boolean isNullOrEmpty(String str) {
        return str == null || str.isEmpty();
    }

    // Static methods using private static method
    static String reverse(String str) {
        if (isNullOrEmpty(str)) {
            return str;
        }
        return new StringBuilder(str).reverse().toString();
    }

    static String toUpperCase(String str) {
        if (isNullOrEmpty(str)) {
            return str;
        }
        return str.toUpperCase();
    }
}

public class Main {
    public static void main(String[] args) {
        System.out.println(StringUtils.reverse("hello"));      // olleh
        System.out.println(StringUtils.toUpperCase("world")); // WORLD
        System.out.println(StringUtils.reverse(null));        // null
    }
}

Complete Example: Validation Interface

interface Validator {
    // Private method - common validation logic
    private boolean isValidLength(String str, int minLength, int maxLength) {
        if (str == null) return false;
        int length = str.length();
        return length >= minLength && length <= maxLength;
    }

    // Private static method - helper for static methods
    private static void printError(String field, String message) {
        System.out.println("Error in " + field + ": " + message);
    }

    // Default methods using private method
    default boolean validateUsername(String username) {
        if (!isValidLength(username, 3, 20)) {
            System.out.println("Username must be 3-20 characters");
            return false;
        }
        return true;
    }

    default boolean validatePassword(String password) {
        if (!isValidLength(password, 8, 30)) {
            System.out.println("Password must be 8-30 characters");
            return false;
        }
        return true;
    }

    // Static methods using private static method
    static boolean validateEmail(String email) {
        if (email == null || !email.contains("@")) {
            printError("Email", "Invalid format");
            return false;
        }
        return true;
    }

    static boolean validatePhone(String phone) {
        if (phone == null || phone.length() != 10) {
            printError("Phone", "Must be 10 digits");
            return false;
        }
        return true;
    }
}

class UserValidator implements Validator { }

public class Main {
    public static void main(String[] args) {
        UserValidator validator = new UserValidator();

        // Using default methods
        System.out.println("Username valid: " + validator.validateUsername("john"));     // true
        System.out.println("Password valid: " + validator.validatePassword("pass"));     // false

        // Using static methods
        System.out.println("Email valid: " + Validator.validateEmail("test@mail.com")); // true
        System.out.println("Phone valid: " + Validator.validatePhone("123"));           // false
    }
}

Comparison Table

FeatureStatic MethodPrivate MethodPrivate Static Method
SinceJava 8Java 9Java 9
AccessPublicPrivatePrivate
Call fromOutside interfaceInside interface onlyInside interface only
BodyRequiredRequiredRequired
Can be overriddenNoNoNo
Used byAnyoneDefault methodsStatic methods
Call syntaxInterface.method()this.method()method()

Real-World Example: Logger Interface

interface Logger {
    // Private static method - formatting helper
    private static String formatMessage(String level, String message) {
        return "[" + level + "] " + java.time.LocalTime.now() + " - " + message;
    }

    // Private method - actual logging implementation
    private void writeLog(String formattedMessage) {
        System.out.println(formattedMessage);
    }

    // Default methods using private methods
    default void info(String message) {
        String formatted = formatMessage("INFO", message);
        writeLog(formatted);
    }

    default void error(String message) {
        String formatted = formatMessage("ERROR", message);
        writeLog(formatted);
    }

    default void warning(String message) {
        String formatted = formatMessage("WARNING", message);
        writeLog(formatted);
    }

    // Static utility method
    static void logSystemInfo() {
        System.out.println(formatMessage("SYSTEM", "Java version: " + System.getProperty("java.version")));
    }
}

class ApplicationLogger implements Logger { }

public class Main {
    public static void main(String[] args) {
        Logger logger = new ApplicationLogger();

        logger.info("Application started");
        logger.warning("Low memory");
        logger.error("Connection failed");

        Logger.logSystemInfo();
    }
}

Benefits

Static Methods:

  1. Utility methods in interface
  2. No need for separate utility class
  3. Related functionality stays together
  4. Factory methods for creating objects

Private Methods:

  1. Code reuse in default methods
  2. Avoid duplication in interface
  3. Encapsulation of helper logic
  4. Clean code organization

Static Method Use Cases

interface Shape {
    double area();

    // Static factory method
    static Shape createCircle(double radius) {
        return new Circle(radius);
    }

    static Shape createRectangle(double length, double width) {
        return new Rectangle(length, width);
    }

    // Static utility method
    static void printShapeInfo(Shape shape) {
        System.out.println("Area: " + shape.area());
    }
}

class Circle implements Shape {
    private double radius;

    Circle(double radius) {
        this.radius = radius;
    }

    @Override
    public double area() {
        return Math.PI * radius * radius;
    }
}

class Rectangle implements Shape {
    private double length, width;

    Rectangle(double length, double width) {
        this.length = length;
        this.width = width;
    }

    @Override
    public double area() {
        return length * width;
    }
}

public class Main {
    public static void main(String[] args) {
        // Using static factory methods
        Shape circle = Shape.createCircle(5);
        Shape rectangle = Shape.createRectangle(4, 6);

        // Using static utility method
        Shape.printShapeInfo(circle);
        Shape.printShapeInfo(rectangle);
    }
}

Private Method Use Cases

interface DataProcessor {
    // Private validation helper
    private boolean isValid(String data) {
        return data != null && !data.isEmpty();
    }

    // Private transformation helper
    private String transform(String data) {
        return data.trim().toUpperCase();
    }

    // Default methods using private helpers
    default void process(String data) {
        if (!isValid(data)) {
            System.out.println("Invalid data");
            return;
        }
        String processed = transform(data);
        System.out.println("Processed: " + processed);
    }

    default void processMultiple(String... dataArray) {
        for (String data : dataArray) {
            if (isValid(data)) {
                System.out.println(transform(data));
            }
        }
    }
}

class MyProcessor implements DataProcessor { }

public class Main {
    public static void main(String[] args) {
        DataProcessor processor = new MyProcessor();
        processor.process("  hello  ");                    // HELLO
        processor.processMultiple(" java ", " python ");  // JAVA \n PYTHON
    }
}

Method Access Rules

interface Example {
    // Private method - accessible only within this interface
    private void privateMethod() {
        System.out.println("Private");
    }

    // Private static method - accessible only within this interface
    private static void privateStaticMethod() {
        System.out.println("Private static");
    }

    // Default method - can call private methods
    default void defaultMethod() {
        privateMethod();          // ✓ OK
        privateStaticMethod();    // ✓ OK
    }

    // Static method - can call only private static methods
    static void staticMethod() {
        // privateMethod();       // ✗ Error - cannot call instance private
        privateStaticMethod();    // ✓ OK
    }
}

Common Patterns

1. Factory Pattern:

interface Product {
    void create();

    static Product getInstance(String type) {
        if ("A".equals(type)) {
            return new ProductA();
        }
        return new ProductB();
    }
}

2. Validation Pattern:

interface Validator {
    private boolean commonValidation(String data) {
        return data != null && data.length() > 0;
    }

    default boolean validate(String data) {
        return commonValidation(data);
    }
}

3. Utility Pattern:

interface Utils {
    static void print(String message) {
        System.out.println(message);
    }
}

Quick Reference

interface MyInterface {
    // Static method (Java 8+)
    static void staticMethod() {
        System.out.println("Static");
    }

    // Private method (Java 9+)
    private void privateMethod() {
        System.out.println("Private");
    }

    // Private static method (Java 9+)
    private static void privateStaticMethod() {
        System.out.println("Private static");
    }

    // Default method using private
    default void defaultMethod() {
        privateMethod();
    }

    // Static method using private static
    static void anotherStatic() {
        privateStaticMethod();
    }
}

// Usage
MyInterface.staticMethod();           // Call static
MyInterface obj = new MyClass();
obj.defaultMethod();                  // Calls private internally

Common Mistakes

interface Example {
    private void privateMethod() { }

    static void staticMethod() {
        // ✗ Cannot call instance private from static
        // privateMethod();  // Error
    }
}

class MyClass implements Example {
    // ✗ Cannot access private methods from implementing class
    void test() {
        // privateMethod();  // Error - not visible
    }

    // ✗ Cannot override static methods
    // static void staticMethod() { }  // Not overriding!
}

Exam Tips

Remember:

  1. Static methods since Java 8
  2. Private methods since Java 9
  3. Static called with interface name
  4. Private only inside interface
  5. Private helps avoid duplication
  6. Static cannot be overridden
  7. Private instance from default methods
  8. Private static from static methods
  9. Must have method body
  10. Used for utility and helper methods

Common Questions:

  • When were static methods added?
  • When were private methods added?
  • How to call static interface method?
  • Can static methods be overridden?
  • Purpose of private methods?
  • Difference: private vs private static?
  • Can private methods be accessed in implementing class?
  • Benefits of static methods in interface?
  • Use cases for private methods?
  • Can static method call private instance method?