Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

When should I return the Interface and when the concrete class?

when programming in Java I practically always, just out of habit, write something like this:

public List<String> foo() {
    return new ArrayList<String>();
}

Most of the time without even thinking about it. Now, the question is: should I always specify the interface as the return type? Or is it advisable to use the actual implementation of the interface, and if so, under what circumstances?

It is obvious that using the interface has a lot of advantages (that's why it's there). In most cases it doesn't really matter what concrete implementation is used by a library function. But maybe there are cases where it does matter. For instance, if I know that I will primarily access the data in the list randomly, a LinkedList would be bad. But if my library function only returns the interface, I simply don't know. To be on the safe side I might even need to copy the list explicitly over to an ArrayList:

List bar = foo();
List myList = bar instanceof LinkedList ? new ArrayList(bar) : bar;

but that just seems horrible and my coworkers would probably lynch me in the cafeteria. And rightfully so.

What do you guys think? What are your guidelines, when do you tend towards the abstract solution, and when do you reveal details of your implementation for potential performance gains?

like image 651
n3rd Avatar asked Sep 05 '25 03:09

n3rd


2 Answers

Return the appropriate interface to hide implementation details. Your clients should only care about what your object offers, not how you implemented it. If you start with a private ArrayList, and decide later on that something else (e.g., LinkedLisk, skip list, etc.) is more appropriate you can change the implementation without affecting clients if you return the interface. The moment you return a concrete type the opportunity is lost.

like image 73
duffymo Avatar answered Sep 08 '25 00:09

duffymo


Sorry to disagree, but I think the basic rule is as follows:

  • For input arguments use the most generic.
  • For output values, the most specific.

So, in this case you want to declare the implementation as:

public ArrayList<String> foo() {
  return new ArrayList<String>();
}

Rationale: The input case is already known and explained by everyone: use the interface, period. However, the output case can look counter-intuitive. You want to return the implementation because you want the client to have the most information about what is receiving. In this case, more knowledge is more power.

Example 1: the client wants to get the 5th element:

  • return Collection: must iterate until 5th element vs return List:
  • return List: list.get(4)

Example 2: the client wants to remove the 5th element:

  • return List: must create a new list without the specified element (list.remove() is optional).
  • return ArrayList: arrayList.remove(4)

So it's a big truth that using interfaces is great because it promotes reusability, reduces coupling, improves maintainability and makes people happy ... but only when used as input.

So, again, the rule can be stated as:

  • Be flexible for what you offer.
  • Be informative with what you deliver.

So, next time, please return the implementation.

like image 38
user3830747 Avatar answered Sep 08 '25 00:09

user3830747