'. '

DefaultMethods

From APIDesign

Revision as of 08:52, 24 September 2016 by JaroslavTulach (Talk | contribs)
Jump to: navigation, search

DefaultMethods is a new feature in JDK8 which breaks the clear separation between Java interface (only specifies a contract) and class (provides some implementation). Many members of the Java community were crying for having a way to add methods into interface in a backward compatible way for ages. Of course, as usual inJava, only when the JDK team felt the need itself (because of adding a lot of new methods into Collection & co. classes), it listen to the general request.

On the other hand, there were people claiming that DefaultMethods are bad - that an interface should be a code-less specification and the change will have consequences. Here is one.

By-Passing Your Interface

When I was implementing Html4Java API, I had to create an observable list - so I did it and created JSONList. I've carefully overwritten each public method that modified the list state and called a change notification handler. What can be the problem?

@Override
public boolean add(T e) {
  boolean ret = super.add(e);
  notifyChange();
  return ret;
}

I thought I did everything correctly, as all the methods of the List interface are properly overwritten. But of course, the problem appeared with DefaultMethods. If you write this code:

People p = new People();
List<String> names = p.getNicknames();
Collections.sort(names);

it works properly on JDK7, but it gets broken on JDK8. In spite of the fact that no [[DefaultMethods] are called, the notification change isn't delivered! The problem is that the static sort method in collection does the sorting by itself in JDK7, but in JDK8 it delegates to List.sort:

public static <T extends Comparable<? super T>> void sort(List<T> list) {
        list.sort(null);
    }

and of course there is an optimized implementation of sort in ArrayList that bypasses all existing (at time of JDK7) methods and sorts directly the internal array:

@Override
@SuppressWarnings("unchecked")
public void sort(Comparator<? super E> c) {
    final int expectedModCount = modCount;
    Arrays.sort((E[]) elementData, 0, size, c);
    if (modCount != expectedModCount) {
        throw new ConcurrentModificationException();
    }
    modCount++;
}

as such the JSONList can be sorted without notifying about changes. This is a similar problem as discussed in Chapter 8 of TheAPIBook.

The solution is to overwrite the sort method, but this is the kind of problems we can expect with DefaultMethods - interface no longer represents a snapshot of protocol at a time, but can evolve.

Personal tools
buy