Static factories for parameterized collections?

M

Mark Space

Joshua Bloch says to use generic methods to reduce redundant parameter
types when creating a new collection. For example:

// Effective Java, by Joshua Bloch
// #27. Favor Generic Methods
HashMap<String, List<String>> result =
NewCollection.makeNewHashMap();

Where

public class NewCollection {
public static <K,V> HashMap<K,V> makeNewHashMap()
{
return new HashMap<K,V>();
}
}

Does a library of these methods exist somewhere already?

I tried to post this question earlier, but it never showed up. Sorry if
it's a duplicate.
 
M

Mike Schilling

Mark said:
Joshua Bloch says to use generic methods to reduce redundant
parameter
types when creating a new collection. For example:

// Effective Java, by Joshua Bloch
// #27. Favor Generic Methods
HashMap<String, List<String>> result =
NewCollection.makeNewHashMap();

Where

public class NewCollection {
public static <K,V> HashMap<K,V> makeNewHashMap()
{
return new HashMap<K,V>();
}
}

And the compiler infers the correct type for K and V from the type of
"result"?

Yes, I understand that given erasure K and V don't really matter
anyway, so all the inference does is to eliminate the need for a
complicated cast that wouldn't generate any bytecode. Still, it's
evil.

Now, I see (by trying it) that

Object o = NewCollection.makeNewHashMap();

will also compile successfully; not even a warning. What is the logic
here, that V and K have some default value, or that they don't matter?
 
M

Mike Schilling

Mark said:
No. The compiler infers their correct types, and applies those
types
to the type of collection.

You snipped the example. Let me restore it:

Object o = NewCollection.makeNewHashMap();

Now, what can it infer K and V from?
 
M

Mark Space

Mike said:
You snipped the example. Let me restore it:

Object o = NewCollection.makeNewHashMap();

Now, what can it infer K and V from?


Oh, I think I see what you are getting at.

I'd guess, with out looking it up, that the type of K and V are the same
as a new HashMap with out specifying a parameterized type. I.e., it's a
raw type.

Object o = new HashMap();

Same, no? What's the type K and V from the Java API of "public class
HashMap<K,V>" when you don't parameterize them, as above? There is
none, it's not inferred and there is no default. If you try to use this
object:

HashMap m = (HashMap)o;
m.put( "Test", "test1" );

This results in unchecked warnings, which is always the case with raw types.


Compiling 6 source files to C:\Users\Dev\misc\fubar\build\classes
C:\Users\Dev\misc\fubar\src\fubar\Fubar.java:131: warning: [unchecked]
unchecked call to put(K,V) as a member of the raw type java.util.HashMap
m.put( "Test", "test1" );
 
M

Mark Space

Mark said:
Joshua Bloch says to use generic methods to reduce redundant parameter
types when creating a new collection.
Does a library of these methods exist somewhere already?

Well, I haven't heard that there is, so I'll supply one. It's rather
too big to publish here, so I used Google docs:

http://docs.google.com/Doc?id=ddgtkqjv_3c4gx9d2w

Comments and criticisms welcome. This class supplies factories for
nearly all Collections and Maps, and for each constructor too. Google
doesn't do .jar (or .zip) files, so I'm looking storage space. It might
be time to break down and get a simple website for myself.

(And Google Docs doesn't do .java files either, so you'll have to remove
the .txt at the end of the file name.)
 
J

John B. Matthews

Mark Space said:
Joshua Bloch says to use generic methods to reduce redundant
parameter types when creating a new collection. [...] Does a library
of these methods exist somewhere already?

I tried a few favorites, just to see what they would look like. Pretty
stereotypical. Interestingly, EnumSet is already an exemplary factory. A
complete set would probably be unwieldy, but the ones "in use" might be
an attractive re-factoring.

public class CollectionFactory {

public static <E> ArrayList<E> newArrayList() {
return new ArrayList<E>();
}

public static <K, V> HashMap<K, V> newHashMap() {
return new HashMap<K, V>();
}

public static <E> HashSet<E> newHashSet() {
return new HashSet<E>();
}

public static <E> LinkedHashSet<E> newLinkedHashSet() {
return new LinkedHashSet<E>();
}

public static <E> LinkedList<E> newLinkedList() {
return new LinkedList<E>();
}

public static <E> TreeSet<E> newTreeSet() {
return new TreeSet<E>();
}
}
 
