Private Methods in Java Interfaces

Evolution of Java Interfaces

In Java 1.0, an interface definition could contain only two kinds of members:

  • final variable
  • abstract methods
public interface Interface01 {
    int finalInt = 9; // variable declaration
    int abstractMethod(double n1, int n2); // method declaration    

Inner classes introduced in Java 1.1. From Java 2 onward, we had the static nested classes and interfaces, and these could also be used inside an interface. Thus, since Java 2, we two extra kinds of members in an interface:

  • inner (nested) interfaces
  • inner (nested) classes
public interface Interface02 {
    // Java 1 kinds of members
    // inner interface definition
    interface InnerInterface {
        // member of an interface
    // inner class definition
    class InnerClass { 
        // members of a class

Java 5 introduced generics type parameters. Then now we can have generic classes, generic interfaces, and generic methods. So, from Java 5 onward, we could have another two members in an interface,

  • inner (nested) enums
  • inner (nested) annotations

and the abstract method now can use Generic type parameter
public interface Interface03<T> {
    // Java 1 kinds of members
    // Java 2 kinds of members
    // method using type parameter
    T abstractMethodUsingGenericType(T cls); 
    // nested enum definition
    enum NestedEnum {   
    // nested annotation definition
    @interface NestedAnnotation {   
        String variable1();

Java 8 added default methods as members in the interface. This allowed the interface to be enhanced with new methods, providing a default implementation for the new method. Java 8 also allowed interfaces to include static methods. Therefore, from Java 8 onward, we could have another two members in an interface:

  • default methods
  • static methods
public interface Interface04<T> {
    // Java 1 kinds of members
    // Java 2 kinds of members
    // Java 5 kinds of members
    default void defaultMethod(int x, int y) {
        // implementation of method
    static void staticMethod(String[] args) {
        // any static method can be included in interface

Check this article about default methods and static methods in Java interfaces.

Since we can implement behavior via default methods which is public in interface, there are possibilities that we have a repetitive, common code, which is duplicated in multiple default methods within the same interface. To avoid this, we should break the repetitive part of implementation of a method into another methods. But, in Java 8, it's also will becomes another default public method. Since these methods may not really be required to be available outside the interface (not public), they should ideally be private.

This can now be done with Java 9, which introduced private methods in an interface. These private methods will improve code re-usability inside interfaces. For example, if two default methods in some parts have repetitive codes, they should move this part into a private method.
public interface Interface05<T> {
    // Java 1 kinds of members
    // Java 2 kinds of members
    // Java 5 kinds of members
    // Java 8 kinds of members
    private int privateMethod(T var) {        
        // private method implementation
        return 0;
    private static void privateStaticMethod(double n1, double n2) {
        // private method implementation

Using private methods in interfaces have four rules :

  1. Private method cannot be abstract.
  2. Private method can be used only inside interface.
  3. Private static method can be used inside other static and non-static interface methods.
  4. Private non-static methods cannot be used inside private static methods.

Let's move to more concrete example below. Interface Number has private method isPrimeNumber() to check if a number is prime number or not. This interface also has a private static method print() to print a number following by space. You can see that every default method will rely to isPrimeNumber() private method to filter the number.
import java.util.function.IntPredicate;

public interface Number {
    default int sumPrimeNumbers(int... nums) {
        return sum(n -> isPrimeNumber(n), nums);
    default long countPrimeNumbers(int... nums) {
        return count(n -> isPrimeNumber(n), nums);
    default void printPrimeNumbers(int... nums) {
        print(n -> isPrimeNumber(n), nums);
    private boolean isPrimeNumber(int num) {
        boolean isPrime = true;
        for(int divisor = 2; divisor <= num / 2; divisor++) {
            if (num % divisor == 0) {
                isPrime = false;
                break; // num is not a prime, no reason to continue checking
        return isPrime;
    private int sum(IntPredicate predicate, int... nums) {
        return IntStream.of(nums).filter(predicate).sum();
    private long count(IntPredicate predicate, int... nums) {
        return IntStream.of(nums).filter(predicate).count();
    private void print(IntPredicate predicate, int... nums) {
        IntStream.of(nums).filter(predicate).forEach(x -> Number.print(x));
    private static void print(int n) {
        System.out.print(n + " ");
public class MainNumber implements Number {
    public static void main(String[] args) {
        int[] nums = {1,2,3,4,5,6,7,8,9,11,12,13,14,15,16,17,18,19,20};
        Number number = new MainNumber();
        long cntPrimeNumbers = number.countPrimeNumbers(nums);
        int sumPrimeNumbers = number.sumPrimeNumbers(nums);

1 2 3 5 7 11 13 17 19 


Overall, this is what Java interface since Java 9 have:

Java 1(public abstract) method
Java 2inner interfaces
inner classes
Java 8(public) default method
(public) static method
Java 9private method
private static method