4

I have an interface and its 2 or more implementations say,

public interface IProcessor {
  default void method1() {
   //logic
  }
  default void method2() {
   //logic
  }
  public void method3();
  public void method4();
}

Here, The method1 and method2 implementation logic is common across all multiple multiple implementation classes. So defined as default methods. So only the rest of the methods can be overridden in the implementation classes.

public CarImpl implements IProcessor {
  @Override 
  public void method3() {
    //logic
  }
  @Override 
  public void method4() {
    //logic
  }
}

public VanImpl implements IProcessor {
  @Override 
  public void method3() {
    //logic
  }
  @Override 
  public void method4() {
    //logic
  }
}

Is there a better approach that I can achieve this without default methods and without redundant code in the respective implementation classes? Because if the code in the default methods increases then the interface looks clumsy.

3
  • You could have an abstract class to hold these implementations and make that a common superclass for your two Impl. This is what people did before there were default methods on interfaces. Commented Jan 13, 2021 at 10:45
  • 3
    " So only the rest of the methods can be overridden in the implementation classes." ... just pointing out that this statement is incorrect. Default methods in interfaces can also be overridden in implementing classes, and implementors are free to do so if they require some other behavior. Commented Jan 13, 2021 at 17:23
  • 1
    btw, we don't usually put an 'I' before interface names in java. The name itself is enough. Commented Jan 15, 2021 at 6:36

2 Answers 2

7

Default methods can be overridden

You said:

So only the rest of the methods can be overridden in the implementation classes.

The word "only" there is incorrect. A default method in an interface can indeed be overridden by an implementing class. Thus the word default used as the keyword here, meaning: use this method code if no other implementing code is present at runtime.

Here is a silly contrived example where we define an interface Fruit with a default method isJuicy that returns true. We have two subclasses, Orange and Banana. The first has no override of isJuicy, so its behavior comes from the default method. The second demonstrates that you can override the default method. Here we see the override return false.

package work.basil.example;

public class OverridingDefault
{
    public static void main ( String[] args )
    {
        OverridingDefault app = new OverridingDefault();
        app.demo();
    }

    private void demo ( )
    {
        System.out.println( "new Orange().isJuicy(): " + new Orange().isJuicy() );
        System.out.println( "new Banana().isJuicy(): " + new Banana().isJuicy() );
    }

    public interface Fruit
    {
        default boolean isJuicy ( )
        {
            return true;
        }
    }

    public class Orange implements Fruit
    {
    }

    public class Banana implements Fruit
    {
        @Override
        public boolean isJuicy ( )
        {
            return false;
        }
    }
}

When run.

new Orange().isJuicy(): true
new Banana().isJuicy(): false

Prefer abstract classes over default methods

You asked:

Is there a better approach that I can achieve this without default methods and without redundant code in the respective implementation classes?

I do suggest you not use default interface methods for this.

The idea and technology for adding default methods to Java interfaces was not as a feature in itself, but as a solution to another problem: Retrofitting functionality onto existing interfaces to support new lambda features but without breaking the existing code of millions of Java programmers as would happen when otherwise adding methods to existing interfaces. By inventing default method on interfaces, the Java team was able to add more methods to existing interfaces while relieving all existing implementations of the need to implement those new methods. New features, without breaking code, a hallmark of Java.

As stated in State of the Lambda by Brian Goetz 2013-09:

The purpose of default methods (…) is to enable interfaces to be evolved in a compatible manner after their initial publication.

My own opinion is that programmers are generally not going to expect behavior to be built into your interfaces. The classic use of an interface in Java is to define a contract per the method signatures, not define behavior (code). So consider adding adding behavior (code) as default methods only as a last resort.

Instead, define your interface as a contract, with no default methods. At least no default methods at first; you may find later a need as did Brian Goetz and the Java team to add default methods later. But start with only the contract.

Then define an abstract class that implements that interface. Any behavior (code) to be shared across the various subclasses can be moved into this abstract class.

Then go on to define subclasses, concrete classes, that inherit from your abstract class.

With this classic and common approach of interface + abstract class + concrete classes, you have flexibility to make changes, and to make testing easier (with stubs rather than real classes), while efficiently sharing code from one place yet allowing overrides where needed.

Sign up to request clarification or add additional context in comments.

3 Comments

I totally agree. Personally, I wouldn't have added methods to interfaces as part of the language spec. I understand the intent and I think that supporting the 1 in a million edge case where you need this serves only to confuse the hell out of people learning the language. Any engineer working for me would have to have a pretty solid reason for using such a thing otherwise they'd be sent on a refresher course on OO principles. Best avoided.
"The purpose of default methods (…) is to enable interfaces to be evolved in a compatible manner after their initial publication." ... here is a place where Joshua Bloch and Brian Goetz don't agree. Bloch asserts that evolving interfaces after publication can break client code if the default implementation isn't capable of preserving all invariants in the client. He does, however, promote using default methods in interfaces before publication to provide skeletal implementations for clients. I.e. Prefer default methods over abstract classes (when feasible) before publication.
@scottb Can you cite a source on Bloch’s position? That would help those who want to further explore this topic.
1

You don't do anything wrong, although I'd say abstract classes are better suited in this case, when you have method implementations (method1,method2) shared across multiple implementations.

If you still want it to be an interface, create a interface and an abstract class extending the interface.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.