J

John B. Matthews

Mark Space said:
Well, I haven't heard that there is, so I'll supply one. It's rather
too big to publish here, so I used Google docs:

http://docs.google.com/Doc?id=ddgtkqjv_3c4gx9d2w

Comments and criticisms welcome. This class supplies factories for
nearly all Collections and Maps, and for each constructor too. Google
doesn't do .jar (or .zip) files, so I'm looking storage space. It might
be time to break down and get a simple website for myself.

(And Google Docs doesn't do .java files either, so you'll have to remove
the .txt at the end of the file name.)

Google sites <http://sites.google.com/> handles attached files nicely
(including JARs and ZIPs), but the redirection spoils JWS.
 
M

Mark Space

Lew said:
It's hard to trust a site that can't even spell Joshua Bloch's last name
correctly, nor the word "collections".


Yeah, that kind of sucked. My eye tends to read what I intended to
write, not what I actually wrote. I have a devil of a time proofreading
my own writing.

New location:

<http://www.techdarwinia.com/newcollection>

I'll delete the old link in a few days... hide my shame...
 
L

Lew

Mark said:
Yeah, that kind of sucked. My eye tends to read what I intended to
write, not what I actually wrote. I have a devil of a time proofreading
my own writing.

New location:

<http://www.techdarwinia.com/newcollection>

I'll delete the old link in a few days... hide my shame...

I apologize for being a bit harsh, as my reread of my post indicates I may've
been. I'm just a bit sensitive about the spelling of "Bloch" after years of
correcting people. Henry and Richard Bloch apparently just gave up and
intentionally misspelled their last name as the name of their tax-preparation
business.

Rest assured that I do have confidence in your suggestions and code after all
this time reading your Usenet posts.
 
M

Mark Space

Lew said:
I apologize for being a bit harsh, as my reread of my post indicates I
may've been.


No worries. I'm hoping that more people than just those from this
newsgroup will use that site and find the code useful. So I think
presentation counts, including spelling.
 
L

Lew

Re:
<http://www.techdarwinia.com/newcollection>

Mark said:
I'm hoping that more people than just those from this
newsgroup will use that site and find the code useful. So I think
presentation counts, including spelling.

The suggestion to use 'import static' has a typo:
import static local.collectionutils.NewCollection.LinkedList;

That should be:
import static local.collectionutils.NewCollection.newLinkedList;

Handy little class, though personally I prefer the repetition of the generic
type in the constructor and regard cover methods for the constructors to be
rather silly. One trades the putative inconvenience of repetition of type
parameters for that of an additional dependency.

I commend you for the fullness of your doc comments, but I have a nit about
those, too. For example:

/** Creates a new LinkedList.
*
* @param collection Passed to LinkedList(Collection) constructor.
* @return A newly created LinkedList;
*/
public static <T> LinkedList<T> newLinkedList(
Collection<? extends T> collection )
{
return new LinkedList<T>( collection );
}

I was taught to include types in the @param and @return tags, thus (modulo
extra line wraps added for Usenet readability):

/** Creates a new <code>LinkedList</code>.
*
* @param collection <code>Collection &lt; ? extends T &gt;</code>
* passed to the <code>LinkedList(Collection)</code> constructor.
* @return LinkedList &lt; T &gt; A newly created LinkedList.
*/
By convention, the first noun in the description [of an @param]
is the data type of the parameter.
<http://java.sun.com/j2se/javadoc/writingdoccomments/index.html#@param>

I note, however, that I learned it differently from Sun's recommendation:
The data type starts with a lowercase letter
to indicate an object rather than a class.

which would make the above @param look like this:

* @param collection the collection passed to the
* <code>LinkedList(Collection)</code> constructor.

I'm switching.

As for the character entities &lt; and &gt;, since Javadoc
[c]omments are written in HTML - The text must be written in HTML,
in that they [sic] should use HTML entities and can use HTML tags ...
entities for the less-than (<) and greater-than (>) symbols
should be written &lt; and &gt;
<http://java.sun.com/javase/6/docs/technotes/tools/solaris/javadoc.html#comments>

I see no way around it, however:
Example of a type parameter of a method:
/**
* @param string the string to be converted
* @param type the type to convert the string to
* @param <T> the type of the element
* @param <V> the value of the element
*/
<T, V extends T> V convert(String string, Class<T> type) {
} <http://java.sun.com/javase/6/docs/technotes/tools/solaris/javadoc.html#@param>

