Capitolo 8 Progettazione di classi Cay S. Horstmann Concetti di informatica e fondamenti di Java quarta edizione Concetti di informatica e fondamenti di Java, 4 ed. Apogeo ©2007 Obiettivi del capitolo Imparare a identificare le classi giuste da realizzare Assimilare i concetti di coesione e di accoppiamento Ridurre al minimo l’uso degli effetti collaterali Documentare le responsabilità dei singoli metodi e di chi li invoca, usando pre-condizioni e post condizioni Capire la differenza tra metodi di esemplare e metodi statici Introdurre il concetto di variabile statica Capire le regole di visibilità per variabili locali e variabili di esemplare Imparare l’utilizzo dei pacchetti Imparare a usare gli ambienti per il collaudo di unità Concetti di informatica e fondamenti di Java, 4 ed. Apogeo ©2007 Scegliere le classi Una classe dovrebbe rappresentare un singolo concetto nel dominio in cui è descritto il problema, come le scienze, la matematica o l’economia Concetti matematici : Point Rectangle Ellipse Entità della vita reale : BankAccount CashRegister Concetti di informatica e fondamenti di Java, 4 ed. Apogeo ©2007 Scegliere le classi Attori (con un nome che termina in “er” oppure “or” ), classi che svolgono un lavoro. Scanner Random // nome migliore: RandomNumberGenerator Classi di utilità (non servono per creare oggetti, ma contengono una raccolta di metodi correlati fra loro) Math Esecutori di programmi: possiedono solo un metodo main Non trasformate azioni in classi: Paycheck é un nome migliore di ComputePaycheck Concetti di informatica e fondamenti di Java, 4 ed. Apogeo ©2007 Coesione Una classe dovrebbe rappresentare un singolo concetto. I metodi pubblici e le costanti che vengono elencati nell’interfaccia pubblica dovrebbero avere una buona coesione, cioè tutte le caratteristiche dell’interfaccia dovrebbero essere strettamente correlate al singolo concetto rappresentato dalla classe. Se scoprite che l’interfaccia pubblica di una classe si riferisce a più di un concetto, forse è giunto il momento di usare classi separate public class CashRegister { public void enterPayment(int dollars, int quarters, int dimes, int nickels, int pennies) . . . public static final double NICKEL_VALUE = 0.05; public static final double DIME_VALUE = 0.1; public static final double QUARTER_VALUE = 0.25; . . . } Segue Concetti di informatica e fondamenti di Java, 4 ed. Apogeo ©2007 Coesione Qui, in verità, sono presenti due concetti: un registratore di cassa che contiene monete e calcola il loro valore totale, e i valori delle singole monete Potrebbe avere più senso disporre di una classe Coin separata, in modo che ciascuna moneta abbia la responsabilità di conoscere il proprio valore public class Coin { public Coin(double aValue, String aName){ . . . } public double getValue(){ . . . } . . . } public class CashRegister { public void enterPayment(int coinCount, Coin coinType) { . . . } . . . } Concetti di informatica e fondamenti di Java, 4 ed. Apogeo ©2007 Accoppiamento Una classe dipende da un’altra classe se usa esemplari di tale classe La classe CashRegister appena ristrutturata dipende ora dalla classe Coin per determinare il totale da pagare La classe Coin non dipende dalla classe CashRegisterCashRegister Se molte classi di un programma dipendono l’una dall’altra, diciamo che c’è un elevato accoppiamento tra le classi E’ buona norma rendere minimo l’accoppiamento (le dipendenze) tra le classi Per visualizzare le relazioni i programmatori tracciano diagrammi di classi UML: Unified Modeling Language.Notazione per oggetti e classi Concetti di informatica e fondamenti di Java, 4 ed. Apogeo ©2007 Accoppiamento Figura 1 Relazione di dipendenza fra le classi CashRegister e Coin Concetti di informatica e fondamenti di Java, 4 ed. Apogeo ©2007 Elevato e basso accoppiamento fra le classi Figura 2: Elevato e basso accoppiamento tra le classi Concetti di informatica e fondamenti di Java, 4 ed. Apogeo ©2007 Metodi di accesso, metodi modificatori e classi immutabili Un metodo d’accesso riporta informazioni senza effettuare alcuna modifica double balance = account.getBalance(); Un metodo modificatore modifica l’oggetto con il quale viene invocato account.deposit(1000); Concetti di informatica e fondamenti di Java, 4 ed. Apogeo ©2007 Metodi di accesso, metodi modificatori e classi immutabili Una classe immutabile non ha metodi modificatori String name = "John Q. Public"; String uppercased = name.toUpperCase(); // name non viene modificata Una classe immutabile offre un vantaggio molto importante: sicuramente i riferimenti ai suoi oggetti si possono distribuire liberamente. Se nessun metodo può cambiare il valore degli oggetti, di conseguenza nessun codice può modificare un oggetto in modo inaspettato Concetti di informatica e fondamenti di Java, 4 ed. Apogeo ©2007 Effetti collaterali Un effetto collaterale di un metodo è qualsiasi modifica apportata ai dati che sia osservabile all’esterno del metodo La modifica di un parametro esplicito può stupire i programmatori ed è meglio evitarlo ogni volta che è possibile. public void transfer(double amount, BankAccount other) { balance = balance - amount; other.balance = other.balance + amount; // modifica il parametro esplicito } Concetti di informatica e fondamenti di Java, 4 ed. Apogeo ©2007 Effetti collaterali Un altro esempio di effetto collaterale è la visualizzazione di dati in uscita. public void printBalance() // sconsigliato { System.out.println("The balance is now $" + balance); } Il messaggio è in inglese e usa l’oggetto System.out. E’ meglio tenere distinte le attività di ingresso e uscita dal vero compito assegnato alla vostra classe Le modifiche che non riguardano il solo parametro implicito dovrebbero essere ridotte al minimo Concetti di informatica e fondamenti di Java, 4 ed. Apogeo ©2007 Errori comuni Tentare di modificare parametri numerici void transfer(double amount, double otherBalance) { balance = balance - amount; otherBalance = otherBalance + amount; } Questo non funzionerà. Consideriamo un’invocazione del metodo: double savingsBalance = 1000; harrysChecking.transfer(500, savingsBalance); System.out.println(savingsBalance); In Java, un metodo non può mai modificare propri parametri di tipo primitivo Concetti di informatica e fondamenti di Java, 4 ed. Apogeo ©2007 La modifica di un parametro numerico non ha alcun effetto su chi ha invocato il metodo Figura 3: La modifica di un parametro non ha alcun effetto su chi ha invocato il metodo Concetti di informatica e fondamenti di Java, 4 ed. Apogeo ©2007 Chiamate per valore e chiamate per riferimento I parametri di un metodo vengono copiati nelle variabili parametro quando il metodo inizia la propria esecuzione. I ricercatori informatici chiamano questo meccanismo “chiamata per valore” Altri linguaggi di programmazione,supportano un meccanismo alternativo, detto “chiamata per riferimento”, che modifica le variabili parametro In Java, sia i numeri sia i riferimenti a oggetto vengono copiati per valore Segue Concetti di informatica e fondamenti di Java, 4 ed. Apogeo ©2007 Chiamate per valore e chiamate per riferimento In Java, un metodo può modificare lo stato dell’oggetto a cui si riferisce uno dei suoi parametri, ma non può sostituire il riferimento con un altro. public class BankAccount { public void transfer(double amount, BankAccount otherAccount) { balance = balance - amount; double newBalance = otherAccount.balance + amount; otherAccount = new BankAccount(newBalance); // non funziona } } Concetti di informatica e fondamenti di Java, 4 ed. Apogeo ©2007 Esempio di chiamata per valore harrysChecking.transfer(500, savingsAccount); Figura 4: La modifica di un parametro di tipo riferimento a oggetto non ha alcun effetto su chi ha invocato il metodo aller Concetti di informatica e fondamenti di Java, 4 ed. Apogeo ©2007 Pre-condizioni Una pre-condizione è un requisito che deve essere soddisfatto da chi invoca un metodo Chi invoca un metodo ha la responsabilità di farlo rispettando tutte le sue pre-condizioni: se il metodo viene invocato in violazione di una di tali precondizioni,esso non è responsabile per il risultato non corretto. /** Versa denaro in questo conto bancario. @param amount la somma di denaro da versare (Pre-condizione: amount >= 0) */ Segue Concetti di informatica e fondamenti di Java, 4 ed. Apogeo ©2007 Pre-condizioni Le pre-condizioni vengono tipicamente enunciate per uno di questi due motivi: per restringere il campo di variabilità dei parametri di un metodo; per richiedere che un metodo venga invocato soltanto quando l’oggetto su cui agisce si trova in uno stato appropriato. il metodo è libero di fare qualsiasi cosa se una precondizione non viene soddisfatta. Concetti di informatica e fondamenti di Java, 4 ed. Apogeo ©2007 Pre-condizioni Un metodo può accertare la violazione e lanciare un’eccezione. Parleremo delle eccezioni nel Capitolo 11 if (amount < 0) throw new IllegalArgumentException(); balance = balance + amount; Un metodo può semplicemente portare a compimento l’elaborazione assumendo che le pre-condizioni siano soddisfatte // se ciò rende negativo il saldo, è colpa dell’invocante balance = balance + amount; Concetti di informatica e fondamenti di Java, 4 ed. Apogeo ©2007 Pre-condizioni Una asserzione è una condizione logica che si ipotizza essere vera all’interno di un programma. assert amount >= 0; balance = balance + amount; Per eseguire un programma con le verifiche di asserzione abilitate si usa questo comando: java -enableassertions MyProg Non è necessario utilizzare le asserzioni per la verifica delle precondizioni:si ritiene accettabile anche il lancio di un’eccezione, ma le asserzioni hanno il vantaggio di poter essere disabilitate dopo il collaudo del programma, che potrà così essere eseguito alla velocità massima. Segue Concetti di informatica e fondamenti di Java, 4 ed. Apogeo ©2007 Pre-condizioni Molti programmatori inesperti ritengono che non sia “bello” provocare la terminazione prematura di un programma dopo aver accertato la violazione di una pre-condizione if (amount < 0) return; // sconsigliato balance = balance + amount; Concetti di informatica e fondamenti di Java, 4 ed. Apogeo ©2007 Sintassi di Java 8.1 Asserzione ssert condizione ; sempio : ssert amount >= 0; biettivo: sserire il soddisfacimento di una condizione. Se è abilitata la verifica elle asserzioni e la condizione è falsa, viene lanciata l’eccezione ssertionError. Concetti di informatica e fondamenti di Java, 4 ed. Apogeo ©2007 Post-condizioni Se un metodo viene invocato nel rispetto delle sue pre-condizioni, deve garantire che le sue post-condizioni siano valide Una promessa fatta dal metodo viene chiamata post-condizione , di cui esistono due tipi: 1. che il valore di ritorno venga calcolato correttamente; 2. che l’oggetto sia in un determinato stato dopo che l’esecuzione del metodo è terminata. Segue Concetti di informatica e fondamenti di Java, 4 ed. Apogeo ©2007 Post-condizioni /** Versa denaro in questo conto bancario. (Post-condizione: getBalance() >= 0) @param amount la somma di denaro da versare (Pre-condizione: amount >= 0) */ Non specificare una post-condizione in ogni metodo, ma quando si usa javadoc,specificare nel marcatore @return una parte di postcondizione, che non si deve ripetere. Segue Concetti di informatica e fondamenti di Java, 4 ed. Apogeo ©2007 Post-condizioni Formulate le pre-condizioni e le post-condizioni soltanto in termini di interfaccia della classe amount <= getBalance() // questo è il modo di formulare una post-condizione amount <= balance //formulazione errate di post-condizione Pre-condizioni e post-condizioni sono termini contrattuali fra un metodo e chi lo invoca. Il metodo si impegna a soddisfare la postcondizione per tutti i dati in ingresso che soddisfano la precondizione. Concetti di informatica e fondamenti di Java, 4 ed. Apogeo ©2007 Metodi statici I metodi statici sono metodi “di classe”. – Usati tipicamente per fare calcoli numerici. E.g. classe Math Un metodo statico non viene invocato mediante un oggetto. – – – Non accede a variabili d'esemplare Non ha parametro implicito (this) Puo' accedere a variabili statiche (incluse le costanti) Per quale ragione si scrive un metodo che non opera su un oggetto? Il motivo più diffuso è che si vogliono incapsulare alcune elaborazioni che coinvolgono solamente numeri: dal momento che i numeri non sono oggetti, non potete utilizzarli per invocare metodi. Ad esempio, l’invocazione x.sqrt() sarebbe illegale in Java. Concetti di informatica e fondamenti di Java, 4 ed. Apogeo ©2007 Metodi statici public class Financial { public static double percentOf(double p, double a) { return (p / 100) * a; } // qui si possono aggiungere altri metodi finanziari. } Quando chiamate un metodo statico, fornite il nome della classe che lo contiene, in modo che il compilatore lo possa trovare, come in questo esempio: double tax = Financial.percentOf(taxRate, total); Notate che non fornite un oggetto di tipo Financial quando chiamate il metodo. Il metodo main è statico. Quando viene eseguito il programma non esiste ancora alcun oggetto. Concetti di informatica e fondamenti di Java, 4 ed. Apogeo ©2007 Variabili statiche Una variabile statica (o campo statico) appartiene alla classe, non a un esemplare della classe. public class BankAccount { . . . private double balance; private int accountNumber; private static int lastAssignedNumber = 1000; } Ciascun esemplare di BankAccount ha i propri campi di esemplare balance e accountNumber, però esiste un’unica copia della variabile lastAssignedNumber Segue Concetti di informatica e fondamenti di Java, 4 ed. Apogeo ©2007 Variabili statiche public BankAccount() { //genera il successivo numero di conto da assegnare lastAssignedNumber++; //Aggiorna la variabile di classe //Assegna il numero di conto di questo conto bancario accountNumber = lastAssignedNumber; //aggiorna la variabile di esemplare } Ridurre al minimo l’uso di metodi e di campi statici Concetti di informatica e fondamenti di Java, 4 ed. Apogeo ©2007 Variabili statiche Esistono tre modi per inizializzare una variabile statica: 1. Non fare nulla. La variabile statica viene inizializzata automaticamente a zero (per i numeri), a false (per i valori boolean) o a null (per gli oggetti). 2. Usare un inizializzatore esplicito. public class BankAccount { . . . private static int lastAssignedNumber = 1000; // Executed once, // when class is loaded } 3. Usare un blocco di inizializzazione statica (leggere Argomenti avanzati 8.3). Segue Concetti di informatica e fondamenti di Java, 4 ed. Apogeo ©2007 Variabili statiche Bisogna sempre dichiarare private le variabili statiche Fanno eccezione a questa regola le costanti statiche, che possono essere private o pubbliche. public class BankAccount { . . . public static final double OVERDRAFT_FEE = 5; // Refer to it as // BankAccount.OVERDRAFT_FEE } Concetti di informatica e fondamenti di Java, 4 ed. Apogeo ©2007 Variabili statiche e di esemplare Figura 5: Variabili statiche e di esemplare Concetti di informatica e fondamenti di Java, 4 ed. Apogeo ©2007 Ambito di visibilità L’ambito di visibilità di una variabile è la porzione di programma all’interno della quale si può accedere alla variabile L’ambito di visibilità di una variabile locale si estende dal punto in cui viene dichiarata fino alla fine del blocco che la contiene Segue Concetti di informatica e fondamenti di Java, 4 ed. Apogeo ©2007 Ambito di visibilità A volte accade che lo stesso nome di variabile venga utilizzato in due metodi: public class RectangleTester { public static double area(Rectangle rect) { double r = rect.getWidth() * rect.getHeight(); return r; } public static void main(String[] args) { Rectangle r = new Rectangle(5, 10, 20, 30); double a = area(r); System.out.println(r); } } Queste variabili sono indipendenti l’una dall’altra, oppure, in altre parole, i loro ambiti di visibilità sono disgiunti Concetti di informatica e fondamenti di Java, 4 ed. Apogeo ©2007 Ambito di visibilità L’ambito di visibilità di una variabile locale non può mai contenere la definizione di un’altra variabile locale avente lo stesso nome Rectangle r = new Rectangle(5, 10, 20, 30); if (x >= 0) { double r = Math.sqrt(x); // Errore:non si può dichiarare in questo punto un’altra variabile di nome r . . . } Segue Concetti di informatica e fondamenti di Java, 4 ed. Apogeo ©2007 Ambito di visibilità Tuttavia se i loro ambiti non si sovrappongono potete avere variabili locali con nomi identici if (x >= 0) { double r = Math.sqrt(x); . . . } // la visibilità di r termina qui else { Rectangle r = new Rectangle(5, 10, 20, 30); // va bene,questa è la variabile r diversa . . . } Concetti di informatica e fondamenti di Java, 4 ed. Apogeo ©2007 Visibilità di membri di classe I membri privati hanno visibilità di classe: a tutti i membri di questo tipo si può accedere da qualsiasi metodo della classe stessa Se volete usare un campo o un metodo pubblico al di fuori della sua classe, dovete renderne qualificato il nome. Il nome di un campo o di un metodo statico si qualifica specificando il nome della classe Math.sqrt harrysChecking.getBalance All’interno di un metodo non c’è bisogno di qualificare i nomi dei campi o dei metodi della classe stessa Segue Concetti di informatica e fondamenti di Java, 4 ed. Apogeo ©2007 Visibilità di membri di classe Le variabili di esemplare si riferiscono automaticamente al parametro implicito del metodo, cioè all’oggetto con cui è stato invocato il metodo (parametro implicito this) public class BankAccount { public void transfer(double amount, BankAccount other) { withdraw(amount); // i.e., this.withdraw(amount); other.deposit(amount); } ... } Concetti di informatica e fondamenti di Java, 4 ed. Apogeo ©2007 Visibilità sovrapposte Una variabile locale può mettere in ombra una variabile di esemplare con lo stesso nome Prevale il nome della variabile locale, che mette in ombra la variabile di esemplare public class Coin { . . . public double getExchangeValue(double exchangeRate) { double value; // variabile locale . . . return value; } private String name; private double value; // variabile di esemplare con lo stesso nome } Concetti di informatica e fondamenti di Java, 4 ed. Segue Apogeo ©2007 Visibilità sovrapposte Si può accedere alla variabile messa in ombra usando il suo nome qualificato mediante il riferimento this value = this.value * exchangeRate; Concetti di informatica e fondamenti di Java, 4 ed. Apogeo ©2007 Organizzare in pacchetti le classi correlate Un pacchetto ( package) è un insieme di classi correlate Per inserire le classi in un pacchetto, dovete inserire la riga seguente quale prima istruzione del file sorgente che contiene le classi: package nomePacchetto; Il nome di un pacchetto è formato da uno o più identificatori, separati da punti Segue Concetti di informatica e fondamenti di Java, 4 ed. Apogeo ©2007 Organizzare in pacchetti le classi correlate Come esempio, inseriamo all’interno di un pacchetto chiamato com.horstmann.bigjava la classe Financial. Il file Financial.java deve iniziare in questo modo: package com.horstmann.bigjava; public class Financial { . . . } Il pacchetto predefinito è senza nome. Se non inserite un enunciato package all’inizio di un file sorgente, le sue classi verranno inserite nel pacchetto predefinito Concetti di informatica e fondamenti di Java, 4 ed. Apogeo ©2007 Pacchetti essenziali della libreria Java Pacchetto Scopo Esempio di classi java.lang Supporto al linguaggio Math java.util Utility Random java.io Input and Output PrintScreen Java.awt Abstract Windowing Toolkit Color Java.applet Applet Applet Java.net Connessione di rete Socket Java.sql Accesso a database tramite Structured Query Language ResultSet Java.swing Interfaccia utente Swing JButton Concetti di informatica e fondamenti di Java, 4 ed. Apogeo ©2007 Sintassi di Java 8.2 Specifica di pacchetto package nomePacchetto; Esempio: package com.horstmann.bigjava; Obiettivo: Dichiarare che tutte le classi presenti nel file appartengono a un determinato pacchetto Concetti di informatica e fondamenti di Java, 4 ed. Apogeo ©2007 Importare pacchetti Se volete usare una classe di un pacchetto, potete indicarla tramite il suo nome completo,costituito dal nome del pacchetto seguito da quello della classe. java.util.Scanner in = new java.util.Scanner(System.in); Naturalmente, questo è un sistema molto scomodo. In alternativa, potete importare un nome mediante un enunciato import: import java.util.Scanner; . . . Scanner in = new Scanner(System.in) Concetti di informatica e fondamenti di Java, 4 ed. Apogeo ©2007 Importare pacchetti Potete importare tutte le classi di un pacchetto, mediante un enunciato import che termina con .*. Per esempio: import java.util.*; Non avrete mai bisogno di importare esplicitamente le classi del pacchetto java.lang java.lang Non c’è bisogno di importare altre classi presenti nel pacchetto in cui si trova la classe che state scrivendo NOTA: import pacchetto.* non opera in maniera ricorsiva Concetti di informatica e fondamenti di Java, 4 ed. Apogeo ©2007 Nomi di pacchetto e come vengono localizzate le classi Usate un nome di dominio in ordine inverso per costruire nomi di pacchetti non ambigui. java.util.Timer vs. javax.swing.Timer com.horstmann.bigjava Se non possedete un vostro nome di dominio, potete sempre creare un nome di pacchetto con alte probabilità di essere univoco scrivendo il vostro indirizzo di posta elettronica al contrario. Per esempio: edu.sjsu.cs.walters: per i pacchetti delle classi di Bertha Walters ([email protected]) Segue Concetti di informatica e fondamenti di Java, 4 ed. Apogeo ©2007 Nomi di pacchetto e come vengono localizzate le classi Un pacchetto è ubicato in una cartella il cui nome corrisponde a quello del pacchetto com/horstmann/bigjava/Financial.java Il percorso del file che contiene una classe deve corrispondere al suo nome di pacchetto Dovete aggiungere le cartelle che possono contenere pacchetti al percorso delle classi (class path) export CLASSPATH=/home/walters:. set CLASSPATH=c:\home\walters;. Concetti di informatica e fondamenti di Java, 4 ed. Apogeo ©2007 Cartella di base e sottocartelle per i pacchetti Figura 6: Cartella di base e sottocartelle per i pacchetti Concetti di informatica e fondamenti di Java, 4 ed. Apogeo ©2007 Ambienti per il collaudo di unità Gli ambienti per il collaudo di unità semplificano il compito di scrivere classi che contengano molti casi di prova JUnit: http://junit.org fa anche parte di molti ambienti di sviluppo più completi come BlueJ e Eclipse La filosofia di JUnit è semplice: essa prevede l’esecuzione di tutti i collaudi ogni volta che viene modificato il codice Concetti di informatica e fondamenti di Java, 4 ed. Apogeo ©2007 JUnit 4 • import org.junit.*; import static org.junit.Assert.*; • annotare un metodo con @Test • Invocare assertTrue(boolExp) dove boolExp è un'espressione booleana che ha valore true iff il test ha successo (alternative: assertEquals, ...) @Test // TODO: usare BankAccount per gli esempi public void simpleAdd() { Money m12CHF= new Money(12, "CHF"); Money m14CHF= new Money(14, "CHF"); Money expected= new Money(26, "CHF"); Money result= m12CHF.add(m14CHF); assertTrue(expected.equals(result)); } Concetti di informatica e fondamenti di Java, 4 ed. Apogeo ©2007 ...JUnit 4 - fixtures • Se esistono più test che operano sugli stessi oggetti (test fixture) possono essere creati in un metodo specifico che viene invocato automaticamente prima dell'esecuzione di ogni test. public class MoneyTest { private Money f12CHF; private Money f14CHF; private Money f28USD; @Before public void setUp() { f12CHF= new Money(12, "CHF"); f14CHF= new Money(14, "CHF"); f28USD= new Money(28, "USD"); } } Concetti di informatica e fondamenti di Java, 4 ed. Apogeo ©2007 ...JUnit 4 - fixtures • Si possono anche usare variabili statiche static private int numberOfOperations = 10; Oppure static private int numberOfOperations; @BeforeClass public static void setUpClass() { numberOfOperations = 10; // Altre operazioni p.e. su risorse: file, database, rete } Concetti di informatica e fondamenti di Java, 4 ed. Apogeo ©2007 JUnit 4 • Esecuzione metodi statici annotati con @BeforeClass • Per ogni metodo annotato con @Test – – – • Esecuzione dei metodi annotati con @Before Esecuzione dei metodi annotati con @Test Esecuzione dei metodi annotati con @After Esecuzione metodi statici annotati con @AfterClass Concetti di informatica e fondamenti di Java, 4 ed. Apogeo ©2007 … JUnit • E' possibile eseguire un test con timeout. L'esecuzione viene interrotta forzatamente se non termina entro il limite di tempo prestabilito. – • @Test(timeout=1000) E' possibile testare se viene lanciata un'eccezione – @Test(expected=IndexOutOfBoundsException.class) public void empty() { new ArrayList<Object>().get(0); } Concetti di informatica e fondamenti di Java, 4 ed. Apogeo ©2007