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.
相关问题
- Sorting 3 numbers without branching [closed]
- Graphics.DrawImage() - Throws out of memory except
- Generic Generics in Managed C++
- Why am I getting UnauthorizedAccessException on th
- 求获取指定qq 资料的方法
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:
I can build one reusable class... (in the case where you don't want to use the raw collection for some reason)
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 aReference<T>
that has to interact with other classes. Do you really want to extendCallable<T>
andFuture<T>
and every other associated class to create type-safe versions?I don't.
Don't forget that generics aren't just used by classes, they can also be used by methods. For example, take the following snippet:
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:
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):
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>>
).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
ClassCastException
s which can be thrown at runtime, and can lead to more robust code.But I suspect that you're fully aware of that.
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 aHashMap
. The code I would have to type in is: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+SpaceTrue, 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:In that piece of code, there are three new Java 5 features present:
First, generics and autoboxing of primitives allow the following lines:
The integer
10
is autoboxed into anInteger
with the value of10
. (And same for42
). Then thatInteger
is tossed into theSet
which is known to holdInteger
s. Trying to throw in aString
would cause a compile error.Next, for for-each loop takes all three of those:
First, the
Set
containingInteger
s are used in a for-each loop. Each element is declared to be anint
and that is allowed as theInteger
is unboxed back to the primitiveint
. And the fact that this unboxing occurs is known because generics was used to specify that there wereInteger
s held in theSet
.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:(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, aObject
is what is beingadd
ed into the set.In the above lines, autoboxing is in play -- the primitive
int
value10
and42
are being autoboxed intoInteger
objects, which are being added to theSet
. However, keep in mind, theInteger
objects are being handled asObject
s, as there are no type information to help the compiler know what type theSet
should expect.This is the part that is crucial. The reason the for-each loop works is because the
Set
implements theIterable
interface, which returns anIterator
with type information, if present. (Iterator<T>
, that is.)However, since there is no type information, the
Set
will return anIterator
which will return the values in theSet
asObject
s, and that is why the element being retrieved in the for-each loop must be of typeObject
.Now that the
Object
is retrieved from theSet
, it needs to be cast to anInteger
manually to perform the addition:Here, a typecast is performed from an
Object
to anInteger
. 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 aClassCastException
waiting to happen, but I digress...)The
Integer
is now unboxed into anint
and allowed to perform the addition into theint
variabletotal
.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.
Single most reason is they provide Type safety
as opposed to,
as a simple example.
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.
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 aList
of things I hope are strings!)?That's why you should want to use generics (or something better).