because

Do not bracket the name of the parameter after the @param tag
with <code>...</code> since Javadoc 1.2 and later automatically do this.
(Beginning with 1.4, the name cannot contain any HTML, as Javadoc
compares the @param name to the name that appears in the signature and
emits a warning if there is any difference.)
<http://java.sun.com/j2se/javadoc/writingdoccomments/index.html#@param>
 
T

Tom Anderson

Handy little class, though personally I prefer the repetition of the
generic type in the constructor and regard cover methods for the
constructors to be rather silly. One trades the putative inconvenience
of repetition of type parameters for that of an additional dependency.

I guess this is mostly a matter of taste. Like you, i'll be sticking with
explicit declarations; it's usually no more than a matter of control-1 in
Eclipse anyway.
I commend you for the fullness of your doc comments, but I have a nit
about those, too. For example:

/** Creates a new LinkedList.
*
* @param collection Passed to LinkedList(Collection) constructor.
* @return A newly created LinkedList;
*/
public static <T> LinkedList<T> newLinkedList(
Collection<? extends T> collection )
{
return new LinkedList<T>( collection );
}

I was taught to include types in the @param and @return tags, thus (modulo
extra line wraps added for Usenet readability):

/** Creates a new <code>LinkedList</code>.
*
* @param collection <code>Collection &lt; ? extends T &gt;</code>
* passed to the <code>LinkedList(Collection)</code> constructor.
* @return LinkedList &lt; T &gt; A newly created LinkedList.
*/

