Not just HashMap:
"java.util.GregorianCalendar, java.util.Hashtable, java.util.HashSet,
java.util.HashMap, java.util.ArrayList, java.util.LinkedList,
java.util.LinkedHashMap, java.util.LinkedHashSet, java.util.TreeSet,
java.util.TreeMap, java.util.Vector"
I suppose the check is pushing me to pass/return custom data objects
that implement Java-specific data structures behind the scenes? I
can't see how you would write meaningful code without eventually using
one of the listed data structures, but I can see vaguely how it would
be beneficial to wrapper the implementation of these data structures.
I think you may be reading too much into what Checkstyle is telling you.
Forgetting about Checkstyle for the moment, there are at least three different
aspects to "good" code that you touch on here. I think it would help to
separate them out from each other.
One is that when you use, say, a HashMap in some private bit of code, how do
you declare the variable that holds the reference. Do you write:
Map map = new HashMap();
or:
HashMap map = new HashMap();
The most popular school of thought is that the first form is to be preferred,
but there are dissenting opinions too. My own opinion is that it doesn't make
much difference in this case, since -- by hypothesis -- we are talking about
private code. If the scope of the variable is restricted, then so is the
"damage" that can possibly be caused by declaring it too narrowly. In short it
doesn't lead to hard-to-manage coupling or brittle code since nothing much can
depend on it.
The second is to ask the same question about externally visible fields and
APIs. For instance the return type of a public or protected method. In /this/
case I think the standard answer is completely correct, and that -- unless you
have some special requirement -- the declared type should be as general as
possible (ideally an interface).
The last issue is the use of "bare" collections in APIs at all. Is it "good"
to export an API which takes a List<MyObject>, or which returns a Map(String,
MyOtherObject>) ? My answer is that its not intrinsically wrong, and is quite
often exactly the right thing to do, but that you should stop and think
whenever you find yourself doing it. If you find yourself doing it much, or if
you find yourself expressing complicated structures as collections (in the
API), then you have quite probably gone too far, and have something of a code
mess, where the responsibility for managing and interpreting a particular raw
structure is scattered all over the code-base, rather than nicely centralised.
For instance, I wouldn't blink at:
List<MyObject>someMethod()
I would feel mildly uneasy about
Map<String, MyObject>someMethod()
and if I came across
List<List<MyObject>>
then my alarm bells would be going off like sky-rockets.
Coming back to Checkstyle. I don't know whether it distinguishes between my
first and second issues, but I think it is trying to warn you about one or the
other. I don't see an easy way that a tool like Checkstyle could provide much
help with the third issue since the cut-off between valid uses of raw
collections, and culpable failure to create a true object, is not easy to
recognise without a true understanding of the code. I suppose some sort of
heuristic could be defined, but I'd not expect it to be much use.
-- chris