Survey
* Your assessment is very important for improving the workof artificial intelligence, which forms the content of this project
* Your assessment is very important for improving the workof artificial intelligence, which forms the content of this project
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