tags:

views:

1792

answers:

28

I thought I'd offer this softball to whomever would like to hit it out of the park. What are generics, what are the advantages of generics, why, where, how should I use them? Please, keep it fairly basic. Thanks.

+1  A: 

Generics allow you to create objects that are strongly typed, yet you don't have to define the specific type. I think the best useful example is the List and similar classes.

Using the generic list you can have a List List List whatever you want and you can always reference the strong typing, you don't have to convert or anything like you would with a Array or standard List.

Mitchel Sellers
+1  A: 

Generics avoid the performance hit of boxing and unboxing. Basically, look at ArrayList vs List<T>. Both do the same core things, but List<T> will be a lot faster because you don't have to box to/from object.

Darren Kopp
That's the essence of it, isn't it? Nice.
MrBoJangles
Well not entirely; they're useful for type safety + avoiding casts for references types too without boxing/unboxing coming into it at all.
kronoz
So I guess the question that follows is, "Why would I ever want to use an ArrayList?" And, hazarding an answer, I'd say that ArrayLists are fine as long as you don't expect to box and unbox their values much. Comments?
MrBoJangles
Nope, they're defunct as of .net 2; only useful for backwards compatibility. ArrayLists are slower, not type safe and require either boxing/unboxing or casting.
kronoz
If you're not storing values types (e.g. ints or structs), there is no boxing when using ArrayList - the classes are already 'object'.Using List<T> is still much better because of type of safety, and if you really do want to store objects, then using List<object> is better.
Wilka
Yes but then there's casting if you're using reference types which, I believe, incurs a performance penalty as well. Not to mention not being type safe + extending code bloat!
kronoz
+1  A: 

Generics let you use strong typing for objects and data structures that should be able to hold any object. It also eliminates tedious and expensive typecasts when retrieving objects from generic structures (boxing/unboxing).

One example that uses both is a linked list. What good would a linked list class be if it could only use object Foo? To implement a linked list that can handle any kind of object, the linked list and the nodes in a hypothetical node inner class must be generic if you want the list to contain only one type of object.

Steve Johnson
+1  A: 

If your collection contains value types, they don't need to box/unbox to objects when inserted into the collection so your performance increases dramatically. Cool add-ons like resharper can generate more code for you, like foreach loops.

gt124
+4  A: 

I just like them because they give you a quick way to define a custom type (as I use them anyway).

So for example instead of defining a structure consisting of a string and an integer, and then having to implement a whole set of objects and methods on how to access an array of those structures and so forth, you can just make a Dictionary

Dictionary<int, string> dictionary = new Dictionary<int, string>();

And the compiler/IDE does the rest of the heavy lifting. A Dictionary in particular lets you use the first type as a key (no repeated values).

Schnapple
+26  A: 
  • Allows you to write code/use library methods which are type-safe, i.e. a List<string> is guaranteed to be a list of strings.
  • As a result of generics being used the compiler can perform compile-time checks on code for type safety, i.e. are you trying to put an int into that list of strings? Using an ArrayList would cause that to be a less transparent runtime error.
  • Faster than using objects as it either avoids boxing/unboxing (where .net has to convert value types to reference types or vice-versa) or casting from objects to the required reference type.
  • Allows you to write code which is applicable to many types with the same underlying behaviour, i.e. a Dictionary<string, int> uses the same underlying code as a Dictionary<DateTime, double>; using generics, the framework team only had to write one piece of code to achieve both results with the aforementioned advantages too.
kronoz
Ah, very nice, and I do like bullet lists. I think this is the most complete yet succinct answer so far.
MrBoJangles
+1  A: 

The primary advantage, as Mitchel points out, is strong-typing without needing to define multiple classes.

This way you can do stuff like:

List<SomeCustomClass> blah = new List<SomeCustomClass>();
blah[0].SomeCustomFunction();

Without generics, you would have to cast blah[0] to the correct type to access its functions.

Kevin Pang
Given the choice, I'd rather not cast than cast.
MrBoJangles
Strong typing is easily the best aspect of generics imho, especially given the compile-time type checking that allows.
kronoz
+1  A: 

