Consider the following code, which is an extraction of a real use case where LinkedList<E>
implements both List<E>
and Deque<E>
.
One can observe that both interfaces have a size()
and an isEmpty()
method, where the isEmpty()
method could be made default in terms of size()
.
So, let's do that (with dummy interfaces), since Java 8 does not do it yet:
interface List<E> {
public int size();
default public boolean isEmpty() {
return (size() == 0);
}
//more list operations
}
interface Deque<E> {
public int size();
default public boolean isEmpty() {
return (size() == 0);
}
//more deque operations
}
class LinkedList<E> implements List<E>, Deque<E> {
private int size;
@Override
public int size() {
return size;
}
}
Oops! We get a compile-time error on LinkedList
, as it does not know which isEmpty()
implementation to use, so we add this:
@Override
public boolean isEmpty() {
return List.super.isEmpty();
}
Now we have lost practically all benefits of default methods for this use case, as it still takes us as much code to write the isEmpty()
method as it did before.
But can it be solved? Yes!
Consider the following implementation:
interface Sizable {
public int size();
default public boolean isEmpty() {
return (size() == 0);
}
}
interface List<E> extends Sizable {
//list operations
}
interface Deque<E> extends Sizable {
//deque operations
}
class LinkedList<E> implements List<E>, Deque<E> {
private int size;
@Override
public int size() {
return size;
}
}
So the question:
- Is this how we, and also the JDK, are supposed to handle it in future implementations?