Thursday, 16 October 2014

Generics

'Generics' let you enforce type safety on Collection, classes and methods.

Eg.
List<String> stringsList = new ArrayList<String>();
stringsList.add("hello");// Ok

stringsList.add("salut"); // Ok

stringsList.add(new Integer(2)); // This won't compile: type safety


Backward compatibility.


Because generics have been introduced since Java 5, you can use, for example, a Collection without specifying a type. The code will compile and run, with however a compilation warning. Eg.
 List mixedList = new ArrayList<String>(); // This is legal!

 mixedList.add("hello");

 mixedList.add("salut");

 mixedList.add(new Integer(2)); // This time it will compile



 for(Object anElement : mixedList){

 System.out.println("- element: "+anElement.toString());

 }
During the compilation, the following warning is displayed: "Note: TestGeneric.java uses unchecked or unsafe operations."

But the code compiles and runs fine, the output is:
- element: hello
- element: salut
- element: 2

You can also pass a typed Collection to a non typed collection as argument: Eg.
// Non typed Collection
 public static void test(List mixedList){ 

 mixedList.add(new Integer(2)); // Ok

 }

 ...



 List mixedList = new ArrayList<String>();

 mixedList.add("hello");

 mixedList.add("salut");

 test(mixedList);



 for(Object anElement : mixedList){

 System.out.println("- element: "+anElement.toString());

 }
During the compilation, a warning is displayed: "Note: TestGeneric.java uses unchecked or unsafe operations."

Output:
- element: hello
- element: salut
- element: 2

Polymorphic declaration.


Note that with generics you can not use a polymorphic declaration. Eg.
 class Animal {}

 class Dog extends Animal {}

 

 List<Animal>animals = new ArrayList<Animal>(); // Ok

 List<Animal> animals = new ArrayList<Dog>(); // This won't compile: "incompatible types"

 Animal[] animals = new Dog[3]; // This works with array but not with generics

Note that this rule does not avoid you adding a 'Dog' in a list of 'Animal':
 List<Animal>animals = new ArrayList<Animal>(); // Ok

 animals.add(new Animal()); // Ok

 animals.add(new Dog()); // Ok, as 'Dog' IS-AN 'Animal'

Usage of wildcard '?' with a collection


If you use generic wildcard '?' with a collection then the collection can be accessed but not modified.

Example of <? extends [className]> :
 public static void testWildcardExtends(List<? extends Animal> animalsList){

 animalsList.get(0); // Ok

 animalsList.add(new Dog()); // This won't compile: "cannot find symbol" => you are not allowed to modify this collection because of the usage of wildcard '?'

 }

 ...



 List<Dog> dogsList = new ArrayList<Dog>();

 dogsList.add(new Dog());

 testWildcardExtends(dogsList); // Ok as 'Dog' is an 'Animal'


Example of <? super [className]> :
 public static void testWildcardSuper(List<? super Dog> animalsList){

 animalsList.get(0); // Ok

 animalsList.add(new Animal()); // This won't compile: "cannot find symbol" => you are not allowed to modify this collection because of the usage of wildcard '?'

 }

 ...



 List<Animal> animalsList = new ArrayList<Animal>();

 animalsList.add(new Animal());

 testWildcardSuper(animalsList); // Ok as 'Animal' is a superclass of 'Dog'


Example of <?> :
 public static void testWildcardOnly(List<?> aList){

 aList.get(0); // Ok

 aList.add(new Animal()); // This won't compile: "cannot find symbol" => you are not allowed to modify this collection because of the usage of wildcard '?'

 }

 ...



 List<Animal> animalsList = new ArrayList<Animal>();

 animalsList.add(new Animal());

 testWildcardOnly(animalsList); // Ok, you can pass any type of collection



 List<Integer> intsList = new ArrayList<Integer>();

 intsList.add(new Integer(87));

 testWildcardOnly(intsList); // Ok, you can pass any type of collection


You can use wildcare in declaration as well. But the limitation is the same: the collection can not be modified:
 List<?> aList = new ArrayList<Animal>(); // Ok

 List<? extends Animal> dogList = new ArrayList<Dog>(); // Ok

 List<? super Dog> animalList = new ArrayList<Animal>(); // Ok

Write a generic class


Eg.
 class MyGenericClass <AType> { // Note that you can also use wildcare ? or many types like <AType1, AType2>, or <? extends AType>, or <? super AType>

 

 private List<AType> typesList;

 

 MyGenericClass(){

 this.typesList = new ArrayList<AType>();

 }

 

 public void add(AType aType){

 this.typesList.add(aType);

 }

 

 public String toString(){

 String toReturn = "";

 for(AType anElement : this.typesList){

 toReturn += "\n- element: "+anElement;

 }

 return toReturn;

 }

 

 }

Let's use the generic class:
 MyGenericClass<String> aGeneric = new MyGenericClass<String>(); // "AType" is now a "String"

 aGeneric.add("hello");

 aGeneric.add("salut");

 System.out.println("Elements: "+aGeneric.toString());

Output:
Elements:
- element: hello
- element: salut

Write a generic method in a non generic class


You can declare one or many generic methods in a non generic class. Eg.
 class MyClass { // This is a simple class (non generic)



 public <AType> void printType(AType aType) { // You can notice that the generic declaration <AType> is just before the method's return type void;

 System.out.println("Element: "+aType); // As for a generic class, you can also use wildcare or many types like <AType1, AType2>, or <? extends AType>, or <? super AType>

 }



 public void doSomething() { // Non generic method

 }

 

 }
Let's use the generic method:
 MyClass myClass = new MyClass();

 myClass.printType(new Integer(40)); // AType is now an Integer
Output:
Element: 40