the jvm casts anyway... it implicitly creates code which treats the generic type as "Object" and creates casts to the desired instantiation. Java generics are just syntactic sugar.

That's interesting, so I'll vote it up.
MrBoJangles
+1  A: 

Another advantage of using Generics (especially with Collections/Lists) is you get Compile Time Type Checking. This is really useful when using a Generic List instead of a List of Objects.

Chris Pietschmann
+1  A: 

Single most reason is they provide Type safety

List<Customer> custCollection = new List<Customer>;

as opposed to,

object[] custCollection = new object[] { cust1, cust2 };

as a simple example.

Vin
Type safety, a discussion in itself. Maybe someone should ask a question about it.
MrBoJangles
Yeah but what are you hinting at? The whole point of Type Safety?
Vin
+1  A: 

In summary, generics allow you to specify more precisily what you intend to do (stronger typing).

This has several benefits for you:

  • Because the compiler knows more about what you want to do, it allows you to omit a lot of type-casting because it already knows that the type will be compatible.

  • This also gets you earlier feedback about the correctnes of your program. Things that previously would have failed at runtime (e.g. because an object couldn't be casted in the desired type), now fail at compile-time and you can fix the mistake before your testing-department files a cryptical bug report.

  • The compiler can do more optimizations, like avoiding boxing, etc.

Thomas Danecker
A: 

Not meaning to answer my own question, but I just found and read this (as did anyone who looks at their start page in VS): http://blogs.msdn.com/kirillosenkov/archive/2008/08/19/how-i-started-to-really-understand-generics.aspx.

Pretty good stuff.

MrBoJangles
+1  A: 

A couple of things to add/expand on (speaking from the .NET point of view):

Generic types allow you to create role-based classes and interfaces. This has been said already in more basic terms, but I find you start to design your code with classes which are implemented in a type-agnostic way - which results in highly reusable code.

Generic arguments on methods can do the same thing, but they also help apply the "Tell Don't Ask" principle to casting, i.e. "give me what I want, and if you can't, you tell me why".

SpongeJim
+1  A: 

I know this is a C# question, but generics are used in other languages too, and their use/goals are quite similar.

Java collections use generics since Java 1.5. So, a good place to use them is when you are creating your own collection-like object.

An example I see almost everywhere is a Pair class, which holds two objects, but needs to deal with those objects in a generic way.

class Pair<F, S> {
    public final F first;
    public final S second;

    public Pair(F f, S s)
    { 
        first = f;
        second = s;   
    }
}

Whenever you use this Pair class you can specify which kind of objects you want it to deal with and any type cast problems will show up at compile time, rather than runtime.

Generics can also have their bounds defined with the keywords 'super' and 'extends'. For example, if you want to deal with a generic type but you want to make sure it extends a class called Foo (which has a setTitle method):

public class FooManager <F extends Foo>{
    public void setTitle(F foo, String title) {
        foo.setTitle(title);
    }
}

While not very interesting on its own, it's useful to know that whenever you deal with a FooManager, you know that it will handle MyClass types, and that MyClass extends Foo.

etchasketch
+1  A: 

I once gave a talk on this topic. You can find my slides, code, and audio recording at http://www.adventuresinsoftware.com/generics/.

Michael L Perry
+2  A: 

The best benefit to Generics is code reuse. Lets say that you have a lot of business objects, and you are going to write VERY similar code for each entity to perform the same actions. (I.E Linq to SQL operations).

With generics, you can create a class that will be able to operate given any of the types that inherit from a given base class or implement a given interface like so:

public interface IEntity
{

}

public class Employee : IEntity
{
    public string FirstName { get; set; }
    public string LastName { get; set; }
    public int EmployeeID { get; set; }
}

public class Company : IEntity
{
    public string Name { get; set; }
    public string TaxID { get; set }
}

public class DataService<ENTITY, DATACONTEXT>
    where ENTITY : class, IEntity, new()
    where DATACONTEXT : DataContext, new()
{

    public void Create(List<ENTITY> entities)
    {
     using (DATACONTEXT db = new DATACONTEXT())
     {
      Table<ENTITY> table = db.GetTable<ENTITY>();

      foreach (ENTITY entity in entities)
       table.InsertOnSubmit (entity);

      db.SubmitChanges();
     }
    }
}

public class MyTest
{
    public void DoSomething()
    {
     var dataService = new DataService<Employee, MyDataContext>();
     dataService.Create(new Employee { FirstName = "Bob", LastName = "Smith", EmployeeID = 5 });
     var otherDataService = new DataService<Company, MyDataContext>();
            otherDataService.Create(new Company { Name = "ACME", TaxID = "123-111-2233" });

    }
}

Notice the reuse of the same service given the different Types in the DoSomething method above. Truly elegant!

There's many other great reasons to use generics for your work, this is my favorite.

Code Monkey
+3  A: 
  • Typed collections - even if you don't want to use them you're likely to have to deal with them from other libraries , other sources.

  • Generic typing in class creation:

    public class Foo < T> { public T get()...

  • Avoidance of casting - I've always disliked things like

    new Comparator { public int compareTo(Object o){ if (o instanceof classIcareAbout)...

Where you're essentially checking for a condition that should only exist because the interface is expressed in terms of objects.

My initial reaction to generics was similar to yours - "too messy, too complicated". My experience is that after using them for a bit you get used to them, and code without them feels less clearly specified, and just less comfortable. Aside from that, the rest of the java world uses them so you're going to have to get with the program eventually, right?

Steve B.
to be accurate regarding avoidance of casting: casting occurs, according to the Sun documentation, but it is done by the compiler. You just get to avoid writing casts in your code.
Demi
Perhaps, I appear to be stuck in a long string of companies unwilling to go above 1.4, so who knows, I may retire before I get to 5. I've also been thinking lately that forking a "SimpleJava" might be an interesting concept--Java is going to keep adding features and for a lot of the code I've seen, it won't be a healthy thing. I already deal with people who can't code a loop--I'd hate to see them try to inject generics into their pointlessly unrolled loops.
Bill K
@Bill K: Few people need to use the full power of generics. That's only necessary when you are writing a class that is itself generic.
Eddie
+1  A: 

I use them for example in a GenericDao implemented with SpringORM and Hibernate which look like this

public abstract class GenericDaoHibernateImpl<T> 
    extends HibernateDaoSupport {

    private Class<T> type;

    public GenericDaoHibernateImpl(Class<T> clazz) {
        type = clazz;
    }

    public void update(T object) {
        getHibernateTemplate().update(object);
    }

    @SuppressWarnings("unchecked")
    public Integer count() {
    return ((Integer) getHibernateTemplate().execute(
        new HibernateCallback() {
            public Object doInHibernate(Session session) {
                    // Code in Hibernate for getting the count
                }
        }));
    }
  .
  .
  .
}

By using generics my implementations of this DAOs force the developer to pass them just the entities they are designed for by just subclassing the GenericDao

public class UserDaoHibernateImpl extends GenericDaoHibernateImpl<User> {
    public UserDaoHibernateImpl() {
        super(User.class);     // This is for giving Hibernate a .class
                               // work with, as generics disappear at runtime
    }

    // Entity specific methods here
}

My little framework is more robust (have things like filtering, lazy-loading, searching). I just simplified here to give you an example

I, like Steve and you, said at the beginning "Too messy and complicated" but now I see its advantages

victor hugo
A: 

Using generics for collections is just simple and clean. Even if you punt on it everywhere else, the gain from the collections is a win to me.

List<Stuff> stuffList = getStuff();
for(Stuff stuff : stuffList) {
    stuff.do();
}

vs

List stuffList = getStuff();
Iterator i = stuffList.iterator();
while(i.hasNext()) {
    Stuff stuff = (Stuff)i.next();
    stuff.do();
}

or

List stuffList = getStuff();
for(int i = 0; i < stuffList.size(); i++) {
    Stuff stuff = (Stuff)stuffList.get(i);
    stuff.do();
}

That alone is worth the marginal "cost" of generics, and you don't have to be a generic Guru to use this and get value.

Will Hartung
Without generics you can do: List stuffList = getStuff(); for(Object stuff : stuffList) { ((Stuff)stuff).doStuff(); }, which isn't much different.
Tom Hawtin - tackline
If you have to cast something, you've already lost.
Jherico
Without generics I do stuffList.doAll(); I said I always have a wrapper class which is exactly the place for code like that. Otherwise how do you avoid copying this loop elsewhere? Where do you put it for reuse?The wrapper class will have a loop of some sort probably, but in that class, since that class is all about "The stuff", using a casted for loop like Tom suggested above is pretty clear/self documenting.
Bill K
@Jherico, That is really interesting. I wonder if there is a reason you feel that way, and if that is what I'm not understanding--that there is something in peoples nature that finds any casting for any reason somehow obscene and is willing to go to unnatural lengths (like adding a much more complex syntax) to avoid it. Why "If you have to cast something, you've already lost"?
Bill K
@Jherico: according to Sun documentation, generics afford the compiler the knowledge of what to cast objects to. Since the compiler does the casting for generics, rather than the user, does this change your statement?
Demi
I've converted code from pre Java 1.5 to Generics, and in the process found bugs where the wrong object type was put into a collection. I also fall into the "if you have to cast you've lost" camp, because if you have to cast manually, you run the risk of a ClassCastException. With Generics the compiler does it invisibly for you, but the chance of a ClassCastException is *way* reduced due to the type safety. Yes, without Generics you can use Object, but that's a terrible code smell to me, the same as "throws Exception".
Eddie
@Eddie: agreed - it's also easier to write and simpler to understand, IMO. @Bill K: do you really see Java generic syntax as being "much more complex" than non-generic syntax?
harto
I see it as being the most complex part of java to learn/master. There are few unique patterns to java syntax that throw new programmers--inner classes, exceptions, memorizing "public static void main(String[])"--hmm--The ternary operator... more? Put on this list, isn't generics by FAR the most complex piece of "unique" syntax in java? I just don't see the benefit meeting this complexity when the rare well-placed cast is a very simple straight-forward syntax who's need is not even completely eliminated by Generics anyway (or is it? If so I might give generics a little more leeway)
Bill K
I think the generic syntax is complex IN THE LARGE, if you take the whole space. But for THIS CASE, which I find the most prevalent, the syntax is (to me) pretty straightforward. At least in Java, >> is not a "keyword" like in C++, so List<Map<Integer>> is legal, wheres in C++ (in the past) it was not, you had to do List<Map<Integer> >, perhaps they've fixed that by now.
Will Hartung
+9  A: 

If you were to search the Java bug database just before 1.5 was released, you'd find seven times more bugs with NullPointerException than ClassCastException. So it doesn't seem that it is a great feature to find bugs, or at least bugs that persist after a little smoke testing.

For me the huge advantage of generics is that they document in code important type information. If I didn't want that type information documented in code, then I'd use a dynamically typed language, or at least a language with more implicit type inference.

Keeping an object's collections to itself isn't a bad style (but then the common style is to effectively ignore encapsulation). It rather depends upon what you are doing. Passing collections to "algorithms" is slightly easier to check (at or before compile-time) with generics.

Tom Hawtin - tackline
Not only is it documented (which by itself is a huge win), it's enforced by the compiler.
James Schek
Good point, but isn't that also accomplished by enclosing the collection in a class that defines "a collection of this type of object"?
Bill K
James: Yes that's the point about it being documented *in code*.
Tom Hawtin - tackline
I don't think I know of good libraries that use collections for "Algorithms" (possibly implying that you are talking about "Functions" which leads me to believe they should be a method in the collection's object). I think that the JDK just about always extracts a nice, clean array that is a copy of the data so that it cannot be messed with--at least more often than not.
Bill K
Also, isn't having an object describing exactly how the collection is used and limiting it's use a MUCH better form of in-code documentation? I find the information given in a generics extremely redundant in good code.
Bill K
Tom--sorry, just trying to distinguish against those who think of "in code" as Hungarian naming...
James Schek
+1  A: 

To give a good example. Imagine you have a class called Foo

public class Foo
{
   public string Bar() { return "Bar"; }
}

Example 1 Now you want to have a collection of Foo objects. You have two options, LIst or ArrayList, both of which work in a similar manner.

Arraylist al = new ArrayList();
List<Foo> fl = new List<Foo>();

//code to add Foos
al.Add(new Foo());
f1.Add(new Foo());

In the above code, if I try to add a class of FireTruck instead of Foo, the ArrayList will add it, but the Generic List of Foo will cause an exception to be thrown.

Example two.

Now you have your two array lists and you want to call the Bar() function on each. Since hte ArrayList is filled with Objects, you have to cast them before you can call bar. But since the Generic List of Foo can only contain Foos, you can call Bar() directly on those.

foreach(object o in al)
{
    Foo f = (Foo)o;
    f.Bar();
}

foreach(Foo f in fl)
{
   f.Bar();
}
Goblyn27
I'm guessing you answered before reading the question. Those are the two cases that don't really help me much (described in question). Are there other cases where it does something useful?
Bill K
+1  A: 

From the Sun Java documentation, in response to "why should i use generics?":

"Generics provides a way for you to communicate the type of a collection to the compiler, so that it can be checked. Once the compiler knows the element type of the collection, the compiler can check that you have used the collection consistently and can insert the correct casts on values being taken out of the collection... The code using generics is clearer and safer.... the compiler can verify at compile time that the type constraints are not violated at run time [emphasis mine]. Because the program compiles without warnings, we can state with certainty that it will not throw a ClassCastException at run time. The net effect of using generics, especially in large programs, is improved readability and robustness. [emphasis mine]"

Demi
I've never found a case where generic typing of collections would have helped my code. My collections are tightly scoped. That's why I phrased this "Can it help me?". As a side question though, are you saying that before you started using generics this happened to you occasionally? (putting the wrong object type in your collection). It seems to me like a solution with no real problem, but maybe I'm just lucky.
Bill K
@Bill K: if the code is tightly controlled (that is, only used by you) perhaps you never will come across this as an issue. That's great! The biggest risks are in large projects that multiple people work on, IMO. It is a safety net, and a "best practice".
Demi
@Bill K: Here is an example. Say you have a method that returns an ArrayList. Let's say that the ArrayList is not a generic collection. Someone's code takes this ArrayList and attempts to perform some operation on its items. The only problem being that you filled the ArrayList with BillTypes, and the consumer is trying to operate on ConsumerTypes. This compiles, but blows up during runtime. If you use generic collections you will have compiler errors instead, which are much nicer to deal with.
Demi
@Bill K: I've worked with people with widely varying skill levels. I don't have the luxury of choosing who I share a project with. Thus, the type safety is very important to me. Yes, I've found (and corrected) bugs by converting code to use Generics.
Eddie
+11  A: 

I really hate to repeat myself. I hate typing the same thing more often than I have to. I don't like restating things multiple times with slight differences.

Instead of creating:

class MyObjectList  {
   MyObjectget(int index) {...}
}
class MyOtherObjectList  {
   MyOtherObjectget(int index) {...}
}
class AnotherObjectList  {
   AnotherObject get(int index) {...}
}

I can build one reusable class... (in the case where you don't want to use the raw collection for some reason)

class MyList<T> {
   T get(int index) { ... }
}

I'm now 3x more efficient and I only have to maintain one copy. Why WOULDN'T you want to maintain less code?

This is also true for non-collection classes such as a Callable<T> or a Reference<T> that has to interact with other classes. Do you really want to extend Callable<T> and Future<T> and every other associated class to create type-safe versions?

I don't.

James Schek
I'm not sure I understand. I'm not suggesting you make "MyObject" wrappers, that would be horrid. I'm suggesting that if your collection of objects is a collection of Cars, then you write a Garage object. It wouldn't have get(car), it would have methods like buyFuel(100) that would buy $100 of fuel and distribute it among the cars that need it most. I'm talking about real business classes, not just "wrappers". For instance, you should almost never get(car) or loop over them outside the collection--you don't ask an Object for it's members, instead you ask it to do an operation for you.
Bill K
Even within your garage, you should have type-safety. So either you have List<Cars>, ListOfCars or you cast everywhere. I don't feel the need to state the type more than the minimum times necessary.
James Schek
I agree that type safety would be nice, but it's much less helpful since it's confined to the garage class. It's encapsulated and easily controlled then, so my point is that it gives you this little advantage at a cost of new syntax. It's like modifying the US constitution to make running a red light illegal--Yes it should always be illegal but does it justify an amendment? I also think it encourages people NOT to use encapsulation for this case, which is actually comparitively harmful.
Bill K
Bill--you may have a point about not-using-encapsulation, but the rest of your argument is a poor comparison. The cost of learning the new syntax is minimal in this case (compare this to lambdas in C#); comparing this to ammending the Constitution makes no sense. The Constitution has no intent to specify traffic code. It's more like switching to a Serif-Font printed version on poster board instead of a hand-written copy on parchment. It's the same meaning, but it's a lot clearer and easier to read.
James Schek
BTW, the word "constitution" should always be capitalized when referring to the U.S. Constitution.
James Schek
A: 

Generics also give you the ability to create more reusable objects/methods while still providing type specific support. You also gain a lot of performance in some cases. I don't know the full spec on the Java Generics, but in .NET I can specify constraints on the Type parameter, like Implements a Interface, Constructor , and Derivation.

eschneider
+2  A: 

Don't forget that generics aren't just used by classes, they can also be used by methods. For example, take the following snippet:

private <T extends Throwable> T logAndReturn(T t) {
    logThrowable(t); // some logging method that takes a Throwable
    return t;
}

It is simple, but can be used very elegantly. The nice thing is that the method returns whatever it was that it was given. This helps out when you are handling exceptions that need to be re-thrown back to the caller:

    ...
} catch (MyException e) {
    throw logAndReturn(e);
}

The point is that you don't lose the type by passing it through a method. You can throw the correct type of exception instead of just a Throwable, which would be all you could do without generics.

This is just a simple example of one use for generic methods. There are quite a few other neat things you can do with generic methods. The coolest, in my opinion, is type inferring with generics. Take the following example (taken from Josh Bloch's Effective Java 2nd Edition):

...
Map<String, Integer> myMap = createHashMap();
...
public <K, V> Map<K, V> createHashMap() {
    return new HashMap<K, V>();
}

This doesn't do a lot, but it does cut down on some clutter when the generic types are long (or nested; i.e. Map<String, List<String>>).

jigawot
I don't think that's true about exceptions. It's making me think, but I'm 95% sure you'd get exactly the same results without using generics at all (and clearer code). Type information is part of the object, not what you cast it to. I'm tempted to give it a try though--maybe I will tomorrow at work and get back to you.. Tell you what, I'm going to try it and if you're right, I'm going to go through your list of posts and vote for 5 of your posts :) If not though, you might want to consider that the simple availability of generics has caused you to complicate your code to no advantage.
Bill K
It is true that this adds extra complexity. However, I think it does have some use. The problem is you can't throw a plain old `Throwable` from within a method body that has specific declared exceptions. The alternative is either writing separate methods to return each exception type, or doing the cast yourself with a non-generic method that returns a `Throwable`. The former is too verbose and quite useless and the latter won't get any help from the compiler. By using generics, the compiler will automatically insert the correct cast for you. So, the question is: is that worth the complexity?
jigawot
Oh, I get it. So it avoids the cast coming out... good point. I owe you 5.
Bill K
+7  A: 

Not needing to typecast is one of the biggest advantages of Java generics, as it will perform type checking at compile-time. This will reduce the possibility of ClassCastExceptions which can be thrown at runtime, and can lead to more robust code.

But I suspect that you're fully aware of that.

Every time I look at Generics it gives me a headache. I find the best part of Java to be it's simplicity and minimal syntax and generics are not simple and add a significant amount of new syntax.

At first, I didn't see the benefit of generics either. I started learning Java from the 1.4 syntax (even though Java 5 was out at the time) and when I encountered generics, I felt that it was more code to write, and I really didn't understand the benefits.

Modern IDEs make writing code with generics easier.

Most modern, decent IDEs are smart enough to assist with writing code with generics, especially with code completion.

Here's an example of making an Map<String, Integer> with a HashMap. The code I would have to type in is:

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

And indeed, that's a lot to type just to make a new HashMap. However, in reality, I only had to type this much before Eclipse knew what I needed:

Map<String, Integer> m = new Ha Ctrl+Space

True, I did need to select HashMap from a list of candidates, but basically the IDE knew what to add, including the generic types. With the right tools, using generics isn't too bad.

In addition, since the types are known, when retrieving elements from the generic collection, the IDE will act as if that object is already an object of its declared type -- there is no need to casting for the IDE to know what the object's type is.

A key advantage of generics comes from the way it plays well with new Java 5 features. Here's an example of tossing integers in to a Set and calculating its total:

Set<Integer> set = new HashSet<Integer>();
set.add(10);
set.add(42);

int total = 0;
for (int i : set) {
  total += i;
}

In that piece of code, there are three new Java 5 features present:

First, generics and autoboxing of primitives allow the following lines:

set.add(10);
set.add(42);

The integer 10 is autoboxed into an Integer with the value of 10. (And same for 42). Then that Integer is tossed into the Set which is known to hold Integers. Trying to throw in a String would cause a compile error.

Next, for for-each loop takes all three of those:

for (int i : set) {
  total += i;
}

First, the Set containing Integers are used in a for-each loop. Each element is declared to be an int and that is allowed as the Integer is unboxed back to the primitive int. And the fact that this unboxing occurs is known because generics was used to specify that there were Integers held in the Set.

Generics can be the glue that brings together the new features introduced in Java 5, and it just makes coding simpler and safer. And most of the time IDEs are smart enough to help you with good suggestions, so generally, it won't a whole lot more typing.

And frankly, as can be seen from the Set example, I feel that utilizing Java 5 features can make the code more concise and robust.

Edit - An example without generics

The following is an illustration of the above Set example without the use of generics. It is possible, but isn't exactly pleasant:

Set set = new HashSet();
set.add(10);
set.add(42);

int total = 0;
for (Object o : set) {
  total += (Integer)o;
}

(Note: The above code will generate unchecked conversion warning at compile-time.)

When using non-generics collections, the types that are entered into the collection is objects of type Object. Therefore, in this example, a Object is what is being added into the set.

set.add(10);
set.add(42);

In the above lines, autoboxing is in play -- the primitive int value 10 and 42 are being autoboxed into Integer objects, which are being added to the Set. However, keep in mind, the Integer objects are being handled as Objects, as there are no type information to help the compiler know what type the Set should expect.

for (Object o : set) {

This is the part that is crucial. The reason the for-each loop works is because the Set implements the Iterable interface, which returns an Iterator with type information, if present. (Iterator<T>, that is.)

However, since there is no type information, the Set will return an Iterator which will return the values in the Set as Objects, and that is why the element being retrieved in the for-each loop must be of type Object.

Now that the Object is retrieved from the Set, it needs to be cast to an Integer manually to perform the addition:

  total += (Integer)o;

Here, a typecast is performed from an Object to an Integer. In this case, we know this will always work, but manual typecasting always makes me feel it is fragile code that could be damaged if a minor change is made else where. (I feel that every typecast is a ClassCastException waiting to happen, but I digress...)

The Integer is now unboxed into an int and allowed to perform the addition into the int variable total.

I hope I could illustrate that the new features of Java 5 is possible to use with non-generic code, but it just isn't as clean and straight-forward as writing code with generics. And, in my opinion, to take full advantage of the new features in Java 5, one should be looking into generics, if at the very least, allows for compile-time checks to prevent invalid typecasts to throw exceptions at runtime.

coobird
The integration with the enhanced for loop is really nice (although I think the damn loop is broken because I can't use the exact same syntax with a non-generic collection--it should just use the cast/autobox to int, it's got all the information it needs!), but you're right, the help in the IDE is probably good. I still don't know if it's enough to justify the additional syntax, but at least that's something I can benefit from (which answers my question).
Bill K
@Bill K: I've added an example of using Java 5 features without using generics.
coobird
That is a good point, I hadn't used that (I mentioned I've been stuck, on 1.4 and early for years now). I agree that there are advantages, but the conclusions I'm reaching are that A) they tend to be quite advantageous to people who don't use OO correctly and are of less use to those who do, and B) The advantages you've listed are advantages, but hardly worth enough to justify even a small syntax change, let alone the large changes required to really grok generics as implemented in Java. But at least there are advantages.
Bill K
+2  A: 

Haven't you ever written a method (or a class) where the key concept of the method/class wasn't tightly bound to a specific data type of the parameters/instance variables (think linked list, max/min functions, binary search, etc.).

Haven't you ever wish you could reuse the algorthm/code without resorting to cut-n-paste reuse or compromising strong-typing (e.g. I want a List of Strings, not a List of things I hope are strings!)?

That's why you should want to use generics (or something better).

Bert F
I've never had to copy/paste reuse for this kind of stuff (Not sure how that would even happen?) You implement an interface that fits your needs, and use that interface. The rare case where you can't do this is when you are writing a pure utility (such as the collections), and for those (as I described in the question) it's really never been a problem. I do compromise strong typing--Just like you have to if you use reflection. Do you absolutely refuse to use reflection because you can't have strong typing? (If I have to use reflection, I just encapsulate it like a collection).
Bill K
+6  A: 

Generics in Java facilitate parametric polymorphism. By means of type parameters, you can pass arguments to types. Just as a method like String foo(String s) models some behaviour, not just for a particular string, but for any string s, so a type like List<T> models some behaviour, not just for a specific type, but for any type. List<T> says that for any type T, there exists a List of Ts. So List is a actually a type constructor. It takes a type as an argument and constructs another type as a result.

Here are a couple of examples of generic types I use every day. First, a very useful generic interface:

public interface F<A, B> {
  public B f(A a);
}

This interface says that for any two types, A and B, there's a function (called f) that takes an A and returns a B. When you implement this interface, A and B can be any types you want, as long as you provide a function f that takes the former and returns the latter. Here's an example implementation of the interface:

F<Integer, String> intToString = new F<Integer, String>() {
  public String f(int i) {
    return String.valueOf(i);
  }
}

Before generics, polymorphism was achieved by subclassing using the extends keyword. With generics, we can actually do away with subclassing and use parametric polymorphism instead. For example, consider a parameterised (generic) class used to calculate hash codes for any type. Instead of overriding Object.hashCode(), we would use a generic class like this:

public final class Hash<A> {
  private final F<A, Integer> hashFunction;

  public Hash(final F<A, Integer> f) {
    this.hashFunction = f;
  }

  public int hash(A a) {
    return hashFunction.f(a);
  }
}

This is much more flexible than using inheritance, because we can stay with the theme of using composition and parametric polymorphism without locking down brittle hierarchies.

Java's generics are not perfect though. You can abstract over types, but you can't abstract over type constructors, for example. That is, you can say "for any type T", but you can't say "for any type T that takes a type parameter A".

I wrote an article about these limits of Java generics, here.

One huge win with generics is that they let you avoid subclassing. Subclassing tends to result in brittle class hierarchies that are awkward to extend, and classes that are difficult to understand individually without looking at the entire hierarchy.

Wereas before generics you might have classes like Widget extended by FooWidget, BarWidget, and BazWidget, with generics you can have a single generic class Widget<A> that takes a Foo, Bar or Baz in its constructor to give you Widget<Foo>, Widget<Bar>, and Widget<Baz>.

Apocalisp
It would be a good point about the subclassing if Java didn't have interfaces. Wouldn't it be correct to have FooWidget, BarWidtet and BazWidget all implement Widget? I could be wrong about this though.. But this is a really good point if I'm wrong.
Bill K