How do you use your interface’s private methods?

I’m having trouble using a private method I had implemented within my interface.

I implemented a print(string, list) method privately in my RequestData interface, to hide implementation as I don’t want it to be called except by the class’ other print methods – but I included it in the interface because it’s going to be the same with each implementing class.

Problem is, when I try to use the print method from my FundingRequests, which implements the RequestData interface, it shows the error – the print method’s access in the RequestData interface is private, so it can’t be found.

Well… how are you supposed to use an interface’s private methods if they are not accessible from within the implementing classes?

Is this a bug, or am I misunderstanding Interfaces?

Interface:

package com.landbay.datamodel.data;

import java.util.List;

public interface RequestData<E> {

    void add(E newRequest);

    List<E> getRequests();

    List<E> getFulfilledRequests();

    List<E> getUnfulfilledRequests();

    void printRequests();

    void printFulfilledRequests();

    void printUnfulfilledRequests();

    private void print(String listTitle, List<E> listToPrint) {
        StringBuilder string = new StringBuilder();
        string.append(listTitle);

        for (E request : listToPrint) {
            string.append("n").append(request);
        }

        System.out.println(string);
    }

}

Offending class & methods:

public class FundingRequests implements RequestData<FundingRequest> {
        private TreeSet<FundingRequest> requests;

        FundingRequests() {
            this.requests = new TreeSet<>();
        }

        ...

        @Override
        public void printRequests() {
            print("",new ArrayList<>(requests));
        }

}

Answer

Private methods were provided as a feature to Java interfaces to help write default methods in interfaces without re-using code. They were not intended to be used for implementation inheritance.

If you want to inherit and use implemented methods, such as what you attempted here:

@Override
public void printRequests() {
    print("",new ArrayList<>(requests));
}

you want to either implement the method in a super class and extend that class, or implement the method as a default method in an interface. Using a super class would be the more conventional way to do this.

Using the code you provided, you could do something like this:

class Printer {

    protected void print(String listTitle, List<E> listToPrint) {
        StringBuilder string = new StringBuilder();
        string.append(listTitle);

        for (E request : listToPrint) {
            string.append("n").append(request);
        }
}

then extend that class:

public class FundingRequests extends Printer implements RequestData<FundingRequest> {
        private TreeSet<FundingRequest> requests;

        FundingRequests() {
            this.requests = new TreeSet<>();
        }

        ...

        @Override
        public void printRequests() {
            print("",new ArrayList<>(requests));
        }

}

although that would limit your class to only extending that class. The better pattern would be to implement that method as a public static method in a class, then use it, like this:

class Printer {

    public static void print(String listTitle, List<E> listToPrint) {
        StringBuilder string = new StringBuilder();
        string.append(listTitle);

        for (E request : listToPrint) {
            string.append("n").append(request);
        }
    }
}

then use the method:

public class FundingRequests implements RequestData<FundingRequest> {
    private TreeSet<FundingRequest> requests;

    FundingRequests() {
        this.requests = new TreeSet<>();
    }

    ...

    @Override
    public void printRequests() {
        Printer.print("",new ArrayList<>(requests));
    }
}

or, if you really want to go crazy, you can pull this off with an abstract class:

abstract class RequestData<E> {

    abstract void add(E newRequest);

    abstract List<E> getRequests();

    abstract List<E> getFulfilledRequests();

    abstract List<E> getUnfulfilledRequests();

    abstract void printRequests();

    abstract void printFulfilledRequests();

    abstract void printUnfulfilledRequests();

    protected void print(String listTitle, List<E> listToPrint) {
        StringBuilder string = new StringBuilder();
        string.append(listTitle);

        for (E request : listToPrint) {
            string.append("n").append(request);
        }

        System.out.println(string);
    }

}

then extend that class:

public class FundingRequests extends RequestData<FundingRequest> {
        private TreeSet<FundingRequest> requests;

        FundingRequests() {
            this.requests = new TreeSet<>();
        }

        // implement the abstract methods

        @Override
        public void printRequests() {
            print("",new ArrayList<>(requests));
        }

}

Leave a Reply

Your email address will not be published. Required fields are marked *