What's cool about generics, why use them?

I thought I was offering this softball to anyone who would like to hit him from the park. What are generics, what are the benefits of generics, why, where, how to use them? Please keep it simple enough. Thank.

+66
generics c # types
Sep 16 '08 at 21:57
source share
27 answers
  • Allows you to write code usage / library usage methods that are type safe, i.e. List <string> is guaranteed to be a list of strings.
  • As a result of using generics, the compiler can perform code compilation time checks for type safety, i.e. are you trying to put int on this list of strings? Using an ArrayList will result in a less transparent runtime error.
  • Faster than using objects, because it either avoids boxing / unboxing (where .net should convert value types to link types or vice versa)) or discarding objects to the desired reference type.
  • Allows you to write code that is applicable to many types with the same basic behavior, that is, the dictionary <string, int> uses the same basic code as the dictionary <DateTime, double>; using generics, the framework team had to write one piece of code to achieve both results with the above benefits.
+104
Sep 16 '08 at 22:04
source share

I enjoy repeating myself. I hate typing the same thing more often than necessary. I do not like to repeat things several times with slight differences.

Instead of creating:

class MyObjectList { MyObject get(int index) {...} } class MyOtherObjectList { MyOtherObject get(int index) {...} } class AnotherObjectList { AnotherObject get(int index) {...} } 

I can create one reusable class ... (in case you do not want to use the original collection for any reason)

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

I am now 3 times more efficient, and I only need to save one instance. Why don't you want to support less code?

This is also true for non-collection classes, such as Callable<T> or Reference<T> , which must interact with other classes. Are you sure you want to extend Callable<T> and Future<T> and every other related class to create security type versions?

I dont know.

+35
Jun 04 '09 at 23:56
source share

No need to resort to type - one of the biggest advantages of Java generics , as it will perform type checking at compile time. This will reduce the possibility of a ClassCastException that can be ClassCastException at runtime, and can lead to more robust code.

But I suspect that you are fully aware of this.

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

Firstly, I also did not see the benefits of generics. I started learning Java from syntax 1.4 (although Java 5 was not available at the time), and when I came across generics, I felt like writing more code, and I really didn't understand the benefits.

Modern IDEs make it easy to write code with generics.

Most modern, decent IDEs are smart enough to help you write code with generics, especially with code completion.

Here is an example of creating a Map<String, Integer> with a HashMap . The code I would have to enter:

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

And indeed, it is a lot to print just to create a new HashMap . However, in fact, I only had to type this information before Eclipse knew what I needed:

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

True, I needed to select a HashMap from the list of candidates, but basically the IDE knew what to add, including generic types. Using the right tools, using generics is not so bad.

In addition, since the types are known, when extracting elements from the general collection, the IDE will act as if this object is already an object of its declared type - there is no need for a cast for the IDE to know what the type of the object is.

A key advantage of generics is how it works well with the new features of Java 5 . Here is an example of selecting integers in Set and calculating its total amount:

 Set<Integer> set = new HashSet<Integer>(); set.add(10); set.add(42); int total = 0; for (int i : set) { total += i; } 

There are three new Java 5 features in this code snippet:

First, generics and autoboxing primitives allow the following lines:

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

The integer 10 is autoboxed in Integer with a value of 10 . (And the same for 42 ). Then, that Integer rushes into Set , which, as you know, holds Integer s. Attempting to throw String will result in a compilation error.

Further, for each cycle, all three of them:

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

First, a Set containing an Integer is used in every loop. Each element is declared as int , and this is allowed, since Integer unpacked back to the int primitive. And the fact that this unlocking is happening is known because generics were used to indicate that Set had Integer .

Generics can be a glue that combines the new features introduced in Java 5, and just simplifies and simplifies coding. And in most cases, the IDEs are smart enough to help you with good suggestions, so as a rule, this will not print much more.

And frankly, as the Set example shows, I believe that using Java 5 features can make the code more concise and reliable.

Edit - an example without generics

The following is an example of the Set example above without using generics. It is possible, but not entirely 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 a warning without warning at compile time.)

When using non-generics collections, the types that are introduced into the collection are objects of type Object . Therefore, in this example, a Object is what is included in the set in add ed.

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

