Java Default Methods
As a Java developer for years, you may have very strong sense about how Java should be. Object-oriented, single inheritance, multiple interface implementation, generic, etc. But things change slightly since the born of Java 8. Have you ever try how to declare optional functions in interface?
History
Java 8 brings lots of modern and powerful new features — Lambda, Stream, etc. Though brand new features come with brand new syntax which we don’t familiar, the fundamental of Java still stand firmly. But it will be a breaking change for some feature like stream if we want to support in the interface layer. Let’s say if we want to add new functions in an existing interface, all the implementation should update or it will break. There will be a big compatible issue for us, so here comes the idea of default methods. Which allow us to add function implementation into an interface. So upgrade to Java 8 won’t be a headache for us.
If you’re interested in Lambda, you can check it out here — Lambda Expression in Java
Default Method
As you can imagine, it’s hard to add new functions into an existing interface because we need to add implementations all over the world. So we decide add implementations into interface itself directly. Here is a basic example:
public interface A {
default void a() {
// add implementation here
}
}
Yes, that simple. If you place the key word default
in front of the function declaration in interface then you can add the implementation just like a normal function does.
With this new feature, we can achieve some things that we can’t do before, even some evil things.
- Optional function.
- Multiple inheritance.
- Common implementation.
Optional function
If we have a function in interface which we want to label it as optional, we can add an empty implementation to it.
public interface A {
default void a() {
}
}public Class realA implement A {
// no need to implement a() again
}
Beside the redundant smell, you should ask yourself if your interface takes too much responsibility which we can divide into different part. There’s no right or wrong, but do think one more second before you start to write.
Multiple inheritance
Java doesn’t support multiple inheritance, but since the interface now can have implementation, it almost like a multiple inheritance-able language.
public interface A {
default void common() {
System.out.println("This is common a.");
}
}public interface B {
default void common() {
System.out.println("This is common b.");
}
}public Class realAB implement A, B {
public void test() {
common();
}
}
Which one will the common()
execute? A or B? The result is compile fail. Multi-inheritance is not only Java 8’s problem and here is the common solution: we should provide the context to the compiler.
public Class realAB implement A, B {
public void test() {
A.super.common(); // execute A
B.super.common(); // execute B
}
}
Problem solved. But we should try to avoid the duplicate naming situation if possible.
Common implementation
If an interface contains some common implementations. It’s the best match for default methods. Here is a simple example.
public interface Callback<T> {
void success(T t); default void fail(String msg) {
LogUtils.log(msg);
UIUtils.showError(msg);
}
}public Class ClassA implement Callback<A> { public void success(A a) {
// success A
}
}public Class ClassB implement Callback<B> { public void success(B b) {
// success B
}
}
If every fail()
function has same logic, there’s no need to repeat ourself.
Summary
Default methods bring a new world to develop Java applications. But we still need to distinguish different role between Class, abstract Class and interface. We should leverage the power of default methods but still comply with our ground rule — an interface is an interface, not a Class or abstract Class.