Question

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?

Was it helpful?

Solution

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.

As everybody else has mentioned, you just mustn't care about how the library has implemented the functionality, to reduce coupling and increasing maintainability of the library.

If you, as a library client, can demonstrate that the implementation is performing badly for your use case, you can then contact the person in charge and discuss about the best path to follow (a new method for this case or just changing the implementation).

That said, your example reeks of premature optimization.

If the method is or can be critical, it might mention the implementation details in the documentation.

OTHER TIPS

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.

In OO programming, we want to encapsulate as much as possible the data. Hide as much as possible the actual implementation, abstracting the types as high as possible.

In this context, I would answer only return what is meaningful. Does it makes sense at all for the return value to be the concrete class? Aka in your example, ask yourself: will anyone use a LinkedList-specific method on the return value of foo?

  • If no, just use the higher-level Interface. It's much more flexible, and allows you to change the backend
  • If yes, ask yourself: can't I refactor my code to return the higher-level interface? :)

The more abstract is your code, the less changes your are required to do when changing a backend. It's as simple as that.

If, on the other hand, you end up casting the return values to the concrete class, well that's a strong sign that you should probably return instead the concrete class. Your users/teammates should not have to know about more or less implicit contracts: if you need to use the concrete methods, just return the concrete class, for clarity.

In a nutshell: code abstract, but explicitly :)

Without being able to justify it with reams of CS quotes (I'm self taught), I've always gone by the mantra of "Accept the least derived, return the most derived," when designing classes and it has stood me well over the years.

I guess that means in terms of interface versus concrete return is that if you are trying to reduce dependencies and/or decouple, returning the interface is generally more useful. However, if the concrete class implements more than that interface, it is usually more useful to the callers of your method to get the concrete class back (i.e. the "most derived") rather than aribtrarily restrict them to a subset of that returned object's functionality - unless you actually need to restrict them. Then again, you could also just increase the coverage of the interface. Needless restrictions like this I compare to thoughtless sealing of classes; you never know. Just to talk a bit about the former part of that mantra (for other readers), accepting the least derived also gives maximum flexibility for callers of your method.

-Oisin

In general, for a public facing interface such as APIs, returning the interface (such as List) over the concrete implementation (such as ArrayList) would be better.

The use of a ArrayList or LinkedList is an implementation detail of the library that should be considered for the most common use case of that library. And of course, internally, having private methods handing off LinkedLists wouldn't necessarily be a bad thing, if it provides facilities that would make the processing easier.

There is no reason that a concrete class shouldn't be used in the implementation, unless there is a good reason to believe that some other List class would be used later on. But then again, changing the implementation details shouldn't be as painful as long as the public facing portion is well-designed.

The library itself should be a black box to its consumers, so they don't really have to worry about what's going on internally. That also means that the library should be designed so that it is designed to be used in the way it is intended.

As a rule, I only pass back internal implementations if I am in some private, inner workings of a library, and even so only sparingly. For everything that is public and likely to be called from the outside of my module I use interfaces, and also the Factory pattern.

Using interfaces in such a way has proven to be a very reliable way to write reusable code.

The main question has been answered already and you should always use the interface. I however would just like to comment on

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.

If you are returning a data structure that you know has poor random access performance -- O(n) and typically a LOT of data -- there are other interfaces you should be specifying instead of List, like Iterable so that anyone using the library will be fully aware that only sequential access is available.

Picking the right type to return isn't just about interface versus concrete implementation, it is also about selecting the right interface.

It doesn't matter all that much whether an API method returns an interface or a concrete class; despite what everyone here says, you almost never change the implementiation class once the code is written.

What's far more important: always use minimum-scope interfaces for your method parameters! That way, clients have maximal freedom and can use classes your code doesn't even know about.

When an API method returns ArrayList, I have absolutely no qualms with that, but when it demands an ArrayList (or, all to common, Vector) parameter, I consider hunting down the programmer and hurting him, because it means that I can't use Arrays.asList(), Collections.singletonList() or Collections.EMPTY_LIST.

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.

You use interface to abstract away from the actual implementation. The interface is basically just a blueprint for what your implementation can do.

Interfaces are good design because they allow you to change implementation details without having to fear that any of its consumers are directly affected, as long as you implementation still does what your interface says it does.

To work with interfaces you would instantiate them like this:

IParser parser = new Parser();

Now IParser would be your interface, and Parser would be your implementation. Now when you work with the parser object from above, you will work against the interface (IParser), which in turn will work against your implementation (Parser).

That means that you can change the inner workings of Parser as much as you want, it will never affect code that works against your IParser parser interface.

In general use the interface in all cases if you have no need of the functionality of the concrete class. Note that for lists, Java has added a RandomAccess marker class primarily to distinguish a common case where an algorithm may need to know if get(i) is constant time or not.

For uses of code, Michael above is right that being as generic as possible in the method parameters is often even more important. This is especially true when testing such a method.

You'll find (or have found) that as you return interfaces, they permeate through your code. e.g. you return an interface from method A and you have to then pass an interface to method B.

What you're doing is programming by contract, albeit in a limited fashion.

This gives you enormous scope to change implementations under the covers (provided these new objects fulfill the existing contracts/expected behaviours).

Given all of this, you have benefits in terms of choosing your implementation, and how you can substitute behaviours (including testing - using mocking, for example). In case you hadn't guessed, I'm all in favour of this and try to reduce to (or introduce) interfaces wherever possible.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top