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!.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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); | |
} | |
} |
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
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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(); | |
} | |
} |
– cannot reduce visibility of private methods
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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 | |
} | |
} |