views:

134

answers:

5

For all the methods in Collections that take a List as their first argument, why aren't those methods simply part of the List interface?

My intuition is: given a List object, that object itself should "know" how to perform on itself operations such as rotate(), shuffle(), or reverse(). But instead, as a Java programmer, I have to review both the methods in the List interface, as well as the static methods "over there" in the Collections class, to ensure I'm using a canonical solution.

Why were some methods placed as static standalone methods in the Collections class, instead of being added to the List interface (and presumably thus implemented by some existing or would-be base class)?

I'm trying to better understand the design decisions behind the Java collections framework.

Is there some compelling OO design principle here that I'm overlooking? Or was this distinction done simply for some practical, performance reason?

+2  A: 

They are utility methods and not core List functionality. The List interface would just get bloated if you added every possible operation you could do on a List. And the operations in Collections do not need to know about the internals of a List, they operate on the public interface so can happily live in an external class.

objects
Is there any specific principle behind what's "utility" and what's "core"? Or is the current design simply someone's best judgment?
Aaron F.
core are basically the minimum set of operations you need for a List, eg. add an element, remove an element. Utility methods operate more on the List itself without needing to know the internals.
objects
@Aaron F, the implementation for "shuffle" or "random" is same regardless of the implementation of the List. Whether your List is backed by an array or a linked list, "shuffle" or "random" is the same.
matt b
+5  A: 

The point is that given suitable primitive operations (remove, set etc) a bunch of more high level operations (sort, shuffle, binary search) can be implemented once rather than being implemented by every single list implementation.

Effectively, java.util.Collections is like .NET's Enumerable class - full of general purpose methods which can work on any collection, so that they can share a single implementation and avoid duplication.

Jon Skeet
you could still implement them in a base class such as AbstractList instead of in every List implementation.Am not saying you'd want to, just that it would avoid implementing them in every List implementation
objects
@objects - but then when I implement the List interface myself but I *don't* extend AbstractList (because maybe I'm extending something else in my problem domain) I'll have to write my own sort(), shuffle(), etc. implementations.
Stephen P
Thats true, was just making the point that its not forced to be implemented in every list implementation. Operation that don't rely on the internals are typically better off in a seperate class as I mention in my answer.
objects
+4  A: 

Rational Behind the List Interface's Methods

  1. The List interface is a very core part of the Java runtime and is already a little onerous to fully implement all of the members when rolling out your own List implementations. So, adding extra methods that aren't directly related to the definition of a list is a bit extraneous. If you need those methods on a List implementation, why not subclass the interface and then require them?
  2. If you where going to come along say in version 1.3 and add functionality to the List interface by adding new utility methods, you will break all past implementors of the interface.
  3. From a Domain-Driven Design perspective, the utility methods in Collections are not part of the normal domain of a list.
  4. Regarding OO design principals, I think it would be important to make the distinction between application OO design and language runtime OO design.

The authors of Java may do things very differently now that they have hindsight and perspective of many years of usage of the API. That said the C# IList interface is quite similar to Java's and C#'s authors did have the perspective.

Elijah
+2  A: 

There are two explanations here:

  1. Historical: Collections class was created after List interface. Designers chose to preserve backward compatibility of already existing interface. Otherwise a lot of developers would have to change their code.

  2. Logical: The methods you are talking about do not require internal knowledge on List implementation and can be implemented over ANY collection implementing it.

eugener
#2 is not quite correct. There are methods in Collection whose arguments specifically call for a List and only a List. e.g. http://java.sun.com/javase/6/docs/api/java/util/Collections.html#sort%28java.util.List%29
Aaron F.
@Aaron F, that is not what eugener is referring to here. What he means is that regardless of how the list is implemented (the "internal knowledge") the algorithm for sorting or shuffling is the same.
matt b
+3  A: 

It's certainly a judgement call at some level. I think the main trade-off to consider is this: When you add a method to an interface, every implementer of that interface must write code to implement it.

If the semantics of that method are such that different implementations of the interface will best implement those semantics in very different ways, then it's better to put it in the interface. (Of course, if the semantics simply can't be defined in terms of other methods in the interface, then it must be its own method in the interface.)

On the other hand, if the semantics are such that they can be defined in terms of other methods in the interface, and implementers of the interface will just tend to write the same code over and over again, then it's better to make a utility method that takes an instance of the interface as an argument.

Matt McHenry