This week's book giveaway is in the OCAJP 8 forum. We're giving away four copies of OCA Java SE 8 Programmer I Study Guide and have Edward Finegan & Robert Liguori on-line! See this thread for details.
Since Java 1.2, I have seen the following naming convention used in the libraries.
An interface defines a type. Remember, a "type" is just a set of method signatures that can be called on a class. A class can implement more than one type.
Example: Executor An abstract class defines a skeletal version of a concrete class. It usually named Abstract<InterfaceName>:
Example: AbstractExecutor An uninstantiable class filled with static factory methods provides commonly useful concrete instances of the type. It usually named <InterfaceName>s (ends with an "s").
Example: Executors This frequently used naming pattern is consistent with the advice found in books like Joshua Bloch's "Effective Java": Prefer Interfaces to Abstract Classes to define a type.
However the Comparator group in Java 8 does not follow this pattern. There is no Comparators class, and all the static methods are instead placed into the Comparator interface? Are the days of using a pure interface to define a type over? If so, why didn't the designers of Java 8 continue new pattern with the Collector and Collectors? Are the static factories in the new Comparator different than those found in Collectors? Are they special in some way that makes it more appropriate to bundle them with the type definition?
Java's standard library contains thousands of classes and interfaces, and has grown bit by bit over the years. Many different engineers have worked on it, and there are many inconsistencies, and also a number of very badly designed APIs in there.
There was probably not a conscious decision made to follow a specific style in the Comparator interface that is different from other classes in the JDK.
If you go back to versions of Java before 8 you find the Comparator interface had two methods: compare and equals. And most people didn't bother implementing equals.
Joined: May 30, 2011
With the most sincere possible respect to both Campbell and Jesper, after some serious reflection on their responses, I don't feel like my question is resolved. This might mean I didn't ask my question clearly, which I will try to rectify with this posting.
"Many different engineers have worked on it, and there are many inconsistencies, and also a number of very badly designed APIs in there."
Sure sure. That is certainly true. No one is perfect. One of the reasons they added default functions to interfaces was for the very purpose of being able to update a broken interface and still maintain binary compatibility with older code that might be compiled against the new library.
"If you go back to versions of Java before 8 you find the Comparator interface had two methods: compare and equals. And most people didn't bother implementing equals."
Is your point that Comparator was largely undeveloped, and that in order to expand it we had to also include defaults for the new parts of the interface? I would certainly agree with that. But in my original post I was mostly concerned about the placement of the static factory functions into the interface. Rather I expected them to be in Comparators. Maybe the only reason that the <InterfaceName>s pattern developed was because programmers couldn't put them in the interfaces. But now the pattern seems well established. I would have expected a code review to have caught this, so I am expecting that there was a conscious decision to avoid the convention here.
So I will restate my question. Was there a good reason why the static factories in the Comparator interface should not have been placed in a separate class called Comparators? Is this a pattern I should follow or avoid in my own API's?
Derik Davenport wrote:Was there a good reason why the static factories in the Comparator interface should not have been placed in a separate class called Comparators? Is this a pattern I should follow or avoid in my own API's?
As with all questions concerning the design of the standard Java API, the answer is that unless an Oracle engineer happens to be browsing these forums you are not going to get a definite answer to your question. Everyone else here can only offer possible reasons for any design decisions that were made, but at the end of the day they will be guesses and your guess will be just as good as anyone elses.
Unless you are working in a company with a style guide that specifies this sort of thing, you should choose whatever suits you best and stick with it. You at least can be consistent even if the Java developers weren't.