Transcript Document

EG-JUG
Java 1.5 Generics
Amr Ali
Software Engineer, IBM-Egypt
Versions of Java
Oak: Designed for embedded devices
Java: Original, not very good version (but
it had applets)
pre-Java
Java 1
JDK 1.1: Adds inner classes and a completely new
event-handling model
JDK 1.2: Includes “Swing” but no new syntax
JDK 1.3: Additional methods and packages, but no
new syntax
JDK 1.4: More additions and the assert statement
Java 2
JDK 1.5: Generics, enums, new for loop,
and other new syntax
Java 5.0
Java 5 overview
1.
2.
3.
4.
5.
6.
7.
8.
Generics
Auto Boxing and Un-boxing
Enhanced for-loop
Enumerations
Annotation
Variable arguments
Static imports
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.
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);
}
Method
Mehtod
Indicates
“add”
‘get’
a generic
returns
accept
parameter
object
class declaration
ofof
type
type
‘E’‘E’
A dog in the cat collection!
Animal
Animal
Collection < Animal >
Dog
Cat
Collection < Cat >
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
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);
1.
Error at line 15: Cannot convert from list<String> to list <Object>
•
Java compiler will prevent any action
2. Error at line 16: Cannot add objects to list of Strings
may
violate
type
safety
3. that
Error at line
17: Type
mismatch, the
trying to
Pop Object
as String 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>) ...
Generic Wildcards
Printing contents of any generic collection:
void printCollection(Collection<Object> c) {
void printCollection(Collection<?> c) {
for
for (Object
(Object ee :: c)
c) {{
System.out.println(e);
System.out.println(e);
}}
}}
 printCollection(new ArrayList<String>());  Okay.
 printCollection(new ArrayList<String>());
Will accept only list of Objects
• Error
: Cannot pass ArrayList<String> as ArrayList<Object>
• Warning : Passing ArrayList<String> as ArrayList<Object> is not type safe
To accept any type of collection regardless its generic
• Success : 0 errors, 0 warnings
type, use “Collection<?> c” notation, means c is a
collection of unknown type.
Generic Wildcards, Cont.
1: Collection<?> c = new ArrayList<String>();
2: c.add(new Object());
3: c.add(null);
• Wildcards seemed to be powerful, but..
– You cannot add elements to a collection declared using wildcards,
1. except
Error at‘null’!
line 1: Cannot instantiate unknown collection
• 2.
On the
other
hand,
given aadd
List<?>,
we
can callcollection
get() and make use of
Error
at
line
2:
Cannot
to
an
unknown
the result.
• 3.
TheWarninig
result type
is an3:unknown
type,
we always
that it is an
at line
adding null
tobut
a collection
is know
useless
object.
• You won’t be able to extract no thing but Object from a collection
declared using wild cards.
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.
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’
• The same restriction exists, you still can’t
2. Success: 0 errors, 0 warnings
add values inside a collection declared using
‘?’.
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 parameter
1. <T> compare (List<T> a, List<T> b)
2.
Generic parameter used as a return type
1. <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" );
}
•
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: }
•
Line 3:
• Interoperating
with legacy code was taken
• Error: Cannot pass a generic collection as row collection
into
consideration,
you still
can
passisanot type
• Warning:
Passing generic collection
as row
collection
safe
generic
collection to a methods that expects
• Success:
0 errors, 0safly
warnings
row
collection
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: }
•
Line 4:
3:
• Passing
a row collection to a method that expect
• Error: Cannot pass a row collection as generic
generic collection will issue a type safety warning.
• Warning: Passing row collection as generic is not type safe
• Warning
disappear when using wildcards
• 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
Generics support in Eclipse 3.1
• Refactor  Infer Generic Type Argument…
Generics support in Eclipse 3.1
• Old 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)));
• Updated code
•
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)));
• Eclipse has gotten smart about finding generic references
• The filter menu of the search window allows you to filter generics-aware results
Limitations
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:
Success
Warning
Error
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 typesafety.
• 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 tutorial
http://java.sun.com/j2se/1.5/pdf/g
enerics-tutorial.pdf