More generics hacks
Monday, December 03rd, 2007Continuing on the generics discussion here, I’ve been using a pattern that I’ve seen discussed in the blogosphere to reduce redundancy in creating collections, e.g. some utility methods on a
CollectionUtils
class:
public static <T> ArrayList<T> newArrayList() { return new ArrayList<T>(); } public static <T> HashSet<T> newHashSet() { return new HashSet<T>(); } public static <K, V> HashMap<K, V> newHashMap() { return new HashMap<K, V>(); }
This eliminates the redundancy of specifying the type(s) twice:
List<VerboseTypeName> list = new ArrayList<VerboseTypeName>(); Map<VerboseKeyName, VerboseValueName> map = new HashMap<VerboseKeyName, VerboseValueName>();
becomes
List<VerboseTypeName> list = newArrayList(); Map<VerboseKeyName, VerboseValueName> map = newHashMap();
assuming we use static imports for the utility methods.
But Groovy and other scripting languages are making me realize how unnecessarily verbose Java is. For example, in Groovy I can create a
List
and initialize its elements in one line:
def numbers = [1, 1, 2, 3, 5, 8, 13, 21];
I recently realized that I can use VarArgs and amend the utility methods to take optional initializing values:
public static <T> ArrayList<T> newArrayList(final T... elements) { return new ArrayList<T>(Arrays.asList(elements)); } public static <T> HashSet<T> newHashSet(final T... elements) { return new HashSet<T>(Arrays.asList(elements)); }
and then
List<String> strings = new ArrayList<String>(); strings.add("foo"); strings.add("bar"); strings.add("baz");
becomes
List<String> strings = newArrayList("foo", "bar", "baz");
Of course this isn’t new – for example Hibernate Shards has a similar implementation but with the various methods split by interface.