Java 8 default methods examples

In Java 8(onwards), we can define default methods in interfaces. The default method is also called as virtual extension method or defender method. In this post, we are going to see Java 8 default methods examples.

In Java 8, default methods were introduced to provide a way to add new methods to interfaces without breaking the classes that implement those interfaces. Default methods allow us to add method implementations to interfaces, which were previously not allowed in Java.

Note – Java 8 default methods can have a body. Also, it is optional to override default methods. The Default methods were introduced to provide backward compatibility for old interfaces so that they can have new methods without affecting existing code. For example, the List interface is implemented by many classes( ArrayListAttributeListCopyOnWriteArrayListLinkedList, and many more). Before Java 8 adding a new method in the List interface would break these implementation classes. Using default methods we can add new methods without breaking those classes, Since default methods have body there we can have implementation logic.

interface MyInterface {
    void regularMethod(); // Regular abstract method

    default void defaultMethod() {
        System.out.println("Default method implementation");
    }
}

class MyClass implements MyInterface {
    @Override
    public void regularMethod() {
        System.out.println("Regular method implementation");
    }

    // Optional: Overriding the default method
    @Override
    public void defaultMethod() {
        System.out.println("Custom default method implementation");
    }
}

Let’s see some more examples.

interface Shape {
    void draw(); // Abstract method

    default void displayInfo() {
        System.out.println("This is a shape.");
    }
}

class Circle implements Shape {
    @Override
    public void draw() {
        System.out.println("Drawing a circle.");
    }
}

class Rectangle implements Shape {
    @Override
    public void draw() {
        System.out.println("Drawing a rectangle.");
    }

    @Override
    public void displayInfo() {
        System.out.println("This is a rectangle.");
    }
}

public class Main {
    public static void main(String[] args) {
        Circle circle = new Circle();
        circle.draw();
        circle.displayInfo();

        Rectangle rectangle = new Rectangle();
        rectangle.draw();
        rectangle.displayInfo();
    }
}

Output:-

Drawing a circle.
This is a shape.
Drawing a rectangle.
This is a rectangle.

Note – Default method can be written only inside interface not inside class.

Here are five different examples of Java 8 default methods, along with their expected outputs.

Example 1: Default Method in Interface

interface Greeting {
    default void greet() {
        System.out.println("Hello, from the Greeting interface!");
    }
}

class Person implements Greeting {
    // No need to provide an implementation for greet() here
}

public class Main {
    public static void main(String[] args) {
        Person person = new Person();
        person.greet(); // Output: Hello, from the Greeting interface!
    }
}

Explanation: The Greeting interface contains a default method greet(). The Person class implements the Greeting interface, inheriting the default greet() implementation.

Example 2: Overriding Default Method

interface Calculator {
    default int add(int a, int b) {
        return a + b;
    }
}

class AdvancedCalculator implements Calculator {
    @Override
    public int add(int a, int b) {
        return a + b + 100;
    }
}

public class Main {
    public static void main(String[] args) {
        Calculator basicCalc = new Calculator() {};
        System.out.println(basicCalc.add(5, 3)); // Output: 8

        AdvancedCalculator advCalc = new AdvancedCalculator();
        System.out.println(advCalc.add(5, 3)); // Output: 108
    }
}

Explanation: The Calculator interface has a default method add(). The AdvancedCalculator class overrides this default method to modify the behavior.

Example 3: Conflicting Default Methods

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

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

class MultipleInterfaces implements InterfaceA, InterfaceB {
    // Must provide an implementation to resolve the conflict
    @Override
    public void display() {
        InterfaceA.super.display(); // Calling default implementation from InterfaceA
        InterfaceB.super.display(); // Calling default implementation from InterfaceB
    }
}

public class Main {
    public static void main(String[] args) {
        MultipleInterfaces obj = new MultipleInterfaces();
        obj.display(); // Output: Interface A, Interface B
    }
}

Explanation: Both InterfaceA and InterfaceB have default display() methods. The MultipleInterfaces class must provide an implementation that explicitly resolves the conflict by choosing which default method to call.

Example 4: Default Method with Parameters

interface Messenger {
    default void sendMessage(String message) {
        System.out.println("Default message: " + message);
    }
}

class ChatUser implements Messenger {
    // No need to provide an implementation for sendMessage()
}

public class Main {
    public static void main(String[] args) {
        ChatUser user = new ChatUser();
        user.sendMessage("Hello!"); // Output: Default message: Hello!
    }
}

