Private interface methods in Java 9

Starting in JDK 9 build 54, compiler support for private interface methods have been resurrected. This was one feature that was planned for Java 8 and did not make the final cut. It is now part of JEP 213. The primary motivation for this proposal is to enable code sharing between non abstract methods in an interface.

Interface evolution was always a tricky problem to solve in earlier versions of Java. You either need to maintain multiple versions of APIs which creates a technical debt over time or brute force your clients to accommodate new methods which breaks binary compatibility. The need to enhance an interface needed support in interface themselves instead of resorting to other options. This was fulfilled by default methods in interfaces in Java 8. Taking this further, private methods come in handy when we have a reusable block of code that default methods could benefit from. Latest Intellij 14.1 builds started to support JDK 9, so lets code an interface!.

public interface Api {
// constant declarations
int CAFEBABE = 0xCAFEBABE;
// abstract methods
void foo(int data);
void bar(int data);
// default methods
default void foo2(int data) {
new Object() {
void foo() {
validate(data);
System.out.println("I am foo v2!");
}
}.foo();
}
default void bar2(int data) {
new Object() {
void bar() {
validate(data);
System.out.println("I am bar v2!");
}
}.bar();
}
// static methods
static String ping() {
return "pong!";
}
// private methods
private boolean validate(int data) {
System.out.println("validating input: " + Integer.toHexString(data) + " => " + this);
return true;
}
static void main(String[] args) {
Api.ping();
Api api = new Api() {
@Override
public void foo(int data) {
System.out.println("I am legacy foo!");
}
@Override
public void bar(int data) {
System.out.println("I am legacy bar!");
}
};
api.foo(CAFEBABE);
api.bar(CAFEBABE);
api.foo2(CAFEBABE);
api.bar2(CAFEBABE);
}
}

view raw
Api.java
hosted with ❤ by GitHub

An interface now can contain these:

– constants
– method signatures
– nested types
– default methods (since 1.8)
– static methods (since 1.8)
– private methods (since 1.9)
– private static methods (since 1.9)

Some of the restrictions of private methods include:
– private methods must contain method body
– combination of modifiers not allowed : abstract and private
– private methods in an interface does not disqualify it from being a @FunctionalInterface
– annotations types cannot declare private methods
– name clash not permitted

public class NameClashTest {
interface I {
void foo(int x);
private I foo() {
return null;
}
private void foo(int x) {} // Invalid: method foo(int) is already defined in interface NameClashTest.I
}
interface J extends I {
private J foo() {
return null;
}
}
interface K extends J {
void foo();
}
}

view raw
NameClashTest.java
hosted with ❤ by GitHub

– cannot reduce visibility of private methods

public class VisibilityTest {
interface I {
private void foo(int x) {}
private void bar(int x) {}
}
interface J extends I {
void foo(int x); // Valid: public abstract method with the same signature as a private method in super type is allowed.
default void bar(int x) {} // Valid: public default method with the same signature as a private method in super type is allowed.
}
interface K extends J {
private void foo(int x) {} // Invalid: attempting to assign weaker access privileges
private void bar(int x) {} // Invalid: attempting to assign weaker access privileges
}
}

view raw
VisibilityTest.java
hosted with ❤ by GitHub

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Google photo

You are commenting using your Google account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s