I think it's helpful to pay attention to who exactly needs to use these constants. Bloch's arguments apply to classes that use constants
internally. They don't really apply to classes that intentionally make those constants available to clients, as part of their own APIs.
For example, consider
WindowConstants. The three classes that implement this are
JDialog,
JFrame, and
JInternalFrame. They all have some common behavior, setDefaultCloseOperation(). This method really should have been defined in the same interface - let's call it ClosableWindow:
Here the constants are intended to be used by clients of JDialog, JFrame, and JInternalFrame - and it makes perfect sense for those clients to see the constants as part of the API. However it would
not make sense for those clients to implement this interface just so they can
use the constants. If my class JimsTetrisGame uses a JFrame, that's fine. But people who use my class don't need to read about DISPOSE_ON_CLOSE etc, because it's not something
they need to call in code in order to use my class. So I shouldn't implement WindowConstants or ClosableWindow just to make my life a tiny bit easier inside the JimsTetrisGame class, because that would unnecessarily affect the public API of my class.
Here we see that defining the method setDefaultCloseOperation() inside ClosableWindow is helpful. Because If I'm writing JimsTetrisGame and I want to implement WindowConstants just for my own convenience, nothing's stopping me. (Other than the fact I am aware this is an antipattern.) But with ClosableWindow, it's different, because I can't implement that without implementing the method setDefaultClosableOperation(). And when I start to do that, I realize that this method isn't something that
clients of my class need - therefore it shouldn't be part of my public API.
Note that Bloch doesn't say you should
never put constants in interfaces. He recommends against defining interfaces
just to make internally-used constants more accessible. But if the constants are intentionally
part of the API, and if the interface also defines one or more methods that
use those constants, that's a different story, much more justifiable.
Note that for most of the examples I can think of, it would be preferable to use an enum to define the list of values that are used by a method. Or prior to JDK 5, you could use the type-safe enumeration
pattern. But this wasn't known - at least, not
widely known - at the time many standard library classes were designed. A more modern version of ClosableWindow would be:
I suspect that for many of the examples Tom's co-worker is thinking of, putting constants in interfaces is similarly justifiable - clients
do need to use them. Together with methods that take those constants as parameters. And since enums are not available (JDK 1.4), the type-safe enumeration pattern is worth considering.
[ June 21, 2007: Message edited by: Jim Yingst ]