Explanation: The Messenger interface’s default method sendMessage() takes a parameter. The ChatUser class implements the interface and inherits the default method with its implementation.

Example 5: Inheritance Chain of Default Methods

interface A {
    default void show() {
        System.out.println("A");
    }
}

interface B extends A {
    // Inherits the default method show() from interface A
}

class C implements B {
    // No need to provide an implementation for show()
}

public class Main {
    public static void main(String[] args) {
        C obj = new C();
        obj.show(); // Output: A
    }
}

Explanation: Interface B extends A, inheriting the default method show(). The class C implements interface B and thus inherits the default method from both interfaces A and B.

These examples illustrate different scenarios where default methods can be used in Java 8 interfaces, providing flexibility and enhancing code reusability.

Default methods are particularly useful when you want to extend existing interfaces without affecting the classes that implement them. They were introduced to support evolving APIs and adding new functionality to interfaces in a backward-compatible manner.

Objective questions. Tets yourself.

Of course! Here are five objective questions related to Java 8 default methods, along with four options for each question. The correct answers are provided at the end.

Question 1:
What is the primary purpose of Java 8 default methods?
A) To create abstract methods in interfaces.
B) To allow multiple inheritance in classes.
C) To provide a way to add new methods to interfaces without breaking existing implementations.
D) To override methods in child classes.

Question 2:
When a class implements an interface that contains a default method, what happens if the class does not provide its own implementation for that method?
A) The class will not compile due to an error.
B) The class inherits the default implementation from the interface.
C) The class inherits the implementation from the Object class.
D) The default method becomes abstract and must be overridden by the class.

Question 3:
What is the term used to describe the scenario when a class implements multiple interfaces with conflicting default method implementations?
A) Ambiguous Implementation
B) Overlapping Method
C) Diamond Problem
D) Interface Conflict

Question 4:
Which keyword is used to declare a default method in an interface?
A) new
B) default
C) abstract
D) override

Question 5:
In a class that implements multiple interfaces with the same default method, how can you explicitly choose which default method implementation to use?
A) By using the super keyword to call the parent interface’s default method.
B) By marking the method as final in the class implementation.
C) By providing a separate implementation for the method in the class.
D) By using the default keyword before the method in the class.

Question 6:

Will the following Java program compile successfully?

interface MyInterface1{

    default void m2(){

    }
    default int hashCode(){
        return 1;
    }
}

class MyTest1 implements MyInterface1{

}

A. Yes, the program will compile successfully.

B. No, the program will not compile due to an error in the m2() method.

C. No, the program will not compile due to an error in the hashCode() method.

D. No, the program will not compile due to errors in both the m2() and hashCode() methods.

Answers:

  1. C) To provide a way to add new methods to interfaces without breaking existing implementations.
  2. B) The class inherits the default implementation from the interface.
  3. C) Diamond Problem
  4. B) default
  5. A) By using the super keyword to call the parent interface’s default method.
  6. C) No, the program will not compile due to an error in the hashCode() method.

Some more programs.

package com.javatute.java8;

interface First {
    default void m1() {
        System.out.println("First interface's m1() method");
    }
}

interface Second {
    default void m1() {
        System.out.println("Second interface's m1() method");
    }
}

public class MyTest implements First, Second {
    public static void main(String[] args) {

    }
}

The above code will give a compilation error since we have the same m1() method in both interfaces. To overcome this problem we need to override m1() in class MyTest(). Below code will compile successfully.

interface First {
    default void m1() {
        System.out.println("First interface's m1() method");
    }
}

interface Second {
    default void m1() {
        System.out.println("Second interface's m1() method");
    }
}

public class MyTest implements First, Second {
    public void m1(){
        System.out.println("i am overridden method");
    }
    public static void main(String[] args) {

    }
}

Calling Java 8 default methods using interface name.

package com.javatute.java8;

interface First {
    default void m1() {
        System.out.println("First interface's m1() method");
    }
}

interface Second {
    default void m1() {
        System.out.println("Second interface's m1() method");
    }
}

public class MyTest implements First, Second {
    public void m1(){
        First.super.m1();
    }
    public static void main(String[] args) {
        MyTest myTest = new MyTest();
        myTest.m1();
    }
}

Output:-

First interface's m1() method

See docs.

That’s all about Java 8 default methods examples.