j2se 5: l’evoluzione di java -...
TRANSCRIPT
1
J2SE 5: l’evoluzione di JavaLuca Ferrari 1/188
Luca Ferrari,Dipartimento di Ingegneria dell’Informazione
Università di Modena e Reggio [email protected] - http://agentgroup.unimo.it
Seminario del corso diLinguaggi per la Programmazione ad Oggetti
(prof. Giacomo Cabri)
20 Dicembre 2004
J2SE 5:l’evoluzione di Java
J2SE 5: l’evoluzione di JavaLuca Ferrari 2/188
ArgomentiStoria
(da OAK a J2SE 5)
Novità sintattiche
(boxing, foreach, varargs, static import, enum, output formattato)
Novità semantiche
(generics, annotazioni, tipo di ritorno variabili)
Classi aggiunte o modificate
(Swing, StackTraceElement, InetAdress, Management Factory, …)
Varie
(Pack200, Ergonomics, …)
Risorse
2
J2SE 5: l’evoluzione di JavaLuca Ferrari 3/188
Storia
J2SE 5: l’evoluzione di JavaLuca Ferrari 4/188
Da Oak…
Java nasce nella prima metà degli anni ’90 nei laboratori della Sun Microsystems.
L’idea di base viene da Jasmes Gosling, che nel Dicembre ’90 guida, assieme a Patrick Naughton e Mike Sheridan un gruppo di programmatori nel progetto green. Ne scaturisce OAK (1992), un linguaggio ad oggetti innovativo:
“Oak is a programming language looselyrelated to C++. It originated
in a project to produce a software development environment for small
distributed embedded systems.”da “Oak Intermediate Bytecodes”, J.Gosling, ACM Sigplan 95
Oak verrà poi ribattezzato Java, e nel 1995 viene rilasciata la prima versione.
3
J2SE 5: l’evoluzione di JavaLuca Ferrari 5/188
… a TigerNel 2004, dopo 3 anni di lavoro e due versioni beta, il JDK 1.5.0 viene rilasciato.“It took us close to three years to deliver Tiger, so one lesson welearned is that we were a little too ambitious and we should
probably have to put in a little less and shipped it a little sooner.”(Graham Hamilton,
Java Platform Team Fellow)
Il progetto, denominato Tiger, rappresenta l’upgrade con il numero di innovazioni maggiori nella storia di Java.
J2SE 5: l’evoluzione di JavaLuca Ferrari 6/188
Che nome ha?Java 5 non esiste!
La piattaforma Java è ancora alla versione 2, la versione del linguaggio è la 5.Il nome corretto è: J2SE 5 (J2EE 5).
4
J2SE 5: l’evoluzione di JavaLuca Ferrari 7/188
Architettura di Java 2
J2SE 5: l’evoluzione di JavaLuca Ferrari 8/188
Ma come nasce una nuova versione?
La SUN ha adottato un sistema chiamato Java Community Process (JCP), attivo da circa 5 anni.
Gli utenti sottomettono delle idee (JSR - Java Specification Requirement), che vengono poi eventualmente discusse, formalizzate, accettate ed implementate.
Alcuni esempi:� JSR 014 (generics)� JSR 175 (annotazioni)� JSR 201 (foreach, autoboxing, enumeration,…)� JSR 163 (JVM Profiling API – JVMTI)
5
J2SE 5: l’evoluzione di JavaLuca Ferrari 9/188
Siamo rimasti indietro!J2SE 6 (Mustang) è disponibile per il
download!
Si tratta in realtà di daily-snapshots, piuttosto instabili e inutili, a meno che non si sia code developers o beta testers(o curiosi).
Si parla già di J2SE 7 (Dolphin)!
J2SE 5: l’evoluzione di JavaLuca Ferrari 10/188
ArgomentiStoria
(da OAK a J2SE 5)
Novità sintattiche
(boxing, foreach, varargs, static import, enum, output formattato)
Novità semantiche
(generics, annotazioni, tipo di ritorno variabili)
Classi aggiunte o modificate
(Swing, StackTraceElement, InetAdress, Management Factory, …)
Varie
(Pack200, Ergonomics, …)
Risorse
6
J2SE 5: l’evoluzione di JavaLuca Ferrari 11/188
Autoboxing-Outboxing
J2SE 5: l’evoluzione di JavaLuca Ferrari 12/188
Le classi wrapperJava non è un linguaggio completamente ad oggetti.
I tipi primitivi (int, float, double, …) non sono oggetti!
Per supportare la gestione dei tipi primitivi uniformemente a quella degli altri oggetti, fin da Java 1 sono presenti delle classi wrapper.
7
J2SE 5: l’evoluzione di JavaLuca Ferrari 13/188
Le classi wrapperL’utilizzo delle classi wrapper risulta scomodo il più delle volte:
Vector v = new Vector();
int i = 10;
...
Integer iObject = new Integer(i);
v.add(iObject);
...
iObject = (Integer)v.get(0);
i = iObject.intValue();
J2SE 5: l’evoluzione di JavaLuca Ferrari 14/188
Autoboxing - OutboxingOra è possibile utilizzare direttamente uno scalare in un contesto di oggetto, lasciando che sia il compilatore a gestire il wrapping del tipo primitivo:
Vector v = new Vector(10);
for(int i=0;i<5;i++){v.add(i);v.add(((float)i)*2.5);
}
for(int i=0;i<v.size();i++){System.out.println(i+"="+
v.elementAt(i));}
0=01=0.02=13=2.54=25=5.06=37=7.58=49=10.0
output di esecuzione
8
J2SE 5: l’evoluzione di JavaLuca Ferrari 15/188
foreach
J2SE 5: l’evoluzione di JavaLuca Ferrari 16/188
foreachE’ ora supportato il ciclo foreach tramite una sintassi particolare di for:
for( variable_type variable_name : list )
Un ciclo foreach consente di scorrere tutti gli elementi di una lista (ad esempio un array) gestendo automaticamente l’incremento di eventuali indici e l’assegnamento della variabile di ciclo all’elemento successivo.
9
J2SE 5: l’evoluzione di JavaLuca Ferrari 17/188
foreach: esempiopublic class foreach{
public static void main(String argv[]){String array[] = new String[10];for(int i=0;i<array.length;i++){
array[i] =new String("Stringa n."+i);
}
//utilizzo del foreachfor(String s: array){
System.out.println(s);}
}}
Stringa n.0
Stringa n.1
Stringa n.2
Stringa n.3
Stringa n.4
Stringa n.5
Stringa n.6
Stringa n.7
Stringa n.8
Stringa n.9
output di esecuzione
J2SE 5: l’evoluzione di JavaLuca Ferrari 18/188
foreach: lavorare con strutture datiimport java.util.Vector;public class foreach2{
public static void main(String argv[]){Vector v = new Vector(10);
for(int i=0;i<10;i++){v.add("String n."+i);
}
// uso il foreach// ATTENZIONE: uso di object!for(Object s: v){
System.out.println(s);}
}}
ATTENZIONE: si deve usare un Object perché un Vector memorizza (e restituisce) Object.
foreach non può effettuare i cast automaticamente! Il problema può essere risolto con generics.
10
J2SE 5: l’evoluzione di JavaLuca Ferrari 19/188
foreach solo per estrazioniforeach non può essere usato come ciclo di assegnamento, ma solo di estrazione:
public static void main(String argv[]){
String array[] = new String[10];
for(String s: array){
s = "CIAO";
}
for(String s:array){
System.out.println(s);
}
}
null
null
null
null
null
null
null
null
null
null
output di esecuzione
J2SE 5: l’evoluzione di JavaLuca Ferrari 20/188
foreach: considerazioniTutto il lavoro “sporco” viene svolto dal compilatore.
Non si ha accesso all’indice numerico della lista (non si è a conoscenza della posizione dell’elemento corrente).
Riduce il rischio di errori banali, come indici fuori dai limiti o cicli annidati sulla stessa variabile.
Non è stata introdotta una parola chiave foreach(come in Perl, C-shell,…) per rispetto al legacy-code.
11
J2SE 5: l’evoluzione di JavaLuca Ferrari 21/188
Preparare una classe per foreach
Affinché una collezione di dati sia utilizzabile in un ciclo foreach, occorre che l’interfaccia Iterable sia implementata.
J2SE 5: l’evoluzione di JavaLuca Ferrari 22/188
foreach: una nota di demeritoL’implementazione di foreach non è null-safe (al contrario di Perl):
String array[]=null;
for(String s:array){
System.out.println(s);
} String array[]=null;
for(int i=0;i<array.length;i++){
String s = array[i];
System.out.println(s);
}
NullPointerException
12
J2SE 5: l’evoluzione di JavaLuca Ferrari 23/188
foreach: una nota di demeritoUna implementazione più sicura sarebbe stata:
String arr []=null;
for(String s:arr){
System.out.println(s);
} String arr []=null;
for(int i=0;arr!=null && i<arr.length;i++){
String s = array[i];
System.out.println(s);
}
J2SE 5: l’evoluzione di JavaLuca Ferrari 24/188
varargs
13
J2SE 5: l’evoluzione di JavaLuca Ferrari 25/188
varargsE’ ora possibile definire metodi che accettino un numero variabile di argomenti.
Gli argomenti devono avere tutti lo stesso tipo, al limite Object (che equivale a “tutti i tipi possibili”).
La sintassi prevede l’uso dell’operatore … fra il tipo e il nome associato all’argomento.
Simile al concetto di variadic in C/C++, si pensi alla printf(..).
J2SE 5: l’evoluzione di JavaLuca Ferrari 26/188
varargs: esempiopublic class varargs {
public void mvar(String...pars){for(int i=0;i<pars.length;i++){
System.out.println("Parametro "+i+" = "+pars[i]);
}}
public static void main(String argv[]){varargs v = new varargs();v.mvar(“ALFA",“BETA",“GAMMA");
}
}
L’argomento di una funzione varargs è
tramutato automaticamente in
un array.
14
J2SE 5: l’evoluzione di JavaLuca Ferrari 27/188
varargs: esempio equivalentepublic class varargs {
public void mvar(String...pars){// uso il foreachfor(String s: pars){
System.out.println(s);}
}
public static void main(String argv[]){varargs v = new varargs();v.mvar(“ALFA",“BETA",“GAMMA");
}
}
J2SE 5: l’evoluzione di JavaLuca Ferrari 28/188
varargs: output degli esempi
Parametro 0 = ALFA
Parametro 1 = BETA
Parametro 2 = GAMMA
output di esecuzione
ALFA
BETA
GAMMA
output di esecuzione
Versione con ciclo fornormale
Versione con ciclo foreach
15
J2SE 5: l’evoluzione di JavaLuca Ferrari 29/188
OverloadE’ possibile sovraccaricare un metodo varargs con una lista di argomenti dello stesso tipo.
Verrà eseguito per primo il metodo il cui prototipo corrisponde perfettamente all’invocazione!
J2SE 5: l’evoluzione di JavaLuca Ferrari 30/188
Overload: esempiopublic class varargs {public void mvar(String...pars){for(int i=0;i<pars.length;i++){
System.out.println("Parametro "+i+" = "+pars[i]);}
}
public void mvar(Object...pars){for(Object o: pars){
System.out.println("Parametro di tipo:“+o.getClass());}}
public void mvar(String s1, String s2){System.out.println("stringhe "+s1+" "+s2);}
v.mvar(“ALFA",“BETA",“GAMMA");
v.mvar("Stringa1","Stringa2");
v.mvar(new Object(), new Integer(10));
16
J2SE 5: l’evoluzione di JavaLuca Ferrari 31/188
Overload: arraySiccome il compilatore tratta i metodi varargs come metodi ad array, il sovraccarico con un array viene impedito:public class varargs {
public void mvar(String...pars){...}
public void mvar(String[] pars){
for(String s:pars){
System.out.println("String array: "+s);
}
}
}varargs.java:31: mvar(java.lang.String...) is already defined influca.varargs
public void mvar(String[] pars){
output di compilazione
J2SE 5: l’evoluzione di JavaLuca Ferrari 32/188
Single-type import
17
J2SE 5: l’evoluzione di JavaLuca Ferrari 33/188
Import StaticiL’operatore import ha ora una granularità più fine, consentendo l’unione di spazi dei nomi composti anche da soli membri, purché statici.
In altre parole, ora è possibile importare la porzione statica di una classe, utilizzandone i membri (statici) come se fossero stati dichiarati nella classe corrente.
Ciò risulta molto comodo per l’utilizzo di costanti o metodi di servizio generale, entrambi dichiarati appunto come membri statici.
J2SE 5: l’evoluzione di JavaLuca Ferrari 34/188
La nuova sintassi di importLa nuova sintassi dell’operatore import risulta ora essere la seguente:
� import package_name.class_name;
Importa la classe class_name nello spazio dei nomi corrente.
� import package_name.*;
Importa tutte le classi (*) del package package_name nello spazio dei nomi corrente.� import static package_name.class_name.member;
Importa il membro statico member della classe class_namenello spazio dei nomi corrente.� import static package_name.class_name.*;
Importa ogni membro statico della classe class_namenello spazio dei nomi corrente.
18
J2SE 5: l’evoluzione di JavaLuca Ferrari 35/188
Esempio: una classe di costantipackage fluca;
public class Constants {// definizione di una serie di membri staticipublic final static String costante1 =
"Vietato Fumare";public final static int costante2 = 30;public final static boolean costante3 = false;
public static void stampa_costanti(){System.out.println("Metodo stampa_caratteristiche");System.out.println("==>\tcostante1="+costante1);System.out.println("==>\tcostante2="+costante2);System.out.println("==>\tcostante3="+costante3);
}}
J2SE 5: l’evoluzione di JavaLuca Ferrari 36/188
Esempio: utilizzo di alcune costantipackage seminario_20;
import static fluca.Constants.costante1;import static fluca.Constants.costante2;
public class Main {
public static void main(String[] args) {
System.out.println("costante1="+costante1);
System.out.println("costante2="+costante2);
}
}
costante1=Vietato Fumarecostante2=30
output di esecuzione
19
J2SE 5: l’evoluzione di JavaLuca Ferrari 37/188
Esempio: utilizzo di alcune costantipackage seminario_20;
import static fluca.Constants.costante1;import static fluca.Constants.costante2;
public class Main {
public static void main(String[] args) {
System.out.println("costante1="+costante1);
System.out.println("costante2="+costante2);
System.out.println(“costante3=“+costante3);
}
} L’utilizzo di un membro statico non importato esplicitamente produce un errore di compilazione
Cannot find symbol:symbol : variable costante3location: class seminario_20.Main
System.out.println("costante3="+costante3);
output di compilazione
J2SE 5: l’evoluzione di JavaLuca Ferrari 38/188
Esempio: utilizzo di alcune costantipackage seminario_20;
import static fluca.Constants.costante1;import static fluca.Constants.costante2;
import static fluca.Constants.costante3;
public class Main {
public static void main(String[] args) {
System.out.println("costante1="+costante1);
System.out.println("costante2="+costante2);
System.out.println(“costante3=“+costante3);
}
}
costante1=Vietato Fumarecostante2=30costante3=false
output di esecuzione
20
J2SE 5: l’evoluzione di JavaLuca Ferrari 39/188
Esempio: importazione di metodipackage seminario_20;
import static fluca.Constants.stampa_caratteristiche;
public class Main {
public static void main(String[] args) {
System.out.println("Invoco il metodo
importato!");
stampa_caratteristiche();
}
}
Invoco il metodo importato!Metodo stampa_caratteristiche
==> costante1=Vietato Fumare==> costante2=30==> costante3=false
output di esecuzione
J2SE 5: l’evoluzione di JavaLuca Ferrari 40/188
ConflittiNel caso di membri omonimi possono nascere dei conflitti.
Se si importano membri omonimi (anche se di tipo differente) da classi diverse, nasce un errore di compilazione.
Se si importano membri omonimi di quelli definiti nella classe corrente, questi ultimi prevaricano (nascondono) quelli importati.
21
J2SE 5: l’evoluzione di JavaLuca Ferrari 41/188
Conflitti: errore di compilazionepackage seminario_20;
import static fluca.Constants.costante1;
import static fluca.Constants2.costante1;
public class Main {
public static void main(String[] args) {
System.out.println("costante1="+costante1);
}
}
Settings\luca\seminario_20\src\fluca\Constants2.java:15:<identifier> expected
public static float costante1 = 6,9;__input:8: costante1 is already defined in a single-type import(source unavailable)
output di compilazione
J2SE 5: l’evoluzione di JavaLuca Ferrari 42/188
Conflitti: prevaricamento a run-timeimport static fluca.Constants.costante1;
import static fluca.Constants.stampa_costanti;
public class Main {
public static int costante1 = 10;
public static void stampa_costanti(){
System.out.println("Nulla da stampare!");
}
public static void main(String[] args) {
System.out.println("costante1="+costante1);
stampa_costanti();
}
} costante1=10Nulla da stampare!
output di esecuzione
22
J2SE 5: l’evoluzione di JavaLuca Ferrari 43/188
enum
J2SE 5: l’evoluzione di JavaLuca Ferrari 44/188
EnumerazioniE’ stata aggiunta la parola chiave enum, che consente di definire enumerazioni on the fly.
Un’utilizzo classico è come lista static di valori.
Si presti attenzione a non confondere una enumerazione
con una serie di costanti. Seppur simili, una serie di costanti
acquisisce importanza in base al valore che si attribuisce alle stesse,
mentre una enumerazione ha importanza solo al fine di distinguere gli
elementi nella lista.
23
J2SE 5: l’evoluzione di JavaLuca Ferrari 45/188
Enumerazioni: esempiopackage seminario_20.enumerazioni;
public class EventType{
public static enum type {
OPEN,
CLOSE,
EXIT,
};
}
J2SE 5: l’evoluzione di JavaLuca Ferrari 46/188
Enumerazioni: esempiopackage seminario_20.enumerazioni;
public class Main1{
// metodo che accetta un valore enumeratopublic void fireEvent(EventType.type event){
System.out.println("L'evento ricevuto e'");
if(event == EventType.type.OPEN)System.out.println("APERTURA");
elseif(event == EventType.type.CLOSE)
System.out.println("CHIUSURA");elseif(event == EventType.type.EXIT)
System.out.println("USCITA");}
24
J2SE 5: l’evoluzione di JavaLuca Ferrari 47/188
Enumerazioni: esempiopublic static void main(String argv[]){
Main1 m = new Main1();m.fireEvent(EventType.type.OPEN);m.fireEvent(EventType.type.CLOSE);
System.out.println("Come risulta stampato? -->“+EventType.type.OPEN);
}}
L'evento ricevuto e'
APERTURA
L'evento ricevuto e'
CHIUSURA
Come risulta stampato? -->OPEN
output di esecuzione
J2SE 5: l’evoluzione di JavaLuca Ferrari 48/188
ConsiderazioniLe enumerazioni sono trattate come oggetti:
luca@linux:~/tmp/j1.5/seminario_20/enumerazioni> ls -l
total 36
-rw-r--r-- 1 luca users 306 2004-12-09 13:52 EventType.class
-rw-r--r-- 1 luca users 121 2004-12-09 13:52 EventType.java
-rw-r--r-- 1 luca users 1251 2004-12-09 13:52 EventType$type.class
-rw-r--r-- 1 luca users 1200 2004-12-09 14:09 Main1.class
-rw-r--r-- 1 luca users 629 2004-12-09 14:09 Main1.java
L’enumerazione viene trattata come inner class.
25
J2SE 5: l’evoluzione di JavaLuca Ferrari 49/188
Che tipo di oggetto è un’enumerazione?public void fireEvent(EventType.type event){
...// analizzo la classe dell'eventoClass clazz = event.getClass();System.out.println("Nome della classe di evento: “
+clazz.getName());for(Field f: clazz.getFields()){
System.out.println("Campo: "+f.getName());System.out.println("\t visibilita': ");int modificatore = f.getModifiers();if(Modifier.isPublic(modificatore)){
System.out.println("\tpubblico");}else if(Modifier.isPrivate(modificatore)){
System.out.println("\tprivato");}
}}
J2SE 5: l’evoluzione di JavaLuca Ferrari 50/188
Che tipo di oggetto è un’enumerazione?
Nome della classe di evento:seminario_20.enumerazioni.EventType$type
Campo: OPEN
visibilita':
pubblico
Campo: CLOSE
visibilita':
pubblico
Campo: EXIT
visibilita':
pubblico
output di esecuzione
26
J2SE 5: l’evoluzione di JavaLuca Ferrari 51/188
Output Formattato
J2SE 5: l’evoluzione di JavaLuca Ferrari 52/188
L’output formattatoLe classi di output su stream (ad es. PrintStream) di Java hanno il pregio di avere un utilizzo molto semplice ed immediato, ma non consentono un elevato controllo sull’output effettivo.
Altri linguaggi, come ad esempio il C/C++ consentono un accurato controllo dell’output mediante l’uso delle funzioni appartenenti alla famiglia printf.
27
J2SE 5: l’evoluzione di JavaLuca Ferrari 53/188
Differenze fra i metodi Java e printfI metodi println(..) di un PrintStream Java sono i più usati per l’output formattato su stream. Le differenze fra tali metodi e la printf(..) del C/C++ sono le seguenti:� printf è una funzione variadic, println no;� printf richiede come primo argomento una stringa di formato, seguita dai parametri da convertire in stringa. println consente di inserire il parametro da stampare direttamente nella posizione in cui deve essere stampato (utilizzo dell’operatore + su stringa);� printf ha una implementazione unica indipendentemente dal tipo e numero di argomenti che deve gestire, println è sovraccaricato per ogni lista di parametri differente;� printf consente di specificare la lunghezza dei valori, println richiede l’utilizzo di operazioni di substringing.
J2SE 5: l’evoluzione di JavaLuca Ferrari 54/188
Il ritorno della printfPer sopperire alle lacune di formattazione, alcune classi di libreria sono state estese: String, PrintWriter e PrintStream hanno acquisito ciascuna i seguenti metodi (varargs):
format(String format, Object... args);
printf(String format, Object... args);
format(Locale locale, String format,Object... args);
printf(Locale locale, String format,
Object... args);
28
J2SE 5: l’evoluzione di JavaLuca Ferrari 55/188
Esempio: printfpublic class Main {
public static void main(String[] args) {int v1 = 10;float v2 = (float)3.69;String v3 = "Ciao";System.out.printf("valori: v1=%d v2=%f
v3=%s\n",v1,v2,v3);
String s = String.format("valori: v1=%d v2=%fv3=%s",v1,v2,v3);
System.out.println(s);}
}
valori: v1=10 v2=3,690000 v3=Ciaovalori: v1=10 v2=3,690000 v3=Ciao
output di esecuzione
J2SE 5: l’evoluzione di JavaLuca Ferrari 56/188
ArgomentiStoria
(da OAK a J2SE 5)
Novità sintattiche
(boxing, foreach, varargs, static import, enum, output formattato)
Novità semantiche
(generics, annotazioni, tipo di ritorno variabili)
Classi aggiunte o modificate
(Swing, StackTraceElement, InetAdress, Management Factory, …)
Varie
(Pack200, Ergonomics, …)
Risorse
29
J2SE 5: l’evoluzione di JavaLuca Ferrari 57/188
Generics
J2SE 5: l’evoluzione di JavaLuca Ferrari 58/188
type-safeProblema: garantire a compile time la coerenza dei dati di una collezione.
Il problema, noto come “type-safe”, richiede la capacità di usare strutture ed algoritmi generali specializzandoli al volo.
Non è banale!
Il controllo di tipo avviene sicuramente a run-time, ma potrebbe essere troppo tardi!
30
J2SE 5: l’evoluzione di JavaLuca Ferrari 59/188
Quando la conformità può creare problemi…
Mediante la conformità è possibile usare le sottoclassi come fossero classi base.
Ciò produce indubbi vantaggi, consentendo di utilizzare lo stesso algoritmo per tutte le classi derivate.
Si pensi ad esempio alle strutture dati Java (ad es. Vector), che sono progettate per accettare qualunque tipo di oggetto…
La conformità può creare problemi di type-safe.
J2SE 5: l’evoluzione di JavaLuca Ferrari 60/188
Un esempio concretoLa soluzione si ha usando i tipi parametrizzati (chiamati in Java generics).Per meglio comprendere, si farà uso del seguente esempio:
� si dispone di due tipi di persone: studenti e professori;� si deve costruire un archivio capace di contenere sia studenti che professori;� l’archivio deve essere omogeneo (non si devono mischiare professori con studenti e vice versa).
31
J2SE 5: l’evoluzione di JavaLuca Ferrari 61/188
Un esempio concreto: implementazione della gerarchia
Studenti e professori sono accomunati dal fatto di essere entrambi persone; inoltre si deve costruire una logica uguale per entrambe le specializzazioni.
Ciò porta alla realizzazione di un legame fra studenti e professori:
una gerarchia!
Persona
Professore Studente
J2SE 5: l’evoluzione di JavaLuca Ferrari 62/188
Un esempio concreto: implementazione della gerarchia
package seminario_20.generics;
public class Persona {
protected String nome, cognome;
protected int eta;
public Persona(String nome, String cognome,
int eta){this.nome = nome;
this.cognome = cognome;
this.eta = eta;
}
Persona
Professore Studente
32
J2SE 5: l’evoluzione di JavaLuca Ferrari 63/188
Un esempio concreto: implementazione della gerarchiapublic String toString(){
return nome+" "+cognome+" "+eta;}
} // fine della classe Persona
Persona
Professore Studente
J2SE 5: l’evoluzione di JavaLuca Ferrari 64/188
Un esempio concreto: implementazione della gerarchia
package seminario_20.generics;
public class Professore extends Persona{
public Professore(String nome,
String cognome,
int eta) {
super(nome,cognome,eta);
}
public String toString(){
return nome+" "+cognome+" "+eta+
" - professore";
}
}Persona
Professore Studente
33
J2SE 5: l’evoluzione di JavaLuca Ferrari 65/188
Un esempio concreto: implementazione della gerarchia
package seminario_20.generics;
public class Studente extends Persona{
public Studente(String nome,
String cognome,
int eta) {
super(nome,cognome,eta);
}
}
Persona
Professore Studente
J2SE 5: l’evoluzione di JavaLuca Ferrari 66/188
Un esempio concreto: l’implementazione dell’archivio
package seminario_20.generics;import java.util.Vector;public class Archivio1 {
protected Vector persone;
public Archivio1() {persone = new Vector(10);
}
public void aggiungi(Persona p){persone.add(p);
}
public void rimuovi(Persona p){persone.remove(p);
}
34
J2SE 5: l’evoluzione di JavaLuca Ferrari 67/188
public Persona get(int index){return (Persona)persone.get(index);
}
public int size(){return persone.size();
}
} // fine della classe Archivio1
Un esempio concreto: l’implementazione dell’archivio
J2SE 5: l’evoluzione di JavaLuca Ferrari 68/188
Il problema di Archivio1La classe Archivio1 gestisce (con una sola logica) tutti i tipi Persona; ciò può provocare type-unsafety.In altre parole non vi è nessun meccanismo che controlli il tipo (specifico) dei dati inseriti/rimossi dall’archivio.
Cosa ancora più importante: le incoerenze non possono essere rilevate a tempo di
compilazione !(si ricordi che Studente e Professore sono sottoclassi di Persona)
35
J2SE 5: l’evoluzione di JavaLuca Ferrari 69/188
Un utilizzo scorrettopublic static void main(String argv[]){
// creazione di studenti e professoriStudente s1 =
new Studente("Luca","Ferrari",26);Studente s2 =
new Studente("Santi","Caballe",29);Studente s3 =
new Studente("James","Gosling",50);Professore pr1 =
new Professore("Silvia","Rossi",27);Professore pr2 =
new Professore("Simon","Ritter", 40);
// creazione di due archivi separatiArchivio1 archivio_prof = new Archivio1();Archivio1 archivio_stud = new Archivio1();
J2SE 5: l’evoluzione di JavaLuca Ferrari 70/188
Un utilizzo scorretto// aggiungo i prof e gli studenti ai relativi// archiviarchivio_prof.aggiungi(pr1);archivio_prof.aggiungi(pr2);archivio_prof.aggiungi(s1);
archivio_stud.aggiungi(s1);archivio_stud.aggiungi(s2);archivio_stud.aggiungi(s3);archivio_stud.aggiungi(pr1);
Disastro imminente!
Disastro imminente!
Oggetti di tipo incoerente sono stati aggiunti agli archivi. Il compilatore e il sistema run-time non possono rilevare
questo errore di logica, essendo l’archivio basato sulla superclasse dei tipi realmente utilizzati.
36
J2SE 5: l’evoluzione di JavaLuca Ferrari 71/188
Un utilizzo scorretto
// stampa professorifor(int i=0;i<archivio_prof.size();i++){
Professore pTemp =(Professore)archivio_prof.get(i);
System.out.println("Professore "+i+" "+pTemp);
}
// stampa studentifor(int i=0;i<archivio_stud.size();i++){
Studente sTemp =(Studente)archivio_stud.get(i);
System.out.println("Studente "+i+" "+sTemp);
}} // fine del metodo main
J2SE 5: l’evoluzione di JavaLuca Ferrari 72/188
Un utilizzo scorretto
Professore 0 Silvia Rossi 27 – professore
Professore 1 Simon Ritter 40 - professore
Exception in thread "main“ java.lang.ClassCastException:
seminario_20.generics.Studente
at seminario_20.generics.Main1.main(Main1.java:32)
output di esecuzione
Il problema risiede nel cast fatto al momento dell’estrazione dall’archivio:Professore pTemp = (Professore)archivio_prof.get(i);
L’assunzione è corretta: l’archivio dei professori (studenti) dovrebbe contenere solo professori (studenti), quindi il cast esplicito è lecito.
37
J2SE 5: l’evoluzione di JavaLuca Ferrari 73/188
Possibili soluzioni (in ordine di disperazione)
1. realizzare una forma di archivio specifica per ogni tipo di dato presente.Ad esempio, realizzando un archivio che accetti come dato un Professore, non si potrà correre il rischio di inserirvi uno Studente.
Questa soluzione risulta valida nel breve termine, ma non accettabile nel lungo periodo, essendo incapace di gestire correttamente il code refactoring. Ogni volta che un nuovo tipo viene inserito, un nuovo archivio deve essere implementato.
Persona
Professore Studente
Tecnico
J2SE 5: l’evoluzione di JavaLuca Ferrari 74/188
Possibili soluzioni (in ordine di disperazione)
2. utilizzare interfacce differenti per ogni archivio.Definendo una interfaccia per ogni archivio, e “costringendo” l’archivio ad implementarle entrambe, si ottiene una soluzione molto ObjectOriented, abbastanza sicura e sicuramente flessibile, al costo di una minima aggiunta di codice.
38
J2SE 5: l’evoluzione di JavaLuca Ferrari 75/188
Possibili soluzioni (in ordine di disperazione)
2. utilizzare interfacce differenti per ogni archivio.
public inteface archivio_studenti{
public void aggiungi(Studente s);
...
}
public interface archivio_professori{
public void aggiungi(Professore p);
}
public class Archivio
implements archivio_studenti, archivio_professori
{...}
J2SE 5: l’evoluzione di JavaLuca Ferrari 76/188
Possibili soluzioni (in ordine di disperazione)
2. utilizzare interfacce differenti per ogni archivio.
I problemi di questa soluzione:a) è potenzialmente non type-safe, essendo
comunque possibile scavalcare le interfacce per lavorare direttamente sull’archivio;
b) come per la soluzione precedente, ogni volta che un nuovo tipo viene aggiunto, l’archivio deve essere modificato di conseguenza.
39
J2SE 5: l’evoluzione di JavaLuca Ferrari 77/188
Possibili soluzioni (in ordine di disperazione)
3. fornire un parametro all’archivio che imponga il tipo di istanza da gestire.
public Archivio1(Class clazz){
this.managedType = clazz;
}
public void aggiungi_persona(Persona p) throws Exception{
if( managedType != null &&
(p.getClass()!= managedType ) ){
throw new Exception(“Tipo sbagliato”);
}
// inserimento dell’argomento…
}
Anticipa ciò che avviene a run-timeper un cast incorretto!
J2SE 5: l’evoluzione di JavaLuca Ferrari 78/188
Possibili soluzioni (in ordine di disperazione)
4. eliminare la gerarchia.
Non è una soluzione Object Oriented!
Produce la scrittura di molto codice in più.
40
J2SE 5: l’evoluzione di JavaLuca Ferrari 79/188
GenericsE’ ora possibile un controllo accurato sui tipi a tempo di compilazione, ma le strutture dati devono essere progettate come tipi parametrici(generics).
Una classe che sfrutti generics non ha un tipo di dato predefinito, ma lo riceve a tempo di istanziazione.
J2SE 5: l’evoluzione di JavaLuca Ferrari 80/188
GenericsIn altre parole, con generics, è possibile costruire classi con algoritmi standard e capaci di agire su più tipi di dati, ma in modo coerente.
“From the perspective of both software engineering and programming pedagogy, Java has a crude type system. Its mostsignificant failing is the lack of support for generic types.”
(Erica Allen, Safe Instantiation in Generic Java,
PPPJ 2004)
La sintassi di generics fa uso delle parentesi angolari (<,>) per indicare un tipo da specificare in seguito.
41
J2SE 5: l’evoluzione di JavaLuca Ferrari 81/188
Usando generics…package seminario_20.generics;import java.util.Vector;
public class Archivio2<E> {protected Vector persone;
public Archivio2() {persone = new Vector(10);
}
public void aggiungi(E p){persone.add(p);
}
public void rimuovi(E p){persone.remove(p);
}
Con questa dichiarazione si
indica che l’identificatore E fa riferimento ad un
tipo di dato che sarà specificato nel
codice che userà Archivio2.
I metodi ora fanno riferimento a
variabili di tipo E.
J2SE 5: l’evoluzione di JavaLuca Ferrari 82/188
Usando generics…
public E get(int index){return (E)persone.get(index);
}
public int size(){return persone.size();
}
} // fine della classe Archivio2
42
J2SE 5: l’evoluzione di JavaLuca Ferrari 83/188
public static void main(String argv[]){...
Archivio2<Professore> archivio_prof =new Archivio2<Professore>();
Archivio2<Studente> archivio_stud =new Archivio2<Studente>();
Archivio2<Persona> archivio_per =new Archivio2<Persona>();
archivio_prof.aggiungi(pr1);archivio_prof.aggiungi(pr2);archivio_prof.aggiungi(s1);...
}
Usando generics…
Main2.java:34: aggiungi(seminario_20.generics.Studente) inseminario_20.generics.Archivio2<seminario_20.generics.Studente>cannot be applied to (seminario_20.generics.Professore)
output di compilazione
J2SE 5: l’evoluzione di JavaLuca Ferrari 84/188
I vantaggi di genericsLe incoerenze di tipo sono rilevate a tempo di compilazione, e non a tempo di esecuzione, aiutando il programmatore nel trovare errori di logica.
Si noti che generics non impedisce di usare la gerarchia mischiando i tipi, ma semplicemente richiede che si sia coscienti di ciò che si sta facendo:Archivio2<Persona> archivio_per =
new Archivio2<Persona>();
43
J2SE 5: l’evoluzione di JavaLuca Ferrari 85/188
WildcardsGenerics ammette l’uso del carattere ‘?’ come speciale wildcard, con i seguenti significati:
� <?> indica tutti i tipi della classe cui si fa riferimento. Ad esempio Archivio2<?> indica sia Archivio2<Studente> che Archivio2<Professore>;� <? extends type> indica tutti i tipi che ereditano da type. Ad esempio Archivio2<? extendsPersona> indica tutti i tipi di Archivio2parametrizzati da Persona;� <? super type> simile al caso precedente, ma tratta superclassi.
J2SE 5: l’evoluzione di JavaLuca Ferrari 86/188
Specializzare una classe con generics
E’ possibile ereditare da una classe e aggiungere, nel contempo, il supporto a generics, facendo però attenzione affinché i metodi non siano in conflitto.
package seminario_20.generics;
public class Archivio3<E> extends Archivio1{
public void aggiungiElement(E p){
persone.add(p);
}
...
}
ATTENZIONE: si ricordi che Studente (Professore) è anche Persona, quindi un metodo aggungi(E p)
potrebbe andare in conflitto con Archivio1#aggiungi(Persona p) qualora il tipo sia
ancora una Persona.
44
J2SE 5: l’evoluzione di JavaLuca Ferrari 87/188
Cosa c’è dietro a genericsLa magia di generics risiede nel nuovo sistema di compilazione.
Il compilatore effettua ora alcuni passi di manipolazione sintattica (type erasurers) al fine di forzare eventuali errori di casting.
J2SE 5: l’evoluzione di JavaLuca Ferrari 88/188
Generics in azione: codice utilizzatoIl tag di generics viene rimosso, e il codice viene compilato sostituendo al tipo parametrico Object.
public class Archivio2<E> {
protected Vector persone;
public Archivio2() {
persone = new Vector(10);
}
public void aggiungi(E p){
persone.add(p);
}
public void rimuovi(E p){
persone.remove(p);
}
public class Archivio2 {
protected Vector persone;
public Archivio2() {
persone = new Vector(10);
}
public void aggiungi(Object p){
persone.add(p);
}
public void rimuovi(Object p){
persone.remove(p);
}
45
J2SE 5: l’evoluzione di JavaLuca Ferrari 89/188
Generics in azione: codice utilizzatoreIl compilatore rimuove i tag di generics, e “forza” dei cast.
public static void main(String argv[]){...
Archivio2<Professore> archivio_prof =new Archivio2<Professore>();
Archivio2<Studente> archivio_stud =new Archivio2<Studente>();
Archivio2<Persona> archivio_per =new Archivio2<Persona>();
archivio_prof.aggiungi(pr1);archivio_prof.aggiungi(pr2);archivio_prof.aggiungi(s1);...
}
public static void main(String argv[]){...
Archivio2 archivio_prof =new Archivio2 ();
Archivio2 archivio_stud =new Archivio2 ();
Archivio2 archivio_per =new Archivio2 ();
archivio_prof.aggiungi((Professore)pr1);archivio_prof.aggiungi((Professore)pr2);archivio_prof.aggiungi((Professore)s1);...
}
J2SE 5: l’evoluzione di JavaLuca Ferrari 90/188
Generics e il resto del mondoLa libreria Java supporta appieno generics:public static void main(String argv[]){
Vector<String> vettore = new Vector<String>();
for(int i=0;i<10;i++){
vettore.add(new String("stringa n."+i));
}
for(String s: vettore){
System.out.println(s);
}
}
Quando usato con generics, foreach lavora sul tipo di dato corretto!
46
J2SE 5: l’evoluzione di JavaLuca Ferrari 91/188
Ma non tutto è generics!Se si tenta di utilizzare una classe “normale” come fosse generics, si ottiene un errore di compilazione.
Archivio1<Professore> = new Archivio1<Professore>();
Main4.java:15: not a statement
Archivio1<Professore> = new Archivio1<Professore>();
Main4.java:15: ';' expected
Archivio1<Professore> = new Archivio1<Professore>();
output di compilazione
J2SE 5: l’evoluzione di JavaLuca Ferrari 92/188
Il rovescio della medagliaGenerics consente di usare un algoritmo generico in type-safe, ma per impostazione predefinita non impedisce di usare l’algoritmo per istanze diverse da quelle per cui questo è stato progettato (cosa impedita dalla conformità)!
Archivio2<String> = new Archivio2<String>();
La ragione di ciò risiede nel modo in cui la classe sottoposta a generics viene compilata: tutti gli identificatori sono sostituiti con Object.
E’ possibile limitare i tipi utilizzabili!
47
J2SE 5: l’evoluzione di JavaLuca Ferrari 93/188
Limitare l’uso dei tipipublic class Archivio2<E extends Persona>{…}
Se a questo punto si tenta di creare un archivio con un tipo sbagliato, si ottiene un errore di compilazione.
Archivio2<String> archivio_stud =
new Archivio2<String>();
seminario_20\generics\Main9.java:13: type parameterjava.lang.String is not within its bound
Archivio2<String> archivio_stud =
new Archivio2<String>();
output di compilazione
J2SE 5: l’evoluzione di JavaLuca Ferrari 94/188
Generics non implica relazioni!Tutte le istanze create in modo parametrizzato condividono la stessa classe.
Archivio2<Persona> aPersona = …
Archivio2<Studente> aStudente = …
Non sono in relazione! (anche se Studente eredita da Persona)
48
J2SE 5: l’evoluzione di JavaLuca Ferrari 95/188
Generics extends GenericsE’ possibile estendere una classe che fa uso di generics, la sottoclasse può a sua volta fare uso di generics.
Valgono tutte le regole dell’ereditarietà (es. overriding)!
Esempio: estendere l’archivio visto in precedenza (Archivio2) in modo che possa memorizzare associazioni Studente-Professore in type-safe.
J2SE 5: l’evoluzione di JavaLuca Ferrari 96/188
Esempiopackage seminario_20.generics;import java.util.Hashtable;
public class Archivio5<E,R> extends Archivio2<E>{// relazioniprotected Hashtable relazioni;
public Archivio5(){super();relazioni = new Hashtable();
}
public void aggiungiRelazione(E p1, R p2){relazioni.put(p1,p2);
}
49
J2SE 5: l’evoluzione di JavaLuca Ferrari 97/188
Esempiopublic void stampaRelazioni(){
Enumeration<E> chiavi = relazioni.keys();
while(chiavi.hasMoreElements()){E chiave = chiavi.nextElement();System.out.println("Relazione "+chiave+" - “
+relazioni.get(chiave));}
}
}
J2SE 5: l’evoluzione di JavaLuca Ferrari 98/188
Esempio: utilizzopackage seminario_20.generics;
public class Main5{public static void main(String argv[]){
Studente s1 =new Studente("Luca","Ferrari",26);
Studente s2 =new Studente("Santi","Caballe",29);
Studente s3 =new Studente("James","Gosling",50);
Professore pr1 =new Professore("Silvia","Rossi",37);
Professore pr2 =new Professore("S.","Ritter", 40);
50
J2SE 5: l’evoluzione di JavaLuca Ferrari 99/188
Esempio: utilizzoArchivio5<Studente,Professore> archivio =
new Archivio5<Studente,Professore>();
archivio.aggiungi(s1);archivio.aggiungi(s2);archivio.aggiungi(s3);
archivio.aggiungiRelazione(s1,pr1);archivio.aggiungiRelazione(s2,pr2);
archivio.stampaRelazioni();}
} // fine della classe
Relazione Luca Ferrari 26 - Silvia Rossi 37 - professore
Relazione Santi Caballe 29 – S. Ritter 40 - professore
output di esecuzione
J2SE 5: l’evoluzione di JavaLuca Ferrari 100/188
Considerazioni sull’esempio� E’ possibile utilizzare generics con più di un tipo di parametro:public class Archivio5<E,R> extends Archivio2<E>{...}
Archivio5<Studente,Professore> archivio = new
Archivio5<Studente,Professore>();
� Il type-safe è garantito:archivio.aggiungi(pr1);
archivio.aggiungiRelazione(pr1,s1);
seminario_20/generics/Main5.java:17: aggiungi(seminario_20.generics.Studente) inseminario_20.generics.Archivio2<seminario_20.generics.Studente> cannot be appliedto (seminario_20.generics.Professore)
archivio.aggiungi(pr1);
^
seminario_20/generics/Main5.java:20:aggiungiRelazione(seminario_20.generics.Studente,seminario_20.generics.Professore)inseminario_20.generics.Archivio5<seminario_20.generics.Studente,seminario_20.generics.Professore> cannot be applied to(seminario_20.generics.Professore,seminario_20.generics.Studente)
archivio.aggiungiRelazione(pr1,s1);
output di compilazione
51
J2SE 5: l’evoluzione di JavaLuca Ferrari 101/188
Templates? No grazie!Anche se molto simili nella sintassi e nell’utilizzo, i Java generics non sono la stessa cosa dei template C++.
I template C++ si riconducono a macro del preprocessore, che producono il codice sorgente di una nuova classe con i tipi “fissati”.
Generics opera a livello di compilatore e non “sporca” il codice della classe che si sta utilizzando.
Generics è un modo di concepire e scrivere software!
J2SE 5: l’evoluzione di JavaLuca Ferrari 102/188
General PurposeAnnotations
52
J2SE 5: l’evoluzione di JavaLuca Ferrari 103/188
AnnotazioniUna annotazione è un’informazione associata ad un frammento di codice.
Le annotazioni non cambiano direttamente la semantica del codice cui sono applicate, ma influenzano l’esecuzione di strumenti che utilizzano tale codice (e quindi ne modificano la semantica!).
J2SE 5: l’evoluzione di JavaLuca Ferrari 104/188
Annotazioni in JavaJava supporta le annotazioni fin dalla versione 1.0.
Esempi di annotazioni sono:� transient: indica al sistema di serializzazione di non salvare su stream il campo� i tag javadoc (@param, @since, …)
Quindi cosa c’è di nuovo?
53
J2SE 5: l’evoluzione di JavaLuca Ferrari 105/188
Annotazioni in JavaGli esempi di annotazioni di prima sono specifici per un solo scopo (serializzazione, documentazione,…).
E’ ora possibile realizzare annotazioni general purpose, utilizzabili in diversi contesti e per scopi differenti.
Ciò aumenta le possibilità di gestione del codice, semplificando lo sviluppo in team, l’analisi del codice, la realizzazione di regression-test, …
J2SE 5: l’evoluzione di JavaLuca Ferrari 106/188
Era necessario?Prima dell’avvento di J2SE 5, era comunque possibile usare annotazioni general purpose.
Si dovevano però utilizzare file di proprietà, file XML (deployment) o altro,costringendo i programmatori a far fronte a sistemi eterogenei.
Ora è possibile realizzare annotazioni in Java, creare librerie di annotazioni,….
54
J2SE 5: l’evoluzione di JavaLuca Ferrari 107/188
Quindi un’annotazione Java è� una classe che contiene membri descrittivi (note); � associabile a membri Java (classi, metodi, variabili) senza influenzarne il comportamento;� associabile ad una fase di vita del codice (compilazione, esecuzione);� analizzabile da altro codice Java (eventualmente tramite reflection).
J2SE 5: l’evoluzione di JavaLuca Ferrari 108/188
Annotazioni Java: definizioneUna annotazione viene definita in modo
simile ad una interfaccia.
La definizione di una annotazione prevede che:
1. vi si riferisca facendo precedere il carattere ‘@’ alla parola interface;
2. non vi siano variabili;3. vi siano metodi senza corpo, con valori
di ritorno standard (int, boolean, String, …);
55
J2SE 5: l’evoluzione di JavaLuca Ferrari 109/188
Esempio di definizioneDefinizione di una annotazione che contenga versione, note, autore di un frammento di codice.
Occorre quindi definire una annotazione con i seguenti membri (metodi che fungono da campi!):� nota, di tipo String� stabile, di tipo boolean, indica se il codice è da considerarsi stabile o affetto da bug� ultimo_autore, di tipo String, il nome dell’ultimo autore� versione, di tipo int
J2SE 5: l’evoluzione di JavaLuca Ferrari 110/188
Esempio di definizioneimport java.lang.annotation.*;
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
public @interface Check {
int versione(); // numero di versione
boolean stabile(); // ha dei bug?
String nota(); // nota di testo
String ultimo_autore(); // ultimo autore
}
Package introdotto per le annotazioni.
Indicano a che “istante di vita” si
applica l’annotazione (RUNTIME) e a che
elementi (METHOD).Una interfaccia speciale!
Simili a metodi astratti (niente corpo).
56
J2SE 5: l’evoluzione di JavaLuca Ferrari 111/188
Alcune note sulla definizioneLe annotazione possono essere annotate!
Una annotazione che ne annota un’altra è dette meta-annotazione. Alcuni esempi sono:
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
J2SE 5: l’evoluzione di JavaLuca Ferrari 112/188
Utilizzo di una annotazioneLe regole per l’utilizzo di una annotazione sono:� alla ”creazione”, vi si riferisce con il nome dato preceduto dal carattere ‘@’;� il valore dei membri (rappresentati dai metodi!) sono assegnati mediante sintassi
nome = valore
� l’utilizzo avviene tramite cast esplicito (come per un normale oggetto); i valori dell’annotazione sono estratti invocando i metodi definiti.
57
J2SE 5: l’evoluzione di JavaLuca Ferrari 113/188
Utilizzo di una annotazionepublic class Test {
@Check(versione=1, stabile=true,nota="Tutto ok!", ultimo_autore="Luca Ferrari")
public void metodo1(){...}
@Check(versione=1, stabile=false,nota="Array index out of bounds!",ultimo_autore="Luca Ferrari")
public void metodo2(){...}
@Check(versione=1, stabile=false,nota="Tutto ok!",ultimo_autore="Giacomo Cabri")
public void metodo3(){...}}
J2SE 5: l’evoluzione di JavaLuca Ferrari 114/188
E adesso?Fino a questo punto abbiamo definito una annotazione e l’abbiamo inserita in una normale classe Java.
Utilizzando la classe Test non noteremmo nessuna differenza, occorre scrivere del codice che analizzi le annotazioni.
Esempio: Un analizzatore che indichi quali metodi sono instabili e chi è il colpevole!
58
J2SE 5: l’evoluzione di JavaLuca Ferrari 115/188
Analizzare le annotazionipublic static void main(String argv[]){// ottengo tutti i metodi di TestMethod metodi[] = Test.class.getMethods();// utilizzo foreachfor(Method m: metodi){
// questo metodo ha almeno un’annotazione?if(m.isAnnotationPresent(Check.class)){
// prelevo tutte le annotazioni del metodoAnnotation annotazioni[] = m.getAnnotations();// so che le annotazioni sono Check!for(Annotation a: annotazioni){
Check c = (Check)a;// è codice instabile?if(c.stabile()==false){System.out.println("ATTENZIONE:”+m.getName());System.out.println(“ultimo autore: “
+c.ultimo_autore());}
}}}}
J2SE 5: l’evoluzione di JavaLuca Ferrari 116/188
Il risultato
Si noti che si usano i dati annotati tramite chiamate a metodi; anche l’annotazione stessa è trattata come un oggetto normale!
Si presti attenzione alle classi usate!
ATTENZIONE: metodo2
ultimo autore: Luca Ferrari
ATTENZIONE: metodo3
ultimo autore: Giacomo Cabri
output di esecuzione
59
J2SE 5: l’evoluzione di JavaLuca Ferrari 117/188
Tipi di annotazioniLe annotazioni sono suddivisibili in:1. Marker annotation – sono annotazioni
“vuote” (senza variabili);2. Single-value annotation – annotazioni
con un solo campo (tipicamente value);3. Full annotation – annotazioni
complesse (come nell’esempio precedente).
Nel caso di single-value, se il campo è value, il suo nome può essere omesso da un assegnamento:
@myAnnotation(value=“Luca Ferrari”)
@myAnnotation(“Luca Ferrari”)
J2SE 5: l’evoluzione di JavaLuca Ferrari 118/188
Annotazioni baseJ2SE 5 fornisce alcune annotazioni di base (built-in annotations):
1. @Override – utilizzabile solo per i metodi, indica che il metodo in questione sta ridefinendo un metodo della classe base.
2. @Deprecated – utilizzabile solo per i metodi, indica che il metodo annotato non dovrebbe essere più usato.
3. @SuppressWarnings – disabilita i messaggi di warning del compilatore.
4. @Inherited – (meta annotation) forza una annotazione anche nelle sottoclassi della classe cui quest’ultima è applicata.
60
J2SE 5: l’evoluzione di JavaLuca Ferrari 119/188
Annotazioni base5. @Retention – (meta annotation) indica a quale
istante di vita del codice l’annotazione deve essere applicata. I valori possibili sono:� RetentionPolicy.SOURCE // no JVM e compiler� RetentionPolicy.CLASS // solo compiler� RetentionPolicy.RUNTIME // solo JVM
6. @Target – (meta annotation) indica a quale porzione di codice una annotazione si riferisce. I valori possibili sono:� ElementType.TYPE // class, interface, enum
� ElementType.FIELD // field
� ElementType.METHOD // method� ElementType.PARAMETER // method parameter� ElementType.CONSTRUCTOR // constructor
� ElementType.LOCAL_VARIABLE // anche catch
� ElementType.ANNOTATION_TYPE // meta annotation
� ElementType.PACKAGE // package
J2SE 5: l’evoluzione di JavaLuca Ferrari 120/188
Utilizzo di più annotazioniSi supponga di voler creare un’annotazione che contenga le informazioni sulla persona che gestisce un pezzo di codice.
package seminario_20.annotazioni;
import java.lang.annotation.*;
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
public @interface Check2 {
String assegnato_a();
}
61
J2SE 5: l’evoluzione di JavaLuca Ferrari 121/188
Utilizzo di più annotazionipublic class Test {
@Check(versione=1, stabile=true,nota="Tutto ok!", ultimo_autore="Luca Ferrari")
public void metodo1(){...}
@Check(versione=1, stabile=false,nota="Array index out of bounds!",ultimo_autore="Luca Ferrari")
public void metodo2(){...}
@Check(versione=1, stabile=false,nota="Tutto ok!",ultimo_autore="Giacomo Cabri")
@Check2(assegnato_a = “Luca Ferrari”)public void metodo3(){...}
}
J2SE 5: l’evoluzione di JavaLuca Ferrari 122/188
Method metodi[] = Test.class.getMethods(); // ottengo tutti i metodifor(Method m: metodi){
if(m.isAnnotationPresent(Check.class)){Annotation annotazioni[] = m.getAnnotations();for(Annotation a: annotazioni){
System.out.println("Annotazione "+a);if(a instanceof Check){
Check c = (Check)a;if(c.stabile()==false){
System.out.println("ATTENZIONE: il metodo “+m.getName());
System.out.println("è instabile.");System.out.println("Ultimo autore: “
+c.ultimo_autore());}
}else if(a instanceof Check2){Check2 c2 = (Check2)a;System.out.println("Assegnato a: "+c2.assegnato_a());
}}
}}
Utilizzo di più annotazioni
62
J2SE 5: l’evoluzione di JavaLuca Ferrari 123/188
Valori di defaultTramite la parola chiave default, è possibile assegnare un valore iniziale ad un campo di una annotazione.
package seminario_20.annotazioni;
import java.lang.annotation.*;
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
public @interface Check3{
boolean testato() default false;
}
J2SE 5: l’evoluzione di JavaLuca Ferrari 124/188
Valori di default: esempiopublic class Test {
@Check(versione=1, stabile=true,nota="Tutto ok!", ultimo_autore="Luca Ferrari")
public void metodo1(){...}
@Check(versione=1, stabile=false,nota="Array index out of bounds!",ultimo_autore="Luca Ferrari")
@Check3(testato=“true”)public void metodo2(){...}
@Check(versione=1, stabile=false,nota="Tutto ok!",ultimo_autore="Giacomo Cabri")
@Check2(assegnato_a = “Luca Ferrari”)@Check3()public void metodo3(){...}
}
testato = false
63
J2SE 5: l’evoluzione di JavaLuca Ferrari 125/188
Valori di default: esempiopublic static void main(String argv[]){
Test test = new Test();// ottengo tutti i metodi di TestMethod metodi[] = Test.class.getMethods();for(Method m: metodi){if(m.isAnnotationPresent(Check3.class)){
Annotation annotazioni[] = m.getAnnotations();for(Annotation a: annotazioni){
if(a instanceof Check3){Check3 c = (Check3) a;if(c.testato()==false){System.out.println("Metodo non testato! “
+m.getName());}
}}
}}
}
Metodo non testato! metodo3
output di esecuzione
J2SE 5: l’evoluzione di JavaLuca Ferrari 126/188
Gli IDE non annotano (ancora)Gli IDE (ad es. Netbeans, Eclipse) hanno ancora qualche problema/bug nell’uso delle annotazioni. Ad esempio, il code inspector non funziona, vengono segnalati errori (a tempo di digitazione) inesistenti, ecc.
64
J2SE 5: l’evoluzione di JavaLuca Ferrari 127/188
Tipi di ritorno variabili
J2SE 5: l’evoluzione di JavaLuca Ferrari 128/188
Method Override & Return TypeIn generale non è possibile ridefinire un metodo se la nuova definizione varia il tipo del valore di ritorno.
J2SE 5, sotto opportune condizioni, consente di ridefinire un metodo variandone il tipo di ritorno, ma quest’ultimo deve essere una sottoclasse di quello dell’implementazione originale!
65
J2SE 5: l’evoluzione di JavaLuca Ferrari 129/188
EsempioSupponendo di avere la seguente gerarchia di tipi di ritorno:
Veicolo
Automobile
package seminario_20.ret;
public class Veicolo {
protected String marca;
protected int cilindrata;
public Veicolo(String marca,
int cilindrata){
this.marca = marca;
this.cilindrata = cilindrata;
}
public String toString(){
return "Veicolo: "+marca+" (“
+cilindrata+")";
}
}
package seminario_20.ret;
public class Automobile
extends Veicolo{
public Automobile(String marca,
int cilindrata){
super(marca,cilindrata);
}
public String toString(){
return "Automobile:"+marca
+" ("+cilindrata+")";
}
}
J2SE 5: l’evoluzione di JavaLuca Ferrari 130/188
EsempioPossono essere definite le seguenti classi:
FabbricaVeicoli
FabbricaAutomobili
package seminario_20.ret;
public class FabbricaVeicoli {
// un metodo che crea un Veicolo
public Veicolo getVeicolo(String marca,
int cilindrata){
return new Veicolo(marca, cilindrata);
}
}
66
J2SE 5: l’evoluzione di JavaLuca Ferrari 131/188
EsempioPossono essere definite le seguenti classi:
FabbricaVeicoli
FabbricaAutomobili
package seminario_20.ret;
public class FabbricaAutomobili extends FabbricaVeicoli{
// costruisce una Automobile
public Automobile getVeicolo(String marca,
int cilindrata){
return new Automobile(marca, cilindrata);
}
}
J2SE 5: l’evoluzione di JavaLuca Ferrari 132/188
Con JDK < 1.5
67
J2SE 5: l’evoluzione di JavaLuca Ferrari 133/188
Con JDK 1.5package seminario_20.ret;public class Main {
public static void main(String argv[]){// creo le frabbricheFabbricaVeicoli fv = new FabbricaVeicoli();FabbricaAutomobili fa = new FabbricaAutomobili();
//....Veicolo v = fv.getVeicolo("FIAT",500);Automobile a = fa.getVeicolo("BMW",2500);
System.out.println("Veicolo "+v);System.out.println("Automobile "+a);
}} Veicolo Veicolo: FIAT (500)
Automobile Automobile:BMW (2500)
output di esecuzione
J2SE 5: l’evoluzione di JavaLuca Ferrari 134/188
ArgomentiStoria
(da OAK a J2SE 5)
Novità sintattiche
(boxing, foreach, varargs, static import, enum, output formattato)
Novità semantiche
(generics, annotazioni, tipo di ritorno variabili)
Classi aggiunte o modificate
(Swing, StackTraceElement, InetAdress, Management Factory, …)
Varie
(Pack200, Ergonomics, …)
Risorse
68
J2SE 5: l’evoluzione di JavaLuca Ferrari 135/188
Swing
J2SE 5: l’evoluzione di JavaLuca Ferrari 136/188
Desktop ClientE’ ora disponibile un nuovo tema di default per Swing: Ocean.
I Look&Feel per Windows e Linux(GTK) sono stati migliorati.
Sono inoltre disponibili le opzioni per il supporto OpenGL:
sun.java2d.opengl=true
e per usare l’implementazione veloce di X11 (XAWT):
awt.toolkit=sun.awt.motif.MToolkit
69
J2SE 5: l’evoluzione di JavaLuca Ferrari 137/188
Swing e il contentpaneLa libreria Swing definisce i container di primo livello (ad es. JFrame, JDialog) come composizione di una serie di pannelli, il più importante dei quali è il pannello dei contenuti (content pane).
L’aggiunta di componenti grafici (ad es. pulsanti) deve avvenire sul pannello dei contenuti:
this.getContentPane().add(new JButton(“pulsante”);
J2SE 5: l’evoluzione di JavaLuca Ferrari 138/188
getContentPane().add(..) == add(..)Fino ad ora l’utilizzo diretto del metodo add(..)per un frame di primo livello provocava una eccezione.
Ora è possibile richiamare add(..) direttamente per tutti i componenti Swing.
In effetti add(..) ora produce una chiamata a getContentPane().add(..), e quindi le seguenti righe di codice sono equivalenti:
this.getContentPane().add(new JButton(“ciao”));this.add(new JButton(“ciao”));
ma la seconda è più corta e leggibile!
70
J2SE 5: l’evoluzione di JavaLuca Ferrari 139/188
Agire sul pannello giustoIn maniera simile a quanto avviene per add(..), anche altri metodi la cui chiamata diretta produceva eccezioni sono stati reimplementatiper lavorare direttamente sul pannello dei contenuti (ad es. setLayout(..), remove(..),removeAll(), ecc.).
Occorre comunque tenere presente la struttura stratificata di Swing per non lavorare sul pannello sbagliato!
J2SE 5: l’evoluzione di JavaLuca Ferrari 140/188
Classi Modificate
71
J2SE 5: l’evoluzione di JavaLuca Ferrari 141/188
Math & StrictMathLa libreria matematica di Java comprende 10 nuovi metodi per il calcolo trigonometrico.
I metodi sono stati aggiunti nelle classi Math e StrictMath.
Si ricordi che molto spesso Mathsi comporta solo da front-end
per StrictMath.
J2SE 5: l’evoluzione di JavaLuca Ferrari 142/188
StackTraceElementIl dump dello stack non è particolarmente utile se non si dispone di una console o di un metodo di cattura dell’output, da qui la necessità di introdurre la possibilità di analisi dello stack.Il package java.lang include ora una classe per un’analisi degli elementi presenti sullo stack di un Thread: StackTraceElement.
La classe Thread è stata modificata di conseguenza, incorporando metodi appositi per ottenere gli elementi presenti nello stack.
72
J2SE 5: l’evoluzione di JavaLuca Ferrari 143/188
StackTraceElement: un primo esempiopublic class stack{
protected void metodo1(){metodo2();
}
protected void metodo2(){metodo3();
}
protected void metodo3(){analizza_stack();
}
J2SE 5: l’evoluzione di JavaLuca Ferrari 144/188
StackTraceElement: un primo esempioprotected void analizza_stack(){
// ottengo il thread correnteThread mySelf = Thread.currentThread();// ottengo le info sui frame dello stackStackTraceElement frames[] =
mySelf.getStackTrace();// stampo informazioni sullo stackfor(int i=0;i<frames.length;i++){System.out.println("\n\t--- Frame n. "+i+
" ---\n");System.out.println("Metodo: "+
frames[i].getMethodName());System.out.println("File: "+
frames[i].getFileName());System.out.println("Classe/linea: "+
frames[i].getClassName()+"/"+frames[i].getLineNumber());
System.out.println("E' nativo: "+frames[i].isNativeMethod());
}}
73
J2SE 5: l’evoluzione di JavaLuca Ferrari 145/188
StackTraceElement: un primo esempiopublic static void main(String argv[]){stack test = new stack();test.metodo1();
}}// fine della classe
--- Frame n. 0 ---
Metodo: dumpThreads
File: Thread.java
Classe/linea: java.lang.Thread/-2
E' nativo: true
--- Frame n. 1 ---
Metodo: getStackTrace
File: Thread.java
Classe/linea: java.lang.Thread/1383
E' nativo: false
--- Frame n. 2 ---
Metodo: analizza_stack
File: stack.java
Classe/linea: stack/19
E' nativo: false
...
output di esecuzione
ATTENZIONE: si ricordi che al momento della cattura, sullo stack
sono sempre presenti i metodi getStackTrace e
dumpThreads.
J2SE 5: l’evoluzione di JavaLuca Ferrari 146/188
StackTraceElement: bloccare le chiamate in base allo stack
public class ThreadStack {
protected void metodo1(){metodo2();
}
protected void metodo3(){metodo2();
}
74
J2SE 5: l’evoluzione di JavaLuca Ferrari 147/188
StackTraceElement: bloccare le chiamate in base allo stack
protected void metodo2(){// ottengo lo stack correnteStackTraceElement[] stack =
Thread.currentThread().getStackTrace();
for(StackTraceElement e:stack){if(e.getMethodName().equals("metodo3")){System.out.println("\tNon puoi invocare questo
metodo");System.out.println("\tcon metodo3 nello stack!");return;
}}
System.out.println("Invocazione riuscita");}
J2SE 5: l’evoluzione di JavaLuca Ferrari 148/188
StackTraceElement: bloccare le chiamate in base allo stack
public static void main(String argv[]){ThreadStack ts = new ThreadStack();ts.metodo1();ts.metodo2();ts.metodo3();
}} // fine della classe
Invocazione riuscita
Invocazione riuscita
Non puoi invocare questo metodo
con metodo3 nello stack!
output di esecuzione
75
J2SE 5: l’evoluzione di JavaLuca Ferrari 149/188
Thread#getStackTraceOccorre tenere presente che:� quando viene invocato, il metodo getStackTrace() si trova sullo stack, e quindi figura sempre fra i frame più recenti (alti). Inoltre, viene usato un servizio di Thread, dumpThreads(..), che figura anch’esso nello stack(come elemento più recente);� il metodo potrebbe non essere portabile:“Some virtual machines may, under some circumstances, omitone or more stack frames from the stack trace. In the extremecase, a virtual machine that has no stack trace informationconcerning this thread is permitted to return a zero-lengtharray from this method.”
J2SE 5: l’evoluzione di JavaLuca Ferrari 150/188
URLConnectionLa classe URLConnection presenta ora dei metodi per la gestione del connection-timeout relativamente ad ogni istanza.
public int getConnectTimeout()
public void setConnectTimeout(int timeout)
public void setReadTimeout(int timeout)
public int getReadTimeout()
Nelle versioni precedenti, il tempo di timeout era impostabile tramite una proprietà globale (ossia comune a tutte le istanze).
76
J2SE 5: l’evoluzione di JavaLuca Ferrari 151/188
InetAddressE’ ora possibile testare la raggiungibilità di un host:
public boolean isReachable(int timeout)
throws IOException
Le implementazioni comuni usano pacchetti ICMP ECHO REQUEST, analogamente a quanto fatto dal comando ping.
J2SE 5: l’evoluzione di JavaLuca Ferrari 152/188
Classi aggiunte
77
J2SE 5: l’evoluzione di JavaLuca Ferrari 153/188
ManagementFactoryE’ stato aggiunto il package java.lang.management per offrire accesso ai dati di esecuzione della JVM; la classe più importante del package è ManagementFactory.
ManagementFactory offre metodi (statici) di accesso a MXBean, oggetti che possono fornire informazioni sullo stato della memoria, dei class loader, ecc. della JVM.
J2SE 5: l’evoluzione di JavaLuca Ferrari 154/188
ManagementFactory: esempiopublic static void main(String argv[]){
// informazioni di loadingClassLoadingMXBean loading =
ManagementFactory.getClassLoadingMXBean();System.out.println("Classi caricate “
+loading.getTotalLoadedClassCount());System.out.println("Classi scaricate “
+loading.getUnloadedClassCount());
// informazioni di memoriaMemoryMXBean mem =
ManagementFactory.getMemoryMXBean();System.out.println("Heap "+mem.getHeapMemoryUsage());System.out.println("Non heap “
+mem.getNonHeapMemoryUsage());System.out.println("Oggetti da finalizzare “
+mem.getObjectPendingFinalizationCount());}
78
J2SE 5: l’evoluzione di JavaLuca Ferrari 155/188
ManagementFactory: esempio
Classi caricate 296
Classi scaricate 0
Heap init = 0(0K) used = 153712(150K) committed =2031616(1984K) max = 66650112(65088K)
Non heap init = 29556736(28864K) used =12021096(11739K) committed = 29851648(29152K) max =121634816(118784K)
Oggetti da finalizzare 0
output di esecuzione
J2SE 5: l’evoluzione di JavaLuca Ferrari 156/188
FormatterLa classe Formatter consente di applicare una formattazione (specificata tramite una stringa di formato) su una stringa costruita al volo.
Da un punto di vista logico, la classe Formatter svolge il compito della famiglia di funzioni sprintf(..) del C++.
79
J2SE 5: l’evoluzione di JavaLuca Ferrari 157/188
Formatter: un esempioimport java.util.Formatter;
public class Main {public static void main(String[] args){
StringBuilder result = new StringBuilder();Formatter f = new Formatter(result);f.format("%d - %s",10,"CIAO CIAO");System.out.println(result);
}}
10 – CIAO CIAO
output di esecuzione
J2SE 5: l’evoluzione di JavaLuca Ferrari 158/188
ScannerLa classe java.util.Scanner consente di prelevare con precisione l’input. Svolge la stessa funzione semantica di una scanf(..) del C.
Scanner consente di ricercare espressioni regolari nell’input di riga, di trattare i valori di input come numerici, ecc.
Se il tipo fornito in ingresso non è quello che Scanner si aspetta,
verrà sollevata una eccezione. Ad esempio, se Scanner si aspetta un int
e viene fornita una stringa, Scanner avvertirà dell’errore con una eccezione.
80
J2SE 5: l’evoluzione di JavaLuca Ferrari 159/188
Scanner: esempioimport java.util.Scanner;
public class scanner{public static void main(String argv[]){
// associo lo scanner a STDINScanner scan = new Scanner(System.in);// leggo tre interi e ne stampo la sommaint uno = scan.nextInt();int due = scan.nextInt();int tre = scan.nextInt();// continua a leggere (senza far nulla) fino// a che l’utente non digita FINITOscan.findInLine("FINITO");scan.close();System.out.println("La somma vale “
+(uno+due+tre));}
}
J2SE 5: l’evoluzione di JavaLuca Ferrari 160/188
Scanner: esempioluca@linux:~/tmp/j1.5/seminario_20> java seminario_20.scanner
10
20
30
La somma vale 60
CIAO
ProVA
FINITO
luca@linux:~/tmp/j1.5/seminario_20>
81
J2SE 5: l’evoluzione di JavaLuca Ferrari 161/188
java.util.concurrent
E’ disponibile un nuovo package che fornisce classi di utilità generale per applicazioni concorrenti (lock, mutex, semafori, scheduler, ecc.).
Lo scopo di questo package è di semplificare la sincronizzazione dei processi (thread) senza usare le classiche wait()/notify(), che possono portare facilmente a situazioni di stallo.
J2SE 5: l’evoluzione di JavaLuca Ferrari 162/188
java.lang.instrument
Il nuovo package java.lang.instrumentcontiene un (ridotto) set di classi per tecniche di instrumenting (JVMTI).
Instrumenting (dirigere) significa aggiungere ad un metodo del codice di controllo (ad es. prologo o epilogo) per controllarne l’esecuzione.
Simile all’Aspect Oriented Programming e alle tecniche di bytecode manipulation
82
J2SE 5: l’evoluzione di JavaLuca Ferrari 163/188
JVMTIOltre a fornire supporto per l’instrumentdi codice Java, JVMTI fornisce un’implementazione dell’utility HPROF (Heap/CPU Profiling tool).
HPROF è una libreria che consente di monitorare l’esecuzione del codice Java, fornendo informazioni sull’uso delle risorse.
J2SE 5: l’evoluzione di JavaLuca Ferrari 164/188
ArgomentiStoria
(da OAK a J2SE 5)
Novità sintattiche
(boxing, foreach, varargs, static import, enum, output formattato)
Novità semantiche
(generics, annotazioni, tipo di ritorno variabili)
Classi aggiunte o modificate
(Swing, StackTraceElement, InetAdress, Management Factory, …)
Varie
(Pack200, Ergonomics, …)
Risorse
83
J2SE 5: l’evoluzione di JavaLuca Ferrari 165/188
Ergonomics & performance
J2SE 5: l’evoluzione di JavaLuca Ferrari 166/188
ErgonomicsLa JVM include ora una serie di opzioni per il tuning e il profiling delle applicazioni.
Le opzioni di ergonomics coprono la scelta del garbage collector, l’utilizzo del nuovo sistema di class-sharing, dimensione dell’heap e degli spazi generazionali, ecc.
84
J2SE 5: l’evoluzione di JavaLuca Ferrari 167/188
La scelta del garbage collectorSono disponibili le seguenti opzioni:� -Xnoclassgc disabilita la class garbagecollection;� -Xincgc (mark & sweep) abilita il garbage collector incrementale;� -XX:+UseParallelGC abilita il GC generazionale parallelo (throughputcollector);� -XX:+UseConcMarkSweepGC versione parallela di –Xincgc.
J2SE 5: l’evoluzione di JavaLuca Ferrari 168/188
Il garbage collector in azioneUsando il flag –verbose:gc è possibile osservare il garbage collector in azione:
Dimensione oggetti prima del passaggio del GC.
Dimensione oggetti dopo il passaggio del GC.
Spazio disponibile in
totale.
Tempo di esecuzione del GC.
85
J2SE 5: l’evoluzione di JavaLuca Ferrari 169/188
La dimensione della memoriaE’ possibile un controllo accurato sulla dimensione della memoria heap:� -Xms imposta la dimensione iniziale dell’heap;� -Xmx imposta la dimensione massima dell’heap;� -Xss imposta la dimensione dello stack di un thread;� -XXMinHeapFreeRatio, -XXMaxHeapFreeRatioimpostano il limite inferiore/superiore (percentuale) dell’heap libero per forzare un passagio del GC. Le generazioni possono essere ridimensionate. Per un architettura a 32 bit i valori sono rispettivamente 40% e 70%.
J2SE 5: l’evoluzione di JavaLuca Ferrari 170/188
Un esempio casalingopublic class runner{
public static void main(String argv[]){long start,stop;start = System.currentTimeMillis();for(int i=0;i<10000;i++){
for(int j=0;j<10000;j++){String s = new String("Una stringa
abbastanza lunga!!!!!!");}
JFrame f = new JFrame("Nuovo frame");}
stop = System.currentTimeMillis();System.out.println("Tempo di esecuzione “
+(stop-start)+" ms");}
}
86
J2SE 5: l’evoluzione di JavaLuca Ferrari 171/188
Un esempio casalingo
8682 ms-Xms 64000000 –XX:MinHeapFreeRatio=1
-XX:MaxHeapFreeRatio=99
8843 ms-Xms 64000000 –XX:MinHeapFreeRatio=1
9033 ms-Xms 64000000
47218 ms-int
9584 ms-incgc
12478 ms-noclassgc
12518 msnormale
J2SE 5: l’evoluzione di JavaLuca Ferrari 172/188
Shared Class DataE’ ora possibile creare al volo degli archivi di classi da condividere fra più JVM (Shared Class Data).
Il flag per controllare il meccanismo delle classi condivise è –Xshare:{auto|off|on}
87
J2SE 5: l’evoluzione di JavaLuca Ferrari 173/188
Prestazioni del nuovo JDK
J2SE 5: l’evoluzione di JavaLuca Ferrari 174/188
Prestazioni del nuovo JDK
88
J2SE 5: l’evoluzione di JavaLuca Ferrari 175/188
Pack200, lint
J2SE 5: l’evoluzione di JavaLuca Ferrari 176/188
Pack200Una nuova tecnica di compressione degli archivi jar (già compressi – zip).
Fornisce ad applicazioni e applet un meccanismo per ridurre la banda richiesta al trasferimento di un insieme di classi.
Può essere combinata con gzip per offrire maggiore compressione.
Non sostituisce gli archivi jar!!
89
J2SE 5: l’evoluzione di JavaLuca Ferrari 177/188
Pack200Dalla versione 1.1 del protocollo HTTP (RFC 2616), è possibile inviare archivi jar in forma compressa.
Le tecniche supportate (da HTTP) sono: gzip, compress, deflate.
Pack200 si appoggia a gzip.
Ogni server dovrebbe conservare tre copie dello stesso jar: normale (.jar), compresso gzip(.jar.gz), compresso gzip+pack200 (.jar.pack.gz).
J2SE 5: l’evoluzione di JavaLuca Ferrari 178/188
Pack200: funzionamento su HTTP
AE = Accepted Encoding
CE = Content Encoding
CT = Content Type
90
J2SE 5: l’evoluzione di JavaLuca Ferrari 179/188
Pack200: funzionamento su HTTP
AE = Accepted Encoding
CE = Content Encoding
CT = Content Type
J2SE 5: l’evoluzione di JavaLuca Ferrari 180/188
Pack200: funzionamento su HTTP
AE = Accepted Encoding
CE = Content Encoding
CT = Content Type
91
J2SE 5: l’evoluzione di JavaLuca Ferrari 181/188
Pack200: funzionamento su HTTP
AE = Accepted Encoding
CE = Content Encoding
CT = Content Type
J2SE 5: l’evoluzione di JavaLuca Ferrari 182/188
UtilizzoI livelli di compressione dei vari tool sono i seguenti:jar: circa il 3%gzip: circa il 14%pack200: fino al 50% (dichiarati al 90%!)
Da riga di comando è sufficiente utilizzare l’utility pack200/unpack200. Ad esempio:
pack200 –repack myJar.jar
92
J2SE 5: l’evoluzione di JavaLuca Ferrari 183/188
FunzionamentoIl funzionamento si basa sui seguenti
passi:1. vengono fusi (e ordinati) i constant-
pool delle classi contenute nell’archivio jar;
2. vengono rimossi gli attributi ridondanti delle classi;
3. viene usata una tecnica di codifica a lunghezza variabile.
J2SE 5: l’evoluzione di JavaLuca Ferrari 184/188
lintIl compilatore ingloba ora un programma, simile a lint per C, che si occupa di verificare la correttezza del codice (ad es. case senza break, uso di metodi deprecated, ecc.).Per attivare lint è sufficiente fornire l’opzione –Xlint al compilatore javac, con uno dei seguenti completamenti:� -Xlint:none – disabilita tutti i warning, se non marcati come obbligatori nel Java Language Specification� -Xlint:unchecked – fornisce dettagli per le conversioni di tipo� -Xlint:path – avvisa nel caso si usino percorsi inesistenti per classpath, sourcepath, ecc.� -Xlint:finally – avvisa per clausole finally che possono produrre problemi
93
J2SE 5: l’evoluzione di JavaLuca Ferrari 185/188
ArgomentiStoria
(da OAK a J2SE 5)
Novità sintattiche
(boxing, foreach, varargs, static import, enum, output formattato)
Novità semantiche
(generics, annotazioni, tipo di ritorno variabili)
Classi aggiunte o modificate
(Swing, StackTraceElement, InetAdress, Management Factory, …)
Varie
(Pack200, Ergonomics, …)
Risorse
J2SE 5: l’evoluzione di JavaLuca Ferrari 186/188
Risorse
94
J2SE 5: l’evoluzione di JavaLuca Ferrari 187/188
Risorse
URL� http://www.java.net� http://java.sun.com/� http://www.java.net� http://www.mokabyte.it� http://www.gamelan.com� http://polaris.ing.unimo.it/fiC/laboratorio.
html
J2SE 5: l’evoluzione di JavaLuca Ferrari 188/188
Riflessione conclusiva
Your development cycle is muchfaster because Java is interpreted. The compile-link-load-test-crash-
debug cycle is obsolete.
(James Gosling)