Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Java: Generics syntax

Tags:

java

generics

This works to return a list of ints:

public List<Integer> GetIListImpl() {
    return new ArrayList<Integer>();
}

But what if I want to let the caller specify the generic type? Something like this, although syntactically I'm not sure how to do it:

public List<T> GetIListImpl<T>() {
    return new ArrayList<T>();
}

The usage would be:

    List<String> = GetIListImpl<String>();
like image 472
Nick Heiner Avatar asked Aug 22 '10 15:08

Nick Heiner


People also ask

What is generic syntax?

The syntax for a generic method includes a list of type parameters, inside angle brackets, which appears before the method's return type. For static generic methods, the type parameter section must appear before the method's return type.

How do you write a generic method in Java?

Example: Create a Generics Method Here, the type parameter <T> is inserted after the modifier public and before the return type void . We can call the generics method by placing the actual type <String> and <Integer> inside the bracket before the method name. demo. <String>genericMethod("Java Programming"); demo.

What is generics in Java with example?

Generics add that type of safety feature. We will discuss that type of safety feature in later examples. Generics in Java are similar to templates in C++. For example, classes like HashSet, ArrayList, HashMap, etc., use generics very well.

How do you pass a generic Object in Java?

We use generics wildcard (?) with super keyword and lower bound class to achieve this. We can pass lower bound or any supertype of lower bound as an argument, in this case, java compiler allows to add lower bound object types to the list.


1 Answers

On generic static factory methods for parameterized types

It looks like you want to write convenient factory methods to instantiate generic collections.

You can write generic methods like these:

public static <T> List<T> newArrayList() {
    return new ArrayList<T>();
}
public static <K,V> Map<K,V> newHashMap() {
    return new HashMap<K,V>();
}

Then you can simply write:

// absolutely type-safe!!! no compilation warnings at all!!!

List<String> names = newArrayList();

List<Integer> nums = newArrayList();

Map<String, List<String>> map = newHashMap();

Note that in some contexts, the above methods do not have to be static, and you may opt to leave out the implementation class names out of the methods and only use the interface names (e.g. newList, newMap).


An endorsement from Effective Java 2nd Edition

This kind of generic type-inferring static factory method is actually endorsed by Effective Java 2nd Edition; it had the unique privilege of being the very first item discussed in the book.

Here are the relevant quotes from Item 1: Consider static factory methods instead of constructors:

A fourth advantage of static factory methods is that they reduce the verbosity of creating parameterized type instances.

When you invoke the constructor of a parameterized class, unfortunately you must specify the type parameters even if they're obvious from context. This typically requires you to provide the type parameters twice in quick succession:

    Map<String,List<String>> m = 
        new HashMap<String,List<String>>();

This redundant specification quickly becomes painful as the length and complexity of the type parameters increase. With static factories, however, the compiler can figure out the type parameters for you. This is known as type inference. For example, suppose that HashMap provided this static factory:

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

Then you could replace the wordy declaration above with this succinct alternative:

    Map<String,List<String>> m = HashMap.newInstance();

Unfortunately the standard collection implementations such as HashMap do not have static factory methods as of release 1.6, but you can put these methods in your own utility class. More importantly you can provide such static factories in your own parameterized classes.

The item also prescribes the common naming convention for these static factory methods:

  • getInstance - returns an instance that is described by the parameters […]
  • newInstance - Like getInstance, except it guarantees that each instance returned is distinct from all others.
  • newType - Like newInstance, but used when the factory method is in a different class. Type indicates the type of object returned by the factory method.

On explicit type parameters

You do not have to explicitly provide the type parameters in most cases, since the Java generics type inference system can usually figure out what you need.

Nevertheless, to provide explicit type parameters, the syntax is to put it before the method name (not after). Here's an example of invoking with explicit parameter the generic method <T> List<T> emptyList() from java.util.Collections:

Collections.<String>emptyList();
// Collections.emptyList<String>(); // DOES NOT COMPILE

Note that a syntax quirk of the explicit type parameterization for generic method invocation is that you must qualify the type (if static) or the object that you're invoking the method on, even if they can be omitted if it was not an explicit parameterization.


References

  • Angelika Langer's Java Generics FAQS
    • What is a generic method?
    • What is type argument inference?
    • What is explicit type argument specification?
  • JLS 8.4.4 Generic Methods

Appendix: Collection factory methods from Guava

It should be noted that Guava in fact already provides the static factory methods for the types in Java Collections Framework:

From the main package com.google.common.collect:

  • Lists.newArrayList(), newLinkedList(), …
  • Sets.newHashSet(), newTreeSet(), newEnumSet(…), …
  • Maps.newHashMap(), newTreeMap(), newEnumMap(…), …

In fact, in the spirit of Effective Java 2nd Edition recommendation, Guava's own collections do not provide public constructors, but instead provide static create() factory methods:

  • HashMultiSet.create(), a Multiset implementation
  • TreeMultimap.create(), a Multimap implementation

The rest of the library also provides many highly useful functionality.

like image 124
polygenelubricants Avatar answered Oct 16 '22 08:10

polygenelubricants