Java 8 Static and Default Methods in Interface

Introduction

Java 8 introduced static and default methods in interfaces, which were a major change to the language. Before Java 8, interfaces could only have abstract methods. With static and default methods, Java 8 allows interfaces to have concrete methods, enabling more flexibility and providing default functionality. These additions simplify interface evolution, allowing developers to add new methods to interfaces without breaking existing implementations.

In this tutorial, we will explore what static and default methods are in interfaces and how they work with examples.

Table of Contents

  • Static Methods in Interface
  • Default Methods in Interface
  • Static vs Default Methods
  • Use Cases for Default and Static Methods

Static Methods in Interface

In Java 8, interfaces can now have static methods. These methods belong to the interface itself rather than to an instance of the class that implements the interface. Static methods in interfaces are called using the interface name and cannot be overridden by implementing classes.

Code Example

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

public class StaticMethodDemo {
    public static void main(String[] args) {
        // Calling static method of interface
        MyInterface.staticMethod();
    }
}

Output

Static method in interface

Explanation

  • The static method staticMethod() is defined in the MyInterface.
  • It is called directly using the interface name MyInterface.staticMethod(), and it cannot be overridden by classes implementing MyInterface.

Default Methods in Interface

Default methods in interfaces allow you to define a method with a body (implementation). Implementing classes can use this default implementation or override it if needed. This helps maintain backward compatibility when adding new methods to existing interfaces.

Code Example

interface MyInterface {
    // Default method in interface
    default void defaultMethod() {
        System.out.println("Default method in interface");
    }
}

public class DefaultMethodDemo implements MyInterface {
    public static void main(String[] args) {
        DefaultMethodDemo obj = new DefaultMethodDemo();
        // Calling default method
        obj.defaultMethod();
    }
}

Output

Default method in interface

Explanation

  • The interface MyInterface provides a default method defaultMethod().
  • The class DefaultMethodDemo implements the interface and calls the default method without overriding it.

Overriding a Default Method

You can override the default method in the implementing class if you need a custom implementation.

Code Example

interface MyInterface {
    default void defaultMethod() {
        System.out.println("Default method in interface");
    }
}

public class CustomMethodDemo implements MyInterface {
    // Overriding the default method
    @Override
    public void defaultMethod() {
        System.out.println("Overridden default method in class");
    }

    public static void main(String[] args) {
        CustomMethodDemo obj = new CustomMethodDemo();
        obj.defaultMethod();
    }
}

Output

Overridden default method in class

Explanation

  • The class CustomMethodDemo overrides the default method provided by MyInterface and provides a custom implementation.

Static vs Default Methods

Feature Static Method Default Method
Invocation Called using the interface name Called using the object instance
Overriding Cannot be overridden by implementing classes Can be overridden by implementing classes
Belongs To Belongs to the interface Belongs to the instance of the implementing class
Purpose Utility or helper methods for the interface Providing default implementation for methods
Example MyInterface.staticMethod() obj.defaultMethod()

Use Cases for Default and Static Methods

1. Backward Compatibility

  • Default methods allow you to add new methods to an interface without forcing all implementing classes to change. This is especially useful when evolving APIs.

  • For example, suppose you have an interface PaymentProcessor that is implemented by several classes. If you want to add a new method processRefund() to the interface, you can provide a default implementation. Existing classes that implement PaymentProcessor will not break.

Code Example: Backward Compatibility with Default Methods

interface PaymentProcessor {
    void processPayment();

    // New method added with default implementation
    default void processRefund() {
        System.out.println("Default refund processing");
    }
}

public class CreditCardProcessor implements PaymentProcessor {
    @Override
    public void processPayment() {
        System.out.println("Processing credit card payment");
    }
}

public class Main {
    public static void main(String[] args) {
        PaymentProcessor processor = new CreditCardProcessor();
        processor.processPayment();      // Calls the overridden method
        processor.processRefund();       // Calls the default method
    }
}

Output

Processing credit card payment
Default refund processing

2. Utility Methods

  • Static methods in interfaces are useful for utility or helper methods that logically belong to the interface. These methods can provide functionality that doesn't require access to instance data.

  • For example, you can add a validatePaymentDetails() static method to a PaymentProcessor interface that validates the payment details without requiring an instance of the implementing class.

Code Example: Static Utility Methods

interface PaymentProcessor {
    void processPayment();

    // Static utility method
    static boolean validatePaymentDetails(String paymentDetails) {
        return paymentDetails != null && !paymentDetails.isEmpty();
    }
}

public class Main {
    public static void main(String[] args) {
        // Calling static method without creating an instance
        boolean isValid = PaymentProcessor.validatePaymentDetails("credit card details");
        System.out.println("Payment details valid: " + isValid);
    }
}

Output

Payment details valid: true

3. Multiple Inheritance of Behavior

  • Default methods allow multiple inheritance of behavior. If a class implements multiple interfaces with default methods having the same method signature, the implementing class must resolve the conflict by overriding the method.

Code Example: Multiple Inheritance of Behavior

interface InterfaceA {
    default void display() {
        System.out.println("Display from Interface A");
    }
}

interface InterfaceB {
    default void display() {
        System.out.println("Display from Interface B");
    }
}

public class MultipleInheritanceDemo implements InterfaceA, InterfaceB {
    // Overriding to resolve the conflict
    @Override
    public void display() {
        InterfaceA.super.display();  // Calling InterfaceA's default method
        InterfaceB.super.display();  // Calling InterfaceB's default method
    }

    public static void main(String[] args) {
        MultipleInheritanceDemo obj = new MultipleInheritanceDemo();
        obj.display();
    }
}

Output

Display from Interface A
Display from Interface B

Conclusion

Java 8's introduction of static and default methods in interfaces provides more flexibility in defining and evolving APIs. Static methods are used for utility functions within the interface, while default methods allow interface evolution without breaking backward compatibility. These features reduce the need for abstract classes and give developers more options to design flexible, maintainable interfaces.

Comments