In the above lines, autoboxing is in the game - the primitive value is int 10 and 42 autoboxing in Integer objects that are added to Set . However, keep in mind that Integer objects are treated as Object s, as there is no type information to help the compiler know what type Set should expect.

 for (Object o : set) { 

This is an integral part. The reason every loop works is because Set implements an Iterable interface that returns an Iterator with type information, if any. ( Iterator<T> , that is.)

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

Now that the Object is retrieved from Set , it must be completed manually for Integer to complete the addition:

  total += (Integer)o; 

Here, type-type runs from Object to Integer . In this case, we know that this will always work, but manual type casting always makes me feel like it is fragile code that can be damaged if minor changes occur otherwise. (I feel that every arrival like ClassCastException waiting, but I digress).

Integer now unpacked into int and allowed to add int total to the variable.

I hope I could illustrate that the new features of Java 5 can be used with non-standard code, but it's just not as clean and straightforward as writing code with generics. And, in my opinion, in order to take full advantage of the new features in Java 5, you need to look at generics if, at least, it allows compile-time checks to prevent invalid type casts to throw runtime exceptions.

+18
Jun 05 '09 at 0:24
source share

If you were looking for a Java error database before 1.5 was released, you would find seven times more errors with a NullPointerException than a ClassCastException . Therefore, it does not seem that this is a great feature for finding bugs, or at least bugs that persist after a little smoke testing.

For me, the great advantage of generics is that they document important type information in code . If I did not want information of this type to be documented in the code, I would use a dynamically typed language, or at least a language with a more implicit type of output.

Saving collections of objects is not in itself a bad style (but then the general style is effectively ignoring encapsulation). It rather depends on what you are doing. Transferring collections to “algorithms” is somewhat easier to verify (at or before compilation) using generics.

+14
Jun 04 '09 at 23:43
source share

Generics in Java facilitate parametric polymorphism . Using type parameters, you can pass arguments to types. In the same way that a method of type String foo(String s) models some behavior, not only for a specific string, but for any string s , therefore a type of type List<T> models some behavior not only for a specific type, but also for any type. List<T> says that for any type T there is a type List whose elements are T s. So List is actually a type constructor. It takes a type as an argument and creates another type as a result.

Here are a few examples of the typical types that I use every day. Firstly, a very useful general interface:

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

This interface says that for some two types A and B there is a function (called f ) that takes 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 first and returns the last. Here is an example implementation of the interface:

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

Prior to generics, polymorphism was achieved by subclassing using the extends . With the help of generics, we can actually abandon subclassification and use parametric polymorphism. For example, consider a parameterized (generic) class used to calculate hash codes for any type. Instead of overriding Object.hashCode (), we will use the generic class as follows:

 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 blocking fragile hierarchies.

Java generics are not perfect. You can abstract from types, but you cannot abstract from type constructors, for example. That is, you can say "for any type T", but you cannot say "for any type T that takes a parameter of type A".

Here I wrote an article about these limitations of Java generics.

One huge win with generics is that they allow you to avoid subclassing. Subclassification tends to lead to fragile class hierarchies that are inconvenient to extend, and classes that are difficult to understand individually without looking at the entire hierarchy.

Before generics appear, you can have classes like Widget , extended FooWidget , BarWidget and BazWidget , with generics you can have one common Widget<A> class that accepts Foo , Bar or Baz in its constructor to give you Widget<Foo> , Widget<Bar> and Widget<Baz> .

+10
Jun 05 '09 at 0:39
source share

Generics avoid hitting boxing performance and unboxing. Basically, look at ArrayList and List <T>. Both accomplish the same basic things, but List <T> will be much faster because you do not need to insert into / from the object.

+6
Sep 16 '08 at 22:00
source share
  • Typed collections - even if you do not want to use them, you may have to deal with them from other libraries, other sources.

  • General text input when creating a class:

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

  • Avoiding casting - I always didn’t like things like

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

Where you basically check for a condition that should exist only because the interface is expressed in terms of objects.

My initial reaction to generics was like yours - "too dirty, too complicated." My experience is that after using them for bits, you get used to them, and the code without them feels less clear and less comfortable. In addition, the rest of the java world uses them, so you have to end up with a program, right?

+5
Jun 04 '09 at 23:39
source share

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 way.

 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 the FireTruck class instead of Foo, the ArrayList will add it, but the Generic List from Foo will throw an exception.

Example 2

Now you have two lists of arrays, and you want to call the Bar () function for each. Since the hte ArrayList is filled with objects, you must drop them before you can call the bar. But since the Foo general list can only contain Foos, you can call Bar () directly on them.

 foreach(object o in al) { Foo f = (Foo)o; f.Bar(); } foreach(Foo f in fl) { f.Bar(); } 
+5
Jun 04 '09 at 23:46
source share

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

So, for example, instead of defining a structure consisting of a string and an integer, and then to implement a whole set of objects and methods on how to access an array of these structures, etc., you can simply make a dictionary

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

And the compiler / IDE does the rest of the hard work. The dictionary, in particular, allows you to use the first type as a key (without duplicate values).

+4
Sep 16 '08 at 22:02
source share

The best benefit for Generics is code reuse. Suppose you have a lot of business objects, and you are going to write VERY similar code for each object to perform the same actions. (IE Linq to SQL operations).

Using generics, you can create a class that can work with any of the types that inherit from this base class or implement this interface as follows:

 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" }); } } 

Note the reuse of the same service, given the different types in the DoSomething method above. Really elegant!

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

+4
Sep 17 '08 at 4:03
source share

Have you never written a method (or class) where the key concept of the method / class was not rigidly tied to a certain data type of parameter / instance variables (mental linked list, max / min functions, binary search, etc.).

Do you never want you to be able to reuse algorthm / code without reusing cut-n-paste or compromising strong typing (for example, I want List strings, not List things I hope are strings!)?

This is why you should want to use generics (or something better).

+4
Jun 05 '09 at 0:33
source share

The main advantage, as Mitchell points out, is a strong typing that does not require the definition of several classes.

This way you can do things like:

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

Without generics, you will need to impose blah [0] on the correct type in order to access its functions.

+2
Sep 16 '08 at 22:04
source share

I know this is a C # question, but generics are used in other languages ​​as well, and their uses / purposes are very similar.

Java collections use generics starting with Java 1.5. Thus, a good place to use them is when you create your own collection-like object.

An example that I see almost everywhere is the Pair class, which contains two objects, but must deal with these objects in a general 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 objects you want to handle, and any problems with type casting will be displayed at compile time, and not at run time.

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

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

Not very interesting in itself is useful to know that whenever you deal with FooManager, you know that it will handle the types MyClass and MyClass extends Foo.

+2
Sep 17 '08 at 2:28
source share

From the Sun Java documentation, in response to “why should I use generics?”:

“Generics provides you with a way to pass a collection type to the compiler so that it can be checked. When the compiler knows the type of the collection item, the compiler can verify that you have used the collection sequentially and can insert the correct discards on the values ​​retrieved from the collection ... Code using generics more clear and safe .... compiler can verify at compile time that the type constraints are not violated during runtime [emphasis mine]. since the program is compiled without notice, we can have Eren declare that it will not generate a ClassCastException exception at runtime. The net effect of the use of generics, especially in large programs, is improved readability and robustness. [emphasis mine] "

+2
Jun 04 '09 at 23:49
source share

Remember that generics are not 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. It's nice that the method returns everything that was given to it. This helps when you handle exceptions that need to be returned repeatedly to the caller:

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

The fact is that you do not lose the type by passing it by a method. You can set the correct type of exception instead of just Throwable , and that’s all you could do without generators.

. , . , , . ( Josh Bloch Effective Java 2nd Edition):

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

, - , ( , .. Map<String, List<String>> ).

+2
05 . '09 0:24
source share

, , . , List .

, List List List, , , - , Array .

+1
16 . '08 21:59
source share

, . (/).

, , - . , Foo? , , node , , .

+1
Sep 16 '08 22:00
source share

, / , . , resharper, , , foreach loop.

+1
16 . '08 22:01
source share

jvm ... , "Object" . Java- - .

+1
16 . '08 22:26
source share

Generics ( /) , . .

+1
16 . '08 22:29
source share

,

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

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

.

+1
16 . '08 22:30
source share

, , ( ).

:

  • , , , , .

  • . , (, - ), , , .

  • , , ..

+1
16 . '08 22:32
source share

/ ( .NET):

. , , , -, .

, "Tell Do not Ask" , " , ", , , ".

+1
17 . '08 1:50
source share

, , GenericDao, SpringORM Hibernate,

 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 } })); } . . . } 

, DAO , , 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 } 

( , , , ). ,

, , , " ",

+1
Jun 04 '09 23:42
source share
0
17 . '08 2:36
source share

generics . , - .

 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(); } 

"" , , .

0
04 . '09 23:43
source share

Generics /, . . Java Generics, .NET , , , .

0
05 . '09 0:00
source share



All Articles