taylorialcom/ Miscellaneous

Generics

The main purpose of generics is to generate compiler errors.... this is a good thing.

Why Generics

First, a very brief history... Generics were not part of the original design of the Java language. Generics were added to the Java language in 2004 with the release of J2SE 5.0.

Generics are said to provide static type safety for collections and eliminate the need for most typecasts. Essentially, they provide a mechanism for the developer to express her intent and then allows the compiler to verify that she has not violated that intent. Consider the following example:

Collection words = new ArrayList();
words.add("first");
words.add("second");
words.add("third");
for(Object word : words) {
  System.out.println(word + " is " + ((String)word).length() + " in length.");
}

Here we're not making use of generics, so the compiler has no idea what we intend to store in the collection. As a result, we had to cast the word Object reference to a String reference before we are able to call the length() method on the string in the collection. That's not the big deal though. The big deal is that I can add anything to this collection without the compiler objecting. For example, the last words.add("third") could be replaced with: words.add(3) and the compiler is still happy.1

With generics, we can be much more explicit in declaring our intented use for the collection:

Collection<String> words = new ArrayList<>();
words.add("first");
words.add("second");
words.add("third");
for(String word : words) {
  System.out.println(word + " is " + word.length() + " in length.");
}

Here we have declared our intent to only store references to Strings within our collection. We no longer need to get Object references and then cast them to String references, but, more importantly, the compiler will be sad, perhaps even angry, if we try to do something stupid like: words.add(3);. When do you want an angry compiler? Anytime you are doing something stupid. The compiler has now become your friend. Instead of letting you do something stupid that you won't discover until later (perhaps much later), the compiler now cares so much about you that it won't let you proceed with your idiocy.

Generics allow the compiler to become your good friend. With generics you can tell the compiler about your dreams for the software you are developing, and the compiler can tell you when you are doing things that will turn your dream into a nightmare.2

Define Your Own Class with Generic Support

We can define our own classes that use generics. In the declaration of the class, we need to add <SomeLabel> immediately after the class name. For example, in our simple ArrayList<E> implementation, we had:

public class ArrayList<E> implements List<E>, RandomAccess {
  private E[] elements = null;
    E[] temp = (E[])new Object[size()+1];

Compiler errors are good if they keep you from making mistakes. It is much easier to find your mistakes if the compiler finds them for you.

Specifying Constraints on Generics

Suppose we have a Shape hierarchy that consists of an abstract Shape class that includes an abstract calculateArea method. In addition, there are a number of concrete subclasses: Circle, Square, Triangle, etc... that provide concrete implementations of the calculateArea() method.

Consider the following implementation of a totalArea() method:

public static double totalArea(Collection<Shape> shapes) {
    double totalArea = 0;
    for(Shape shape : shapes) {
        if(shape!=null) {
            totalArea += shape.calculateArea();
        }
    }
    return totalArea;
}
   List<Shape> shapes = new LinkedList<>();
   for(int i=0; i < 10; ++i) {
       shapes.add(new Circle(Math.random()));
   }
   System.out.println(totalArea(shapes));

where the constructor for the Circle class takes the radius of the circle as an argument.

   List<Circle> shapes = new LinkedList<>();
   for(int i=0; i < 10; ++i) {
       shapes.add(new Circle(Math.random()));
   }
   System.out.println(totalArea(shapes));
public static double totalArea(Collection shapes) {

but here the porridge is too cold...

public static double totalArea(Collection<? extends Shape> shapes) {
1

Well, as happy as a compiler can be...

2

or something like that

3

from the implementation of add()

4

If you ask me, she was doing the bears a favor. How is it possible that a baby bear could sit on a chair and not break it, but a little girl causes it to fall to pieces?