Java 1.5 Generics Amr Ali Software Engineer, IBM-Egypt EG-JUG EG-JUG
Java 1.5 Generics
Amr Ali
Software Engineer, IBM-Egypt
EG-JUGEG-JUG
Versions of Java
Java 1
Java 2
Java 5.0
Oak: Designed for embedded devices
Java: Original, not very good version (but it had applets)
JDK 1.2: Includes “Swing” but no new syntaxJDK 1.3: Additional methods and packages, but no new syntax
JDK 1.4: More additions and the assert statement
JDK 1.5: Generics, enums, new for loop, and other new syntax
JDK 1.1: Adds inner classes and a completely new event-handling model
pre-Java
Java 5 overview1. Generics2. Auto Boxing and Un-boxing3. Enhanced for-loop4. Enumerations5. Annotation6. Variable arguments7. Static imports8. Other Enhancements
Motivations• In Java, array elements must all be of the same type:
– int[] counts = new int[10];• Hence, arrays are type safe: The compiler will not
let you put the wrong kind of thing into an array• A collection, such as a Vector or ArrayList, cannot
hold primitives, but will accept any type of Object:– Stack someStuff = new Stack();
someStuff.push("A String is an Object");someStuff.push(Color.BLUE);
• Is not type safe
Motivations, Cont.• Making a collection type safe is a tedious process
class StackOfStrings {private Stack internalStack = new Stack();public boolean isEmpty() { return internalStack.isEmpty();}public String push(String s) { internalStack.push(s); return s;}public String pop() { return(String)internalStack.pop();} etc.
class StackOfStrings {private Stack internalStack = new Stack();public boolean isEmpty() { return internalStack.isEmpty();}public String push(String s) { internalStack.push(s); return s;}public String pop() { return(String)internalStack.pop();} etc.
Generics for type safety in Java 5
• In Java 5, you can easily make any collection type safe• For example, you can create a Stack that holds only
Strings as follows:– Stack<String> names = new Stack<String>();
• You can write methods that require a type-safe collection as follows:– void printNames (Stack<String> names) {
• String nextName = names.pop(); // no casting needed!
• names.push("Hello"); // works just the same as before
• names.push(Color.RED); // compile-time error!
What generics are and aren’t
In JDK 1.4:-
myStack = new Stack();•String s = myStack.pop(); will not compile•String s = (String)myStack.pop(); compiles, with runtime check•myStack.push(Color.RED); compiles with no complaint
In JDK 1.5:-
myStack = new Stack<String>();•String s = myStack.pop(); Compiles with NO runtime check Does not compile if myStack was declared any other way•myStack.push(Color.RED) is a compiler error (= syntax error)
Defining Simple Generics
• Here is a small excerpt from the definitions of the interfaces List and Iterator in package java.util:
public interface List <E> {void add(E element);E get(int index);
}
public interface List <E> {void add(E element);E get(int index);
}Indicates a generic class declaration
Method “add” accept parameter
of type ‘E’
Mehtod ‘get’ returns object of
type ‘E’
A dog in the cat collection!
If a Collection of Cats were to inherit from Collection of Animals, then you may add a Dog (as an animal) to the Cats Collection, which is very Dangerous
Animal
Collection < Cat >
Collection < Animal >
Cat
Animal
Dog
Generics, Cont.• What bout this code snippet
14: List<String> strList = new ArrayList<String>(); 15: List<Object> objList = strList;16: objList.add(new Object());17: String s = strList.get(0);
14: List<String> strList = new ArrayList<String>(); 15: List<Object> objList = strList;16: objList.add(new Object());17: String s = strList.get(0);
1. Error at line 15: Cannot convert from list<String> to list <Object>
2. Error at line 16: Cannot add objects to list of Strings
3. Error at line 17: Type mismatch, trying to Pop Object as String
• Java compiler will prevent any action that may violate the type safety rules or threaten your application stability.
Generics, Behind the scene• Generics are implemented by the Java compiler
as a front-end conversion called erasure.• You can (almost) think of it as a source-to-
source translation, whereby the generic version of any method is converted to the non-generic version.
• Behind the scene, JavaC removes all type information:– e.g. new Stack<String>(); new Stack();
• As a result,– You can still say: if (thing instanceof Stack) ...– but you cannot say:
if (thing instanceof Stack<String>) ...
void printCollection(Collection<Object> c) {
for (Object e : c) {
System.out.println(e);
}
}
printCollection(new ArrayList<String>());
void printCollection(Collection<Object> c) {
for (Object e : c) {
System.out.println(e);
}
}
printCollection(new ArrayList<String>());
Generic WildcardsPrinting contents of any generic collection:
Will accept only list of Objects
To accept any type of collection regardless its generic type, use “Collection<?> c” notation, means c is a collection of unknown type.
• Error : Cannot pass ArrayList<String> as ArrayList<Object>• Warning : Passing ArrayList<String> as ArrayList<Object> is
not type safe• Success : 0 errors, 0 warnings
void printCollection(Collection<?> c) {for (Object e : c) {
System.out.println(e);}
} printCollection(new ArrayList<String>()); Okay.
void printCollection(Collection<?> c) {for (Object e : c) {
System.out.println(e);}
} printCollection(new ArrayList<String>()); Okay.
Generic Wildcards, Cont.
• Wildcards seemed to be powerful, but..– You cannot add elements to a collection declared using
wildcards, except ‘null’!• On the other hand, given a List<?>, we can call get() and
make use of the result.• The result type is an unknown type, but we always know that it
is an object.• You won’t be able to extract no thing but Object from a
collection declared using wild cards.
1: Collection<?> c = new ArrayList<String>();2: c.add(new Object());3: c.add(null);
1: Collection<?> c = new ArrayList<String>();2: c.add(new Object());3: c.add(null);
1. Error at line 1: Cannot instantiate unknown collection
2. Error at line 2: Cannot add to an unknown collection
3. Warninig at line 3: adding null to a collection is useless
Bounded Wildcard• To restrict access to specific type of
objects, you can bound the generic parameter:– Ex: Stricting access to numbers
• Double getAvg(Collection<? extends Number> col) { }
– Will accept any collection of any subclass of Number (Including Number it self)
• Remember the solution:– Double getAvg(Collection<Number> col) {} will not
work, as it is expecting a List<Number> and it will not accept List<Float> for example
Generic Wildcards, Cont.
• The same restriction exists, you still can’t add values inside a collection declared using ‘?’.
1: void doSomeThing(Collection <? extends Number> col)2: {
...4: Col.add(new Number());5: }
1: void doSomeThing(Collection <? extends Number> col)2: {
...4: Col.add(new Number());5: }
1. Error at line 4: Method add is not applicable for type ‘Number’
2. Success: 0 errors, 0 warnings
Generic methods• Consider writing a method that takes an array of
objects and a collection and puts all objects in the array into the collection.– It won’t work with Collection <?>– It will be tedious to use Collection <Object>
• Solution, is to make that method a generic method as well.– <E> Collection<E> arrayToCollection(E [] elems,Collection
<E> col) { for(E x : elems){
col.add(x);return col;
}}
Generic methods, Cont.• We should now ask, When to use generic wildcards
and when to use generic method.– Use generic method in the following situations
1. Generic parameter appeared in more than one parameter1. <T> compare (List<T> a, List<T> b)
2. Generic parameter used as a return type1. <T extends Comparable > T getMin (Collection <T> col)
– Generally:• Generic methods allow type parameters to be used to express
dependencies among the types of one or more arguments to a method and/or its return type.
• If there isn’t such a dependency, a generic method should not be used.
• It is a sign to use wild card if the generic argument appeared only once in the method signature or body
– <T> void printAll (Collection <T> x) == void printAll (Collection <?> x)
static void overloadedMethod ( Object o) { System.out.println(" overloadedMethod (Object) called");}static void overloadedMethod( String s) { System.out.println(" overloadedMethod ( String) called ");}static void overloadedMethod ( Integer i) { System.out.println(" overloadedMethod ( Integer) called ");}
static <T> void genericMethod(T t) { overloadedMethod (t) ; // which method is called? }
public static void main(String[] args) { genericMethod ( "abc" ); }
static void overloadedMethod ( Object o) { System.out.println(" overloadedMethod (Object) called");}static void overloadedMethod( String s) { System.out.println(" overloadedMethod ( String) called ");}static void overloadedMethod ( Integer i) { System.out.println(" overloadedMethod ( Integer) called ");}
static <T> void genericMethod(T t) { overloadedMethod (t) ; // which method is called? }
public static void main(String[] args) { genericMethod ( "abc" ); }
• Output:
• overloadedMethod (Object) called
• overloadedMethod ( String) called
• overloadedMethod ( Integer) called
Interoperating with Legacy Code-1
void doSomeThing1(Collection col){
...}1: public static void main(String []args)2: {3: doSomeThing1(new ArrayList<String>());4: }
void doSomeThing1(Collection col){
...}1: public static void main(String []args)2: {3: doSomeThing1(new ArrayList<String>());4: }
• Interoperating with legacy code was taken into consideration, you still can pass a generic collection to a methods that expects row collection safly
• Line 3:
• Error: Cannot pass a generic collection as row collection
• Warning: Passing generic collection as row collection is not type safe
• Success: 0 errors, 0 warnings
Interoperating with Legacy Code-2
<T> void doSomeThing1(Collection <T> col){
...}void doSomeThing2(Collection <?> col){
...}1: public static void main(String []args)2: {3: doSomeThing1(new ArrayList());4: doSomeThing2(new ArrayList());5: }
<T> void doSomeThing1(Collection <T> col){
...}void doSomeThing2(Collection <?> col){
...}1: public static void main(String []args)2: {3: doSomeThing1(new ArrayList());4: doSomeThing2(new ArrayList());5: }
• Line 3:
• Error: Cannot pass a row collection as generic
• Warning: Passing row collection as generic is not type safe
• Success: 0 errors, 0 warnings
• Passing a row collection to a method that expect generic collection will issue a type safety warning.
• Warning disappear when using wildcards
• Line 4:
• Error: Cannot pass a row collection as generic
• Warning: Passing row collection as generic is not type safe
• Success: 0 errors, 0 warnings
More on Generics• More than one generic type:
– <X,Y, Z> void myMethod (X a, Y b, Z c);
• The use of more than one upper bound– void myMethod (Collection <T extends A &
B>)
• The use of lower bound– void myMethod (Collection <? super T>)
• Explicitly inferring generic type– Collections.<String> unmodifiableSet(set);
Generics support in Eclipse 3.1
• Quick Fix features
• Quick fix suggest a solution
• Refactor Infer Generic Type Argument…
Generics support in Eclipse 3.1
• Old Code:
• Updated code
• List empList = new ArrayList (5); empList.add(new Employee("Homer", 200.0, 1995));empList.add(new Employee("Lenny", 300.0, 2000));empList.add(new Employee("Waylon", 700.0, 1965)); empList.add(new Manager("Monty", 2000.0, 1933, empList.get(2)));
• List empList = new ArrayList (5); empList.add(new Employee("Homer", 200.0, 1995));empList.add(new Employee("Lenny", 300.0, 2000));empList.add(new Employee("Waylon", 700.0, 1965)); empList.add(new Manager("Monty", 2000.0, 1933, empList.get(2)));
• List<Employee> empList = new ArrayList<Employee>(5); empList.add(new Employee("Homer", 200.0, 1995));empList.add(new Employee("Lenny", 300.0, 2000));empList.add(new Employee("Waylon", 700.0, 1965)); empList.add(new Manager("Monty", 2000.0, 1933, empList.get(2)));
• List<Employee> empList = new ArrayList<Employee>(5); empList.add(new Employee("Homer", 200.0, 1995));empList.add(new Employee("Lenny", 300.0, 2000));empList.add(new Employee("Waylon", 700.0, 1965)); empList.add(new Manager("Monty", 2000.0, 1933, empList.get(2)));
Generics support in Eclipse 3.1
• Eclipse has gotten smart about finding generic references
• The filter menu of the search window allows you to filter generics-aware results
Limitations1: class AClass<T> extends T {
2: private static Collection<T> myCol2;
3: Private static T myMethod() {}
4: public static void aMethod(Object arg) {
5: if(arg instanceof T) {}
6: T var = new T();
7: T[] array = new T[100];
8: T[] array = (T)new Object[SIZE];
9: ArrayList x = new ArrayList<int>();
10: List <String> [] s = new ArrayList <String> [9];
11: Collection<?> c = new ArrayList<String>();
12: c.add(new Object());
13: class MyList implements MyCollection<Integer>,
14: MyCollection <Double>
{
}
}
}
1: class AClass<T> extends T {
2: private static Collection<T> myCol2;
3: Private static T myMethod() {}
4: public static void aMethod(Object arg) {
5: if(arg instanceof T) {}
6: T var = new T();
7: T[] array = new T[100];
8: T[] array = (T)new Object[SIZE];
9: ArrayList x = new ArrayList<int>();
10: List <String> [] s = new ArrayList <String> [9];
11: Collection<?> c = new ArrayList<String>();
12: c.add(new Object());
13: class MyList implements MyCollection<Integer>,
14: MyCollection <Double>
{
}
}
}
Legend:Legend: SuccessSuccess WarningWarning ErrorError
People’s opinion…• “Generics are probably the most long awaited addition to the
Java language. “ Neal Ford – Application Architect• “Why do we have erasure?, They prevent ClassCastExceptions.
How big of a problem is this, versus the overhead of (1) learning and (2) maintaining the code of the new syntax of the feature “Bruce Eckel ,Author of “Thinking in Java”, Here
• “Generics Considered Harmful” , same source, Here
• “Generics are a mistake. ”, Ken Arnold, the creator of Jini, JavaSpaces, Curses, and Rogue , Here
• “it's not the idea of generics that is the problem, but the implementation ”, Same source
Conclusion• Generics were developed to provide type-
safety. • They accomplish that goal to a certain
degree. However, they don’t provide type-safety to the full extent. This is largely due to the design goals and implementation constraints.
• First learn Generics in Java. Then have the wisdom to decide when and how (much) to use it.
References
• Sun Microsystems Generic tutorialhttp://java.sun.com/j2se/1.5/pdf/generics-tutorial.pdf