Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Java 8 - default methods - concerns for legacy code

Question from a book:

In the past (pre-Java 8), you were told that it’s bad form to add methods to an interface because it would break existing code. Now you are told that it’s okay to add new methods, provided you also supply a default implementation.

  1. How safe is that? Describe a scenario where the new stream method of the Collection interface causes legacy code to fail compilation.
  2. What about binary compatibility? Will legacy code from a JAR file still run?"

My answers are as follows but I am not quite sure about them.

  1. It's safe only if legacy code does not provide a method with the same name stream and with the same signature (e.g. in a legacy class that implements Collection). Otherwise, this old legacy code will fail compilation.
  2. I think binary compatibility is preserved, legacy code from old JAR file will still run. But I have no clear arguments at all about this.

Could anyone confirm or reject these answers, or just add some more arguments, references, or clarity to these answers?

like image 486
peter.petrov Avatar asked Oct 14 '15 16:10

peter.petrov


1 Answers

  1. The new stream() default method in Collection returns a Stream<E>, also a new type in Java 8. Legacy code will fail compilation if it contains a stream() method with the same signature, but returning something else, resulting in a clash of return types.

  2. Legacy code will continue to run as long as it's not recompiled.

First, in 1.7, set up the following:

public interface MyCollection {
    public void foo();
}

public class Legacy implements MyCollection {
    @Override
    public void foo() {
        System.out.println("foo");
    }

    public void stream() {
        System.out.println("Legacy");
    }
}

public class Main {
    public static void main(String args[]) {
        Legacy l = new Legacy();
        l.foo();
        l.stream();
    }
}

With -source 1.7 -target 1.7, this compiles and runs:

$ javac -target 1.7 -source 1.7 Legacy.java MyCollection.java Main.java
$ java Main
foo
Legacy

Now in 1.8, we add the stream method to MyCollection.

public interface MyCollection
{
    public void foo();
    public default Stream<String> stream() {
        return null;
    }
}

We compile only MyCollection in 1.8.

$ javac MyCollection.java
$ java Main
foo
Legacy

Of course we can't recompile Legacy.java any more.

$ javac Legacy.java
Legacy.java:11: error: stream() in Legacy cannot implement stream() in MyCollection
    public void stream()
                ^
  return type void is not compatible with Stream<String>
1 error
like image 162
rgettman Avatar answered Oct 27 '22 00:10

rgettman