Huh. I've never come across that idea. Given that the types are included
in the actual parameter declaration, it seems redundant to include them in
the comments too. Often, the name of the type will be useful in
constructing the description (List<Product> productsToAdd gets "@param
products the list of products to add to the cart"), but sometimes it won't
(String customerName gets "@param name the customer's name").

Since we're picking nits in Mark's sterling code, my gripe about the above
quote would be the way the parameter is described: "Passed to
LinkedList(Collection) constructor.". This is true, but not immediately
helpful - you can't determine what that actually means without referring
to the comment for that constructor. In practice, of course, everyone
knows what that means, so it does the job, but in principle, i think it'd
be better to say something like "the collection whose elements are to be
placed into this list", which is a copy-and-paste from the param comment
for the constructor.

The style of commentary employed by Mark becomes particularly enraging
when used in a big complex system with complex layered interactions, where
you end up with comments like "the value used to initialise the
ParameterBlock which is passed to the ServiceInitiator", when it could say
something like "the name of the service to start". Mark isn't committing
that sin here, of course.
By convention, the first noun in the description [of an @param] is the data
type of the parameter.
<http://java.sun.com/j2se/javadoc/writingdoccomments/index.html#@param>

I note, however, that I learned it differently from Sun's recommendation:
The data type starts with a lowercase letter to indicate an object rather
than a class.

which would make the above @param look like this:

* @param collection the collection passed to the
* <code>LinkedList(Collection)</code> constructor.

I'm switching.

I do think that's slightly more readable.

Other weirdness in Sun's coding conventions:

http://java.sun.com/docs/codeconv/html/CodeConventions.doc7.html

Sayeth:

One blank line should always be used [...] between the local variables in
a method and its first statement

Which is kind of nutty. This sounds to me like it was written by an ex-C
programmer who still thinks the way you write methods is to declare all
the variables at the top, and then get onto the code, which i would
consider incredibly poor style.

tom
 
M

Mark Space

Lew said:
The suggestion to use 'import static' has a typo:


Oops, thanks.

I was taught to include types in the @param and @return tags, thus
(modulo extra line wraps added for Usenet readability):


I notice however that Sun itself doesn't always do this. Just randomly
I checked the docs for the Pattern class. They almost always refer to
Strings as "the pattern", no "String" or "string" anywhere in the @param
comment. Similarly for int, which is often referred to as "the limit"
when it specifies a maximum offset for a search, or once as a "mask"
when it specifies option flags. There's no use of "int" or "integer"
anywhere in many of those @param comments.

I think the rule to use types in a @param comment is a good general one,
but should be modified when clarity demands otherwise.

/** Creates a new <code>LinkedList</code>.


Also I checked out Joshua Bloch's Java doc comments in Effective Java, I
notice <code> and <tt> are both obsolete and the {@code} tag is now
preferred. I'll have to change that in my own code.



The {@code} automatically quotes <, > and &, which is perhaps what they
are referring to. Bloch gives an example like:

where {@code (t < end && t >= start)}

Not only is this reproduced in the appropriate font style, but the < and
& are quoted properly in the HTML. The result is a lot more readable in
the comment and still correct in the resulting Java doc.

So I would assume that the parameter after @param is wrapped in a
@{code} tag. E.g.: {@code <V>}.

There's also a {@literal} tag with does the same thing (quote special
HTML characters) when you don't need the code font style.

However, <pre> tags are still needed around multi-line code snippets.

<pre>{@code int i = 0;
String s = "Bloch";
//...
}</pre>

Etc.
 
M

Mark Space

Tom said:
above quote would be the way the parameter is described: "Passed to
LinkedList(Collection) constructor.". This is true, but not immediately
helpful - you can't determine what that actually means without referring
to the comment for that constructor. In practice, of course, everyone
knows what that means, so it does the job, but in principle, i think
it'd be better to say something like "the collection whose elements are
to be placed into this list", which is a copy-and-paste from the param
comment for the constructor.


I fretted over that myself as well. On one hand, I didn't want to
duplicate the comments from the various constructors. They might have
preconditions or postconditions which could conceivably change over time.

On the other hand, rereading Effective Java, Joshua Bloch says to
document what is done, not how it is done. And "passing this to another
constructor" is surely documenting how I create each new collection.

I think I should modify these comments, and document what I think I'm
doing, rather than worry over much about how the public API of the
various underlying constructors might change. Maybe I'll add a link to
the constructor I use, for convenience.

http://java.sun.com/docs/codeconv/html/CodeConventions.doc7.html

Sayeth:

One blank line should always be used [...] between the local variables in
a method and its first statement

Which is kind of nutty. This sounds to me like it was written by an ex-C
programmer who still thinks the way you write methods is to declare all
the variables at the top, and then get onto the code, which i would
consider incredibly poor style.


I just use the style where braces for classes go on a new line, in the
leftmost column. It's more readable, and automatically gives a (mostly)
blank line in between the method declaration and its first statement.
 
L

Lew

Mark said:
So I would assume that the parameter after @param is wrapped in a
@{code} tag. E.g.: {@code <V>}.

I don't think so. As I read the Javadoc docs, you need to leave the parameter
name part alone. I will have to experiment with this.
 
M

Mark Space

Lew said:
I don't think so. As I read the Javadoc docs, you need to leave the
parameter name part alone. I will have to experiment with this.


I meant "effectively wrapped by the javadoc compiler in a {@code}" not
that one should actually go around putting {@code} tags around the
parameter. The article you cited was pretty clear that parameters after
a @param should be plain text. Unless you're referring to something
else....
 
T

Tom Anderson

I fretted over that myself as well. On one hand, I didn't want to
duplicate the comments from the various constructors. They might have
preconditions or postconditions which could conceivably change over
time.

On the other hand, rereading Effective Java, Joshua Bloch says to
document what is done, not how it is done. And "passing this to another
constructor" is surely documenting how I create each new collection.

I think I should modify these comments, and document what I think I'm
doing, rather than worry over much about how the public API of the
various underlying constructors might change. Maybe I'll add a link to
the constructor I use, for convenience.

Links are always good.

But my personal preference would be to delete the comments altogether, and
let the method names stand for themselves. :)
http://java.sun.com/docs/codeconv/html/CodeConventions.doc7.html

Sayeth:

One blank line should always be used [...] between the local variables in
a method and its first statement

Which is kind of nutty. This sounds to me like it was written by an ex-C
programmer who still thinks the way you write methods is to declare all the
variables at the top, and then get onto the code, which i would consider
incredibly poor style.

I just use the style where braces for classes go on a new line, in the
leftmost column. It's more readable, and automatically gives a (mostly)
blank line in between the method declaration and its first statement.

I read the quote above as being about local variable declarations, rather
than the method declaration. So:

public int foo(int x) {
int a;

a = frobnicate(x);
return a + x;
}

That's what seems mad and C-like to me. Perhaps i was misinterpreting it.

tom
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
474,432
Messages
2,571,680
Members
48,796
Latest member
Greg L.

Latest Threads

Top