Indice

Alcune novità rispetto a java 1.4

PREV Introduzione a java generics NEXT Subtyping & wildcards

FIXME Pagina in costruzione. Questa pagina è una rielaborazione, fatta prevalentemente di copia&incolla, delle slide relative ai generics disponibili sulla pagina dedicata.

Cominciamo

Generics e Collections vanno a braccetto con altre nuove feature (introdotte da Java5):

La loro combinazione è sinergica: l'intero è maggiore della somma delle parti!

Versione "cool"

List<Integer> ints = Arrays.asList(1,2,3);
int s = 0;
for (int n : ints) {
s += n;
}
assert s == 6;

Probabilmente il codice è comprensibile anche senza alcuna spiegazione …

List<Integer> ints =
Arrays.asList(1,2,3);
for (int n : ints) {
s += n;
}
assert s == 6;

Versione old fashion

List ints = Arrays.asList(new Integer [] {
new Integer(1),
new Integer(2),
new Integer(3) }
);
int s = 0 ;
for (Iterator it = ints.iterator() ; it.hasNext() ; ){
int n = ((Integer)it.next()).intValue();
s += n;
}
assert(s == 6);

Generics: Base

Una classe o interfaccia può dichiarare di ricevere uno o più parametri di tipo:

List <String> words = new ArrayList<String>();
words.add("Hello ");
words.add("world !");
String s = words.get(0) + words.get(1);
assert s.equals("Hello world !");

Codice senza l'ausilio dei generics …

List words = new ArrayList();
words.ADD("Hello ");
words.ADD("world !");
String s = (String)words.get(0) + (String)words.get(1);
assert s.equals("Hello world !");

Type erasure

Il bytecode compilato dei due precedenti esempi è (grossomodo) identico → retro compatibilità. I generics sono implementati tramite la type erasure

compile timerun time
List<Integer> List
List<String> List
List<List<String» List

I generics eseguono implicitamente il cast che deve essere esplicitato nella versione senza generics

Cast-iron guarantee: I cast impliciti aggiunti dalla compilazione dei generics non falliscono mai!(*) (*) si applica esclusivamente al caso in cui non vengano inviati dal compilatore dei “unchecked warnings”

Type erasure, come mai?

Generics VS C++ Template

JavaC++
List<List<String» List< List<String> > (con lo spazio!) :-(
Type erasure: una sola versione della classe Expansion: n versioni della solita classe; una per ogni tipo definito a compile-time → code bloat :-( (?ottimizzazioni?)

Tipi reference

Tipi primitivi

8 tipi primitivi hanno un corrispondente “tipo reference” nel package java.lang

Primitivo Reference
byte Byte
short Short
int Integer
long Long
float Float
double Double
bool Boolean
char Character

Boxing e unboxing

Boxing → conversione da primitivo a reference

Unboxing → conversione da reference a primitivo

La conversione viene fatta in automatico

int e → new Integer(e) // boxing
Integer e → e.intValue() // unboxing

Esempi

// OK
public static int somma(List<Integer> ints){
int s = 0;
for ( int n :ints) { s += n ; }
return s;
}
//Troppe conversioni! Performance :-(
public static Integer sommaInteger(List<Integer> ints)
{
Integer s = 0;
for ( int n :ints) { s += n ; }
return s;
}

Binary Numeric Promotion

Se uno degli operandi è un reference type viene applicato l'unboxing. Poi

Si applica a vari operatori binari ( tra cui == )

Pericolo boxing/uboxing

:!: Per i primitivi == signifca “uguaglianza dei valori”

:!: Per i reference == signifca “stessa identità”

L ist<Integer> bigs =
Arrays.asList(100,200,300);
assert sommaInteger(bigs) == somma(bigs);
assert sommaInteger(bigs) !=
sommaInteger(bigs); // non raccomandato

I generics funzionano solo con i reference

:!: Interi da -128 a 127, caratteri da 0 a \u007f, Byte e Boolean possono essere cachati

List<Integer> smalls = Arrays.asList(1,2,3);
assert sommaInteger(smalls)
  == somma(smalls);// 6
assert sommaInteger(smalls)
  == sommaInteger(smalls); // 6, non raccomandato

:!: Posso assegnare null ad un primitivo? → NO

Due paroline sul ciclo foreach

For (Pippo p: pippi) …

int[] ints = {1,2,3,4};
for (Integer i :ints)
System.out.println(i);

Metodi generici

class Lists {
public static <T> List<T> toList(T[] arr){
List<T> list = new ArrayList<T>();
for (T elem: arr) list.add(elem);
return list;
}
...
List<Integer> ints = Lists.toList(
new Integer[] {1,2,3});
List<String> strings = Lists.toList(
new String[] {"ciao","mondo"});

Boxing e unboxing gratuiti!

Varargs

Che noia inserire gli elementi nell'array!

public static <T> List<T> toList(T ... arr){
List<T> list = new ArrayList<T>();
for (T elem: arr) list.add(elem);
return list;
}
...
List<Integer> ints = Lists.toList( 1,2,2);
List<String> strings = Lists.toList( "ciao","mondo");

Abbiamo sostituito

Qualsiasi numero di argomenti può precedere il vararg, niente deve seguire il vararg

:!: Attenzione! Il tipo T non viene sempre dedotto dal compilatore, a volte è necessario esplicitarlo

Lists.<Object>toList( 1,"mondo");

Non è detto che Integer e String abbiano in comune solo Object! (Serializable, Comprarable, …)

Asserzioni

Possono essere abilitate tramite i fag della JVM -ea o -enableassertions Altrimenti stanno a dormire …

NEXT Subtyping & wildcards