Search code examples
javadesign-patternsinterfacejvm-languages

Why adding a new method to the Java interface breaks the clients that depend on old version?


In Java when you add a new method to an interface, you break all your clients. When you have an abstract class, you can add a new method and provide a default implementation in it. All the clients will continue to work.

I wonder why the interface is designed this way?

All the old methods are still there, so seems like there is no backward compatibility issue. (Of course there need to be certain exceptions, but I think enabling to add new methods to java interfaces without breaking the clients could be really good idea...)

I'd appreciate your comments.


Solution

  • There are a few possible breaks I can see

    • you assume that clients will use a new overloaded method, but they don't because the code hasn't been recompiled.
    • you add a method which the client already had which does something different.
    • you add a method which means their subclasses break when recompiled. IMHO This is desirable.
    • you change the return type, method name or parameters types which will cause an Error at runtime.
    • you swap parameters of the same type. This is possibly the worst and most subtle bug. ;)

    IMHO, It's the subtle problems which are more likely to cause you grief. However, I wouldn't assume that simply adding a method will break the code and I wouldn't assume that if a client's code isn't getting runtime error means they are using the latest version of anything. ;)


    If I compile this code

    public interface MyInterface {
        void method1();
    
        // void method2();
    }
    
    public class Main implements MyInterface {
        @Override
        public void method1() {
            System.out.println("method1 called");
        }
    
        public static void main(String... args) {
            new Main().method1();
        }
    }
    

    it prints

    method1 called
    

    I then uncomment method2() and recompile just the interface. This means the interface has a method the Main doesn't implement. Yet when I run it without recompiling Main I get

    method1 called
    

    If I have

    public class Main implements MyInterface {    
        public void method1() {
            System.out.println("method1 called");
        }
    
        public void method2() {
            System.out.println("method2 called");
        }
    
        public static void main(String... args) {
            new Main().method1();
        }
    }
    

    and I run with // method2() commented out, I don't have a problem.