Introduzione a OOP con Java

annuncio pubblicitario
Sommario
1
2
3
Oggetti e classi.............................................................................................................................4
1.1
Definizione di oggetto e di classe..........................................................................................4
1.2
concetto di istanza di oggetto................................................................................................4
1.3
Invocazione di metodi............................................................................................................4
1.4
Parametri di un metodo..........................................................................................................4
1.5
Tipi di dati..............................................................................................................................4
1.6
Istanze multiple di una classe................................................................................................4
1.7
Stato di un oggetto.................................................................................................................4
1.8
Cos'è un oggetto?...................................................................................................................4
1.9
Il codice Java.........................................................................................................................4
1.10
Interazione di oggetti.........................................................................................................4
1.11
Codice sorgente..................................................................................................................4
1.12
Esercizio Lab-classes.........................................................................................................4
1.13
Valori restituiti da un metodo.............................................................................................5
1.14
Oggetti come parametri......................................................................................................5
Comprendere la definizione delle classi.......................................................................................5
2.1
Una macchina che stampa biglietti........................................................................................5
2.2
Metodi accessors e mutators..................................................................................................6
2.3
Interazione con la console.....................................................................................................6
2.4
Esercizi sulle classi.............................................................................................9
2.5
Per ripassare................................................................................................................9
2.6
Esercizi di fine capitolo.......................................................................................................10
Interazione tra oggetti.................................................................................................................10
3.1
L'orologio digitale................................................................................................................10
Esperimenti.................................................................................................................................11
4
3.2
Class Diagram vs. Object Diagram.....................................................................................12
3.3
Object type e primitive type................................................................................................12
3.4
Gli oggetti posso creare altri oggetti....................................................................................14
3.5
Overloading dei metodi e dei costruttori.............................................................................14
3.6
Esercizi di potenziamento....................................................................................................15
3.7
Uso del riferimento this....................................................................................................15
3.8
Uso del debugger in BlueJ...................................................................................................15
3.9
Per ripassare.........................................................................................................................16
Raggruppamento di oggetti........................................................................................................17
4.1
Music-organizer-v1......................................................................................................17
4.2
Music-organizer-v2......................................................................................................19
Eseguire i brani musicali mediante un oggetto MusicPlayer.....................................................19
4.3
Music-organizer-v3......................................................................................................20
Processare tutti gli elementi di una collection............................................................................20
ciclo predeterminato - for-each loop......................................................................................21
4.4
Music-organizer-v4......................................................................................................22
Cicli indeterminati – while.....................................................................................................22
4.5
Music-organizer-v5......................................................................................................23
Un miglioramento del progetto del MusicOrganizer: classe Track............................................23
4.6
Scorrere gli elementi di una collection con un iteratore......................................................25
4.7
Modalità di iterazione in Java (riassunto)............................................................................26
4.8
Esercizi con le classi............................................................................................................26
Progetto Club..............................................................................................................................26
Progetto Music-Organizer-v5e (con shuffle)..............................................................................26
Copia di un ArrayList in un altro ArrayList...........................................................................30
Ancora sul progetto Club...........................................................................................................30
Progetto Products (StockManager, Product, etc.)......................................................................30
4.9
Collections a dimensione fissa: gli array.............................................................................31
Alcuni esempi.............................................................................................................................31
4.10
Passaggio dei parameteri in java......................................................................................32
Passing Primitive Data Type Arguments....................................................................................32
Passing Reference Data Type Arguments...................................................................................32
4.11
5
Per ripassare.....................................................................................................................33
Oggetti con comportamento complesso.....................................................................................34
5.1
Un risponditore automatico completo: tech-support-complete...........................................34
5.2
Un risponditore banale: tech-support1.................................................................................34
5.3
La documentazione Java......................................................................................................34
Concetto di interfaccia e di implementazione di una classe.......................................................35
5.4
Utilizzo delle funzioni di libreria.........................................................................................35
5.5
Utilizzo di package, import e archivi jar.............................................................................36
Organizzazione delle classi in package......................................................................................36
Creazione di archivi jar..............................................................................................................38
5.6
Uso di mappe per creare associazioni..................................................................................38
Concetto di Map: la classe HashMap.........................................................................................38
Concetto di Set: classe HashSet.................................................................................................41
Suddivisione di stringhe.............................................................................................................41
Esercizi.......................................................................................................................................42
5.7
La documentazione delle classi...........................................................................................43
Uso di javadoc............................................................................................................................43
getImage.................................................................................................................................44
Public vs. Private........................................................................................................................44
Information Hiding.....................................................................................................................45
La parola chiave static................................................................................................................45
Le costanti – static final..............................................................................................................46
5.8
6
Per ripassare.........................................................................................................................46
Il progetto delle classi (cenni) - Design gudelines.....................................................................47
6.1
Dipendenza (coupling) e coesione (cohesion).....................................................................47
Coupling (the lower is better).....................................................................................................47
Cohesion (the higher is better)...................................................................................................47
6.2
Duplicazione del codice (da evitare)...................................................................................47
6.3
Incapsulamento e dipendenza (information hiding enforces decoupling)...........................48
6.4
Responsability driven design (to redouce coupling)...........................................................48
6.5
Refactoring..........................................................................................................................48
Refactoring per supporto multilingua (esempio)........................................................................48
6.6
Metodi statici (keyword static)............................................................................................49
Il metodo Main (rivisitato).........................................................................................................50
La classe Math............................................................................................................................50
6.7
7
Per ripassare.........................................................................................................................51
Testing e debugging....................................................................................................................52
7.1
Testing con BlueJ.................................................................................................................52
Test positivi e test negativi.........................................................................................................53
7.2
Test automatici.....................................................................................................................54
JUnit...........................................................................................................................................54
Test Fixture.................................................................................................................................57
8
7.3
Debugging............................................................................................................................57
7.4
Per ripassare.........................................................................................................................58
Riferimenti per Java...................................................................................................................58
In queste note si seguirà l'approccio del testo Objects First with Java i cui esempi (utilizzati in
queste
note)
sono
liberamente
scaricabili
al
link
http://www.bluej.org/objectsfirst/resources/projects.zip .
1 Oggetti e classi
1.1 Definizione di oggetto e di classe
1.2 concetto di istanza di oggetto
Esempio figures → new Circle()
1.3 Invocazione di metodi
(la comunicazione con gli oggetti). Metodo makeVisible() sull'istanza cicle1.
1.4 Parametri di un metodo
Segnatura di un metodo.
1.5 Tipi di dati
I tipi di dati dei parametri di un metodo.
1.6 Istanze multiple di una classe
1.7 Stato di un oggetto
1.8 Cos'è un oggetto?
Un oggetto di una classe ha i campi della classe e i metodi di quella classe.
1.9 Il codice Java
Un programma contiene o usa dichiarazione di classi; crea oggetti e effettua chiamate di metodi su
oggetti. Uso del code panel di blueJ.
1.10 Interazione di oggetti
Utilizzo dell'esempio house.
1.11 Codice sorgente
La scrittura delle classi: analisi del codice sorgente. Vedere il codice delle classi Person e Circle.
Esercizi 1.18, 1.19, 1.20
1.12 Esercizio Lab-classes
Esercizio lab-classes
1.13 Valori restituiti da un metodo
1.14 Oggetti come parametri
Con la classe lab-class creare una classe e iscrivere alcuni studenti alla classe. Con questo
esempio possiamo osservare che in Java è possibile passare come parametri ai metodi di una classe i
riferimenti a oggetti di altre classi.
2 Comprendere la definizione delle classi
2.1 Una macchina che stampa biglietti
Riprendiamo i concetti già visti nel capitolo precedente con un altro esempio guida: la classe
naive-ticket-machine .
Creare un oggetto di macchina che stampa biglietti. Analizzare i limiti di questa implementazione.
Cosa succede se mettiamo più soldi del costo del biglietto?
E se mettiamo meno soldi?
Come fare a stampare biglietti di taglio diverso?
Analizziamo il codice della classe e osserviamo alcuni aspetti fondamentali:
class header:
public class TicketMachine
{
Inner part of the class omitted.
}
field, constructors, methods:
public class ClassName
{
Fields
Constructors
Methods
}
Attenzione alla scelta dei nomi di variabili: devono essere scelti in modo da rendere il più possibile
chiaro il significato di una variabile.
I metodi:
public class TicketMachine
{
Fields omitted.
Constructor omitted.
/**
* Return the price of a ticket.
*/
public int getPrice()
{
return price;
}
Remaining methods omitted.
}
Un metodo che non restituisce alcun valore ha un tipo di ritorno void e un'istruzione return
seguita da un punto e virgola:
public void Print()
{
//some statement
return;
}
2.2 Metodi accessors e mutators
I metodi che accedono alle variabili di istanza (i campi di classe) si dicono metodi accessors e
hanno un nome del tipo getNomeCampo(). Ad esempio getPrice(), oppure getBalance(). I metodi
che impostano una variabile d'istanza si dicono mutators e tipicamente hanno un nome del tipo
setNomeCampo();
public int getPrice()
{
return price;
}
public void setPrice(int cost)
{
price = cost;
}
2.3 Interazione con la console
Stampare il biglietto con il metodo printTicket().
Stampare su console:
System.out.println("Stringa da stampare tra doppi apici");
String parole = "qualcosa da dire";
String paroleSensate = "altrimenti meglio tacere";
System.out.println(parole +"quando sei preparato” + paroleSensate);
In generale per utilizzare la console conviene osservare l'uso dei metodi più usati (print, println,
format) in questo link.
E per leggere da console? Non è così semplice come in C#..., ma dipende dalla versione di JDK
utilizzata. In Java 5 (JDK1.5) si può far uso dell'oggetto scanner come nell'esempio seguente:
import java.util.Scanner;
public class InputExperiment {
public static void main(String[] args) {
String name;
int age;
Scanner in = new Scanner(System.in);
System.out.println("inserisci il tuo nome");
// Reads a single line from the console
// and stores into name variable
name = in.nextLine();
System.out.println("Inserisci la tua età");
// Reads a integer from the console
// and stores into age variable
age=in.nextInt();
in.close();
// Prints name and age to the console
System.out.println("Name :"+name);
System.out.println("Age :"+age);
}
}
In Java 6 è stato introdotto l'oggetto console, che si può utilizzare in maniera analoga alla console
C#. La console di Java 6 può non funzionare in alcuni IDE (tra cui BlueJ) che simulano la console
reale. Ad esempio il seguente codice
import java.io.Console;
public class InputExperiment2
{
public static void main(String[] args) throws Exception {
Console console = System.console();
if (console == null) {
System.out.println("Unable to fetch console");
return;
}
console.printf("Per favore scrivi qualcosa\n");
String line = console.readLine();
console.printf("I saw this line: %s", line);
}
}
In BlueJ fallisce:
Nella console reale funziona:
Nelle versioni di Java precedenti alla 5 bisogna scrivere del codice come riportato di seguito:
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
public class InputExperiment3 {
public static void main(String[] args) {
BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
System.out.print("Enter String: ");
try
{
String s = br.readLine();
System.out.print("Enter Integer: ");
int i = Integer.parseInt(br.readLine());
System.out.println("Your string: " + s);
System.out.println("your number: " + i);
}
catch(NumberFormatException nfe){
System.err.println("Invalid Format!");
}
catch (Exception e)
{
//qualunque altra eccezione qui
}
}
}
Riflettiamo sulla classe TicketMachine e osserviamo quanto riportato in 2.12. Si può certamente
fare di meglio.
 il metodo insertMoney() accetta solo valori non negativi
 il metodo printTicket() stampa il biglietto solo se il saldo supera il costo del biglietto
 la macchina implementa un metodo refoundBalance() che restituisce il resto.
Il progetto better-ticket-machine riporta queste modifiche.
É utile sapere che BlueJ evidenzia lo scope delle variabili con colori diversi così come descritto in
2.15.
Per le variabili locali valgono le stesse regole di visibilità viste in C# (par 2.16).
Ripassiamo i concetti di campi, parametri e variabili locali con il paragrafo 2.17.
2.4 Esercizi sulle classi
Iniziamo a scrivere codice modificando la classe TicketMachine (del progetto better-ticketmachine ) in modo da svolgere gli esercizi 2.61, 2.62, 2.63.
Rivediamo la classe Student del progetto lab-classes con particolare riferimento ai metodi
getLoginName() e print(). Il campo Id non ha nessun metodo per modificarne il valore. Si
dice in tal caso che si tratta di un campo immutabile. Ci sono oggetti che non possono essere
modificati una volta creati. In tal caso si parla di oggetti immutabili. Ad esempio gli oggetti di tipo
stringa sono tutti oggetti immutabili.
2.5 Per ripassare
Concetti fondamentali:
Classe
Oggetti (o istanza di una classe)
Campi (o variabili d'istanza)
cosa rappresentano?
Pattern di riferimento: dovrebbero essere privati (libro, pag. 26 e pag. 27)
Costruttori
A cosa servono?
Quali regole deve soddisfare?
Quanti costruttori possiamo avere?
Metodi
a cosa servono?
Cosa si intende per segnatura?
Cosa indicano le parole chiave pubblic e private? Si veda anche:
http://docs.oracle.com/javase/tutorial/java/javaOO/accesscontrol.html
Parametri
parametri formali (parametri)
parametri attuali (effettivi)
scope di una variabile
lifetime di una variabile
metodi accessors (get)
metodi mutators (set)
Istruzioni di selezione
Variabili locali
2.6 Esercizi di fine capitolo
Completare la classe Book con gli esercizi 2.83 e successivi. Svolgere i due challenge
exercise 2.92 e 2.93.
3 Interazione tra oggetti
fig.
“Un’astrazione denota le caratteristiche essenziali di un oggetto, che lo distinguono da tutti gli altri
oggetti e gli forniscono nuovi contorni concettuali, dal punto di vista di chi lo guarda”.(Booch, 1998)
3.1 L'orologio digitale
Iniziamo a studiare i concetti di questo capitolo con un esempio guida “l'orologio digitale”.
Vogliamo realizzare un orologio digitale con le orario in formato europeo 00:00 a 23:59.
Come procedere? Applicando astrazione (abstraction) e decomposizione (modularization).
Esperimenti
a) un orologio è fatto da cifre … (astrazione) le cifre sono quattro (decomposizione)...: come
gestiamo l'interazione tra gli oggetti (cifre)?
b) un orologio è fatto di due numeri rappresentati su due cifre (astrazione e decomposizione)
c) un orologio è fatto da due numeri … (astrazione) il primo numero rappresenta le ore da 0 a 23 e
il secondo numero rappresenta i minuti da 0 a 59 (decomposizione)...i due numeri si comportano
allo stesso modo, nel senso che partono da un valore nullo e arrivano a un valore massimo per poi
tornare al valore nullo...: Ogni numero è rappresentato da su due cifre decimali. Questo modo di
vedere le cose sembra più semplice da gestire: creiamo la classe che rappresenta una coppia di
cifre...
public class NumberDisplay
{
private int limit;
private int value;
Constructor and methods omitted.
}
e un orologio è costituito da due oggetti NumberDisplay:
public class ClockDisplay
{
private NumberDisplay hours;
private NumberDisplay minutes;
Constructor and methods omitted.
}
Una classe può essere pensata come un iceberg1:
•
Solo una piccola parte di una classe dovrebbe essere visibile all’esterno.
•
La maggior parte dei dettagli della classe dovrebbe essere nascosta.
fig.
3.2 Class Diagram vs. Object Diagram
Osserviamo il class diagram e l' object diagram nel paragrafo 3.6.
3.3 Object type e primitive type
Nel paragrafo 3.6 troviamo un'altra importante differenza: quella tra variabili che contengono
riferimenti a oggetti (reference data type) e variabili che contengono valori di tipi semplici
(primitive data type).
In un programma Java ogni oggetto ha un tipo rappresentato dalla sua classe.
Ad esempio:

1
Da Mario può essere un’istanza (oggetto) della classe Pizzeria
Metafora ispirata da Bertrand Meyer, Object-oriented software construction. Prentice Hall, 1988.

Il Cliente Gianni può essere un’istanza (oggetto) della classe Cliente

L’auto con
Automobile.

La frase di benvenuto può essere un’istanza (oggetto) della classe string.
targa
BR123XY può essere un’istanza (oggetto) della classe
In un programma Java è possibile definire variabili di tipo riferimento a oggetti di una data classe.

Una variabile di tipo riferimento rappresenta un riferimento, ossia un modo per individuare
univocamente una specifica istanza (oggetto) di una data classe.

Una variabile di tipo riferimento serve a referenziare una specifica istanza, ma non è
l’istanza (oggetto). Infatti, è possibile avere più riferimenti (più variabili di tipo riferimento)
a uno stesso oggetto (istanza).

Il riferimento a un oggetto è ciò che Java mette a disposizione per interagire con gli oggetti.
Ad esempio, mediante la variabile daMario (di tipo riferimento a Pizzeria) sarà
possibile accedere allo stato dell’oggetto Da Mario e interagire con esso inviandogli
messaggi (ossia invocare i suoi metodi).
fig.
Per ragioni pratiche, in Java c’è la possibilità di definire anche variabili che non siano riferimenti ad
oggetti in senso stretto. Queste variabili (o espressioni) hanno tipo valore. Un tipo valore è messo a
disposizione dal linguaggio e non è creato mediante la definizione di una classe. Il termine “tipo
valore” indica che le variabili di tali tipi contengono il loro valore direttamente. I tipi riferimento e i
tipi valore esauriscono le categorie di tipi disponibili in Java.
La distinzione tra tipi primitivi e tipi riferimento è molto importante perché la semantica degli
assegnamenti è diversa nei due casi.
Una variabile di tipo primitivo può essere pensata come il nome di un contenitore che conserva un
valore di quel tipo.
fig. 4: esempi di variabili di
tipo primitivo
L’assegnamento fra tipi primitivi ha l’effetto di copiare il valore di un contenitore (membro destro)
nell’altro (membro sinistro).
fig. 5: L’assegnamento fra tipi primitivi
L’assegnamento fra tipi riferimento ha l’effetto di cambiare il riferimento del membro sinistro verso
l’oggetto referenziato dal membro destro, senza copiare valori.
fig.
fig.
I tipi come int, bool, char, double etc. appartengono alla categoria “value type”.
In Java i tipi primitivi sono:
Data Type
Default Value (for fields)
byte
0
short
0
int
0
long
0L
float
0.0f
double
0.0d
char
'\u0000'
boolean
false
I tipi come le string e come i tipi astratti corrispondenti al concetto di classe (come Persona,
Pizzeria, Auto, etc.) appartengono alla categoria “reference type” e permettono di rappresentare gli
oggetti.
3.4 Gli oggetti posso creare altri oggetti
Esaminiamo il codice del progetto clock-display (par. 3.8) partendo dalla classe
NumberDisplay. Gli oggetti possono creare altri oggetti (par. 3.9) usando l'operatore new().
3.5 Overloading dei metodi e dei costruttori
(Par. 3.11) In una classe possiamo avere più costruttori oppure più metodi con lo stesso nome a
patto che le segnature dei metodi siano diverse: i costruttori o i metodi devono differire nella lista
dei parametri formali. Questo concetto va sotto il nome di overloading. Ad esempio
ClockDisplay() e ClockDisplay(int hours, int minute) hanno segnature diverse. In
questo link troviamo la documentazione ufficiale Java che descrive cosa si intende per segnatura di
un metodo e per overloading.
3.6 Esercizi di potenziamento
Svolgere i due challenge exercises 3.31 e 3.32 (realizzare un orologio che visualizza le cifre delle
ore da 1 a 12 e riporta la dicitura AM o PM).
3.7 Uso del riferimento this
(Par. 3.12) apriamo il progetto mail-system. Questo progetto è, per il momento, troppo
complesso per poter essere compreso completamente. Tuttavia è utile per comprendere alcuni
aspetti importanti. Per prima cosa osserviamo l'utilizzo del riferimento all'oggetto corrente this nel
costruttore della classe MailItem.
public MailItem(String from, String to, String message)
{
this.from = from;
this.to = to;
this.message = message;
}
Methods omitted.
}
this è una parola chiave del linguaggio Java ed è il riferimento all'oggetto corrente. Serve per
riferire in maniera esplicita un membro (campo o metodo) dell'oggetto corrente. L'uso più comune
del riferimento this si ha quando un campo è nascosto da un parametro locale.
Scorrere il codice per capire cosa fa...
3.8 Uso del debugger in BlueJ
Il progetto mail-system è composto da tre classi: una molto semplice MailItem, una semplice
MailClient, una un po' complessa MailServer. Creiamo un'istanza di mailserver e poi due
istanze di client (juan e sophie) a cui passiamo il riferimento per il mailserver. Poi iniziamo a
scambiare messaggi (mailitem) tra i due. Mettiamo un breakpoint su un'istruzione di
printNextMailItem.
3.9 Per ripassare
4 Raggruppamento di oggetti
In questo capitolo vedremo più in dettaglio il concetto di astrazione e di interazione di
oggetti. Inizieremo con una importante applicazione del concetto di astrazione: la collezione
(collection) di oggetti. Partiamo dal concetto di collezione e immaginiamo di poter scrivere una
classe che rappresenti il concetto di collezione; otterremo oggetti di tipo collection in grado di
memorizzare un numero arbitrario di altri oggetti. Per illustrare il concetto di collection utilizziamo
l'esempio guida music-organizer. Questo progetto realizza una versione minimale di player
mp3 utilizzando la libreria jlayer scaricabile dal sito http://www.javazoom.net/projects.html.
4.1 Music-organizer-v1
La versione v1 del progetto si limita a creare un oggetto di tipo ArrayList e a inserirvi un certo
numero di stringhe di testo corrispondenti al “full name” (percorso del file + nome file con
estensione) di file in formato .mp3. Questa versione non esegue i file musicali, ma si limita a
esplorare le funzioni di base che si hanno su on oggetto di tipo ArrayList: add(),
remove(index), get(index), size().
import java.util.ArrayList;
public class MusicOrganizer
{
private ArrayList<String> files;
public MusicOrganizer()
{
files = new ArrayList<String>();
}
public void addFile(String filename)
{
files.add(filename);
}
public int getNumberOfFiles()
{
return files.size();
}
public void listFile(int index)
{
if(index >= 0 && index < files.size()) {
String filename = files.get(index);
System.out.println(filename);
}
}
public void removeFile(int index)
{
if(index >= 0 && index < files.size()) {
files.remove(index);
}
}
}//end of class
Dall'esempio music-organizer-v1 si vede l'utilizzo di una particolare astrazione: la collection
ArrayList. La creazione di un oggetto di tipo ArrayList deve includere anche la definizione del
tipo base degli elementi della lista, dal momento che ArrayList è una classe generica. Per creare
un ArrayList e assegnare il suo riferimento a una variabile si utilizza il costrutto:
ArrayList<TipoBase> rifLista; //dichiarazione del riferimento
rifLista = new ArrayList<TipoBase>();
oppure da Java 7 si può scrivere:
rifLista = new ArrayList<>();
TipoBase è un qualsiasi tipo ottenuto mediante la definizione di una classe (deve essere un object
type). Si noti che un ArrayList e in generale una collection Java non può contenere tipi primitivi
(boolean, char, int, double, etc..) a meno di non ricorrere a classi wrapper. Si vedano a tal proposito
i concetti di:
Autoboxing e Unboxing
Wrapper classes
Primitive type
Wrapper class
boolean
Boolean
byte
Byte
char
Character
float
Float
int
Integer
long
Long
short
Short
double
Double
Number classes e java numbers
Da questo esempio si è visto anche cosa succede all'indice degli elementi di un ArrayList quando si
inseriscono o si rimuovono elementi.
4.2 Music-organizer-v2
Eseguire i brani musicali mediante un oggetto MusicPlayer
La seconda versione del progetto utilizza la classe MusicPlayer per eseguire i file musicali caricati
nell'ArrayList files.
import java.util.ArrayList;
public class MusicOrganizer
{
private ArrayList<String> files;
private MusicPlayer player;
public MusicOrganizer()
{
files = new ArrayList<String>();
player = new MusicPlayer();
}
public void addFile(String filename)
{
files.add(filename);
}
//other methods
public void startPlaying(int index)
{
String filename = files.get(index);
player.startPlaying(filename);
}
public void stopPlaying()
{
player.stop();
}
}//end of class MusicOrganizer
La classe MusicPlayer utilizza la libreria jl di javazoom.net per creare un player di file mp3. I
dettagli saranno analizzati in seguito. Ora interessa che i file sono riprodotti correttamente.
4.3 Music-organizer-v3
Processare tutti gli elementi di una collection
In Java esistono diversi modi per processare tutti gli elementi di una collection. Uno dei più usati è
il for-each loop (analogo al foreach di C#).
ciclo predeterminato - for-each loop
In Java non esiste una keyword foreach, ma si utilizza il classico for per effettuare un for-each su
una collection. Cambia il modo di iterare la collection.
for(ElementType element : collection) {
loop body
}
Ad esempio nel progetto music-organizer-v3 c'é il metodo di MusicOrganizer che stampa
tutti i file presenti nell'ArrayList files. In tale metodo si utilizza il for-each:
/**
* Show a list of all the files in the collection.
*/
public void listAllFiles()
{
for(String filename : files) {
System.out.println(filename);
}
}
Con un costrutto for-each é ovviamente possibile processare in maniera selettiva solo degli elementi
della collection che soddisfano un particolare requisito come ad esempio nel metodo listMatching
che stampa solo i nomi dei file che contengono il nome passato al metodo:
/**
* List the names of files matching the given search string.
* @param searchString The string to match.
*/
public void listMatching(String searchString)
{
for(String filename : files) {
if(filename.contains(searchString)) {
// A match.
System.out.println(filename);
}
}
}
Esercizio 4.27: aggiungere alla classe MusicOrganizer il metodo playAllSamples che esegue
in sequenza un campione di tutti i brani presenti nella collection files. Attenzione: bisogna usare
il metodo playAndWait e non il metodo startPlaying della classe MusicPlayer, dal
momento che startPlayer ritorna non appena ha creato un nuovo thread che mette in esecuzione
il brano passatogli. Il metodo palyAndWait esegue solo un campione del brano passatogli come
parametro, e ritorna quando l'esecuzione è terminata.
Osservazione 1: un costrutto for-each va usato quando bisogna processare tutti gli elementi della
collection. Se viceversa si vuole processare gli elementi della collection fino al verificarsi di una
determinata condizione è meglio ricorrere ad altri costrutti, come ad esempio il while che vedremo
nel prossimo paragrafo.
Osservazione2: il for-each consente di cambiare i valori ai campi degli oggetti della collection, ma
non consente di eliminare o aggiungere elementi alla collection. Se si prova a fare una cosa del
genere si solleva un'eccezione del tipo ConcurrentModificationException. Se si vuole
avere la possibilità di aggiungere o rimuovere elementi dalla collection mentre si effettua la
scansione bisogna utilizzare un ciclo while in combinazione a un iteratore, come descritto nei
prossimi paragrafi.
4.4 Music-organizer-v4
Cicli indeterminati – while
Esempio 1: Questo esempio mostra come iterare tutta la collection, come si sarebbe potuto fare con
un for-each. Questo esempio è un ciclo sviluppato con il while, ma che è in realtà predeterminato.
/**
* Show a list of all the files in the collection.
*/
public void listAllFiles(){
int index = 0;
while(index < files.size()) {
String filename = files.get(index);
System.out.println(filename);
index++;
}
}
Esempio 2: questo esempio mostra un ciclo indeterminato nel quale si cerca un brano che contiene
nel nome una parola data in input. Questo ciclo è effettivamente un ciclo indeterminato dal
momento che non è noto a priori quando si uscirà da ciclo.
/**
* Find the index of the first file matching the given
* search string.
* @param searchString The string to match.
* @return The index of the first occurrence, or -1 if
* no match is found.
*/
public int findFirst(String searchString){
int index = 0;
// Record that we will be searching until a match is found.
boolean searching = true;
while(searching && index < files.size()) {
String filename = files.get(index);
if(filename.contains(searchString)) {
// A match. We can stop searching.
searching = false;
}
else {
// Move on.
index++;
}
}
if(searching) {
// We didn't find it.
return -1;
}
else {
// Return where it was found.
return index;
}
}
4.5 Music-organizer-v5
Un miglioramento del progetto del MusicOrganizer: classe
Track
Negli esempi precedenti, le informazioni sull'artista e sul titolo del brano erano nel nome del file
mp3, seguendo la convenzione “nome artista – nome brano.mp3”. Ora si vuole migliorare il
progetto introducendo una classe Track che contenga i dati relativi a un brano (artista, titolo, nome
completo del file) nei suoi campi e di conseguenza l'elenco dei brani gestiti dal MusicOrganizer
sarà un ArrayList di oggetti di tipo Track. Per semplificare ulteriormente le cose è utile avere
una classe TrackReader che ha lo scopo principale di caricare, con il metodo readTracks, i file
presenti in una determinata directory e aventi estensione specificata (.mp3) in un ArrayList di
Track. Il metodo readTracks assume che il nome dei file sia “nome artista – titolo brano .mp3”.
Nella classe MusicOrganizer il metodo readLibrary richiama readTracks e aggiunge le
tracce alla lista tracks.
import java.util.ArrayList;
public class MusicOrganizer{
// An ArrayList for storing music tracks.
private ArrayList<Track> tracks;
// A player for the music tracks.
private MusicPlayer player;
// A reader that can read music files and load them as tracks.
private TrackReader reader;
/**
* Create a MusicOrganizer
*/
public MusicOrganizer(){
tracks = new ArrayList<Track>();
player = new MusicPlayer();
reader = new TrackReader();
readLibrary("audio");
System.out.println("Music library loaded. " + getNumberOfTracks()
+ " tracks.");
System.out.println();
}
private void readLibrary(String folderName)
{
ArrayList<Track> tempTracks = reader.readTracks(folderName,
".mp3");
// Put all the tracks into the organizer.
for(Track track : tempTracks) {
addTrack(track);
}
}
//other methods
}//end of MusicOrganizer
Si noti che il metodo readLibrary di MusicOrganizer fa uso del metodo readTracks
sull'oggetto reader della classe TrackReader. Questo metodo implementa il caricamento da file
in oggetti di tipo Track e contiene del codice che sarà chiaro più avanti.
Con questa nuova struttura della classe MusicOrganizer il metodo che stampa l'elenco delle
tracce è:
public void listAllTracks(){
System.out.println("Track listing: ");
for(Track track : tracks) {
System.out.println(track.getDetails());
}
System.out.println();
}
Si noti che la classe Track ha anche un metodo che stampa a console i dettagli di una traccia:
public String getDetails()
{
return artist + ": " + title + "
}
L'esecuzione di un brano con la nuova struttura diventa:
public void playTrack(int index){
(file: " + filename + ")";
if(indexValid(index)) {
Track track = tracks.get(index);
player.startPlaying(track.getFilename());
System.out.println("Now playing: " + track.getArtist() +
" - " + track.getTitle());
}
}
4.6 Scorrere gli elementi di una collection con un iteratore
Un Iteratore è un oggetto molto potente che permette di scorrere gli elementi di una collection in
maniera semplice e senza particolari restrizioni (come accadeva con il for-each).
Per utilizzare un iteratore occorre importare la classe java.util.Iterator e il suo uso è associato al
ciclo while nel seguente modo:
Iterator<ElementType> it = myCollection.iterator();
while(it.hasNext()) {
call it.next() to get the next element
do something with that element
}
Ad esempio supponendo di fare riferimento al MusicOrganizer si potrebbe scrivere il metodo
/**
* List all the tracks.
*/
public void listAllTracks(){
Iterator<Track> it = tracks.iterator();
while(it.hasNext()) {
Track t = it.next();
System.out.println(t.getDetails());
}
}
Con un oggetto di tipo iteratore è possibile anche eliminare o aggiungere elementi a una collection.
Ad esempio si potrebbe scrivere un frammento di codice come il seguente:
Iterator<Track> it = tracks.iterator();
while(it.hasNext()) {
Track t = it.next();
String artist = t.getArtist();
if(artist.equals(artistToRemove)) {
it.remove();
}
}
Si noti che la rimozione di un elemento dalla collection avviene utilizzando direttamente il
riferimento dato dall'iteratore. Per approfondimenti si veda anche questo link.
4.7 Modalità di iterazione in Java (riassunto)

ciclo for semplice (con indice), come quello visto in C#

ciclo for-each

ciclo while con indice

iteratore con ciclo while

ciclo do while con indice o con iteratore
4.8 Esercizi con le classi
Esercizi 4.40, 4.41, 4.42
Osservazioni importanti: la classe ClubDemo utilizza oggetti anonimi nel metodo join, ossia
oggetti che non hanno un reference, e che sono creati quando servono.
public void demo()
{
club.join(new Membership("David", 2, 2004));
club.join(new Membership("Michael", 1, 2004));
System.out.println("The club has " +
club.numberOfMembers() +
" members.");
}
Progetto Music-Organizer-v5e (con shuffle)
Esercizi 4.43, 4.44. 4.45
Riferimenti utili:
http://docs.oracle.com/javase/7/docs/api/java/util/Random.html
http://docs.oracle.com/javase/7/docs/api/java/util/Random.html#nextInt(int)
Versione1: Fare una prima versione che genera un numero a caso tra 0 e tracks.size()-1 e
stampa a video i titoli delle tracce selezionate. Poi passare alla versione che utilizza il metodo
playSample per ascoltare il risultato.
Suggerimento: partendo dal metodo listAllFiles del §4.4 si arriva facilmente a un metodo
come printRandomSamples
import java.util.Random;
//
public void printRandomSamples(){
Random randomGen = new Random();
int index = 0;
while(index < tracks.size()) {
int posizione = randomGen.nextInt(tracks.size());
String filename =tracks.get(posizione).getFilename();
System.out.println(filename);
index++;
}
}
/**
* NOTA IMPORTANTE: una volta lanciata la sequenza non è possibile interromperla!
*/
public void playRandom(){
Random randomGen = new Random();
int index = 0;
try{
while(index < tracks.size()) {
player.playSample(tracks.get(randomGen.nextInt(tracks.size())).getFilename());
index++;
}
}
catch (Exception e)
{
e.printStackTrace();
}
}
Per ottenere un metodo che esegue una sequenza di brani e che possa essere interrotto occorre
modificare la classe MusicPlayer come segue:
public class MusicPlayer
{
// The current player. It might be null.
private AdvancedPlayer player;
//impostata a true quando si deve eseguire una lista di brani
//impostata a false quando si deve interrompere una lista di brani
private boolean vaiAvanti;
//altri metodi
public void playListSamples(final ArrayList<String> filenames)
{
try {
//vaiAvanti è true fino a quando non si decide di interrompere la sequenza
vaiAvanti = true;
Thread playerThread = new Thread() {
public void run()
{
Iterator<String> it = filenames.iterator();
while(it.hasNext() && vaiAvanti){
String brano = it.next();
try {
setupPlayer(brano);
player.play(500);
}
catch(JavaLayerException e) {
reportProblem(brano);
}
catch (Exception ex) {
ex.printStackTrace();
}
finally {
killPlayer();
}
}
}
};
playerThread.start();
}
catch (Exception ex) {
ex.printStackTrace();
}
}
//altri metodi
public void stopList()
{
vaiAvanti = false;
killPlayer();
}
A questo punto nella classe MusicOrganizer si possono aggiungere i seguenti metodi:
*
*
*
*
*
*/
/**
Esegue l'elenco dei file delle tracce, scelti a caso.
Il numero di file eseguiti è uguale alla dimensione della lista.
E' possibile che alcuni file siano eseguiti più volte e che alcuni file
non siano eseguiti
NOTA IMPORTANTE: questo metodo può essere interrotto con il metodo stopList
public void playRandomSamples(){
Random randomGen = new Random();
ArrayList<String> shuffled = new ArrayList<String>();
int index = 0;
try{
while(index < tracks.size()) {
//calcolo indice random
int posizione = randomGen.nextInt(tracks.size());
shuffled.add(tracks.get(posizione).getFilename());
index++;
}
player.playListSamples(shuffled);
}
}
catch (Exception e)
{
e.printStackTrace();
}
public void stopPlayingList()
{
player.stopList();
}
Versione 2: Fare una seconda versione che esegue in modalità random i brani della lista una sola
volta e poi ferma l'esecuzione. Suggerimento: creare una copia della lista delle tracce (come?) e poi
estrarre a caso un indice dalla lista e eseguire il relativo brano. Il brano eseguito sarà rimosso dalla
copia della lista. Quando la copia della lista sarà vuota ogni brano sarà stato eseguito una sola volta
a caso.
/**
* Stampa i brani presenti nella lista in ordine casuale. Ogni brano è eseguito una sola volta
*/
public void printRandomOnceSamples(){
//shallow copy mediante copy constructor
ArrayList<Track> copiedList= new ArrayList<Track>(tracks);
Random randomGen = new Random();
ArrayList<String> shuffled = new ArrayList<String>();
try{
while(copiedList.size()>0) {
//calcolo indice random
int posizione = randomGen.nextInt(copiedList.size());
shuffled.add(copiedList.get(posizione).getFilename());
copiedList.remove(posizione);
}
for(String brano: shuffled){
// player.playListSamples(shuffled);
System.out.println(brano);
}
}
catch (Exception e)
{
e.printStackTrace();
}
}
/**
* Esegue i brani presenti nella lista in ordine casuale. Ogni brano è eseguito una sola volta
*/
public void playRandomOnceSamples(){
ArrayList<Track> copiedList= new ArrayList<Track>();
//copio la lista delle tracce in una lista temporanea copiedList <-- tracks
listDeepCopy(copiedList, tracks);
Random randomGen = new Random();
ArrayList<String> shuffled = new ArrayList<String>();
try{
while(copiedList.size()>0) {
//calcolo indice random
int posizione = randomGen.nextInt(copiedList.size());
shuffled.add(copiedList.get(posizione).getFilename());
copiedList.remove(posizione);
}
player.playListSamples(shuffled);
}
catch (Exception e)
{
e.printStackTrace();
}
}
Copia di un ArrayList in un altro ArrayList
Per copiare una lista in un'altra lista ci sono diversi metodi, ma la cosa veramente importante è
comprendere cosa si vuole copiare! La cosa più semplice è fare una shallow copy di una lista, vale a
dire una nuova lista che contiene i riferimenti agli stessi oggetti della prima. Se si modifica un
oggetto nella prima lista lo si modifica anche nella seconda. Solo nel caso di tipi primitivi si
ottengono due liste di elementi disgiunti.
Per fare una shallow copy si può ricorrere al copy constructor:
ArrayList<Track> copiedList= new ArrayList<Track>(tracks);
oppure si può fare un metodo che esegue la copia elemento per elemento
private void listCopy(ArrayList<Track> dest, ArrayList<Track> source){
try{
dest.clear();
for(int i=0; i<source.size(); i++){
dest.add(source.get(i));
}
}
catch (Exception e){
e.printStackTrace();
}
}
il risultato sarà lo stesso. Anche nel secondo caso otterremo una shallow copy dal momento che
l'istruzione composta dest.add(source.get(i)); utilizza il riferimento della lista sorgente per inserire
un nuovo elemento nella lista destinazione.
Ancora sul progetto Club
Esercizi 4.54 e 4.55
Progetto Products (StockManager, Product, etc.)
Esercizi 4.56, 4.57, 4.58, 4.59, 4.60
Suggerimento: scrivere nell'ordine printProductDetails, findProduct, numberInStock, delivery,
4.9 Collections a dimensione fissa: gli array
Le collections a dimensione fissa sono gli array. Rispetto alle collezioni a dimensione variabile, gli
array hanno caratteristiche peculiari che li rendono particolarmente adatti in certi contesti. In
particolare gli array hanno lo svantaggio di non poter variare la loro dimensione una volta creati,
tuttavia rispetto alle collections a dimensione variabile hanno i seguenti vantaggi:

L'accesso agli elementi di un array è in genere più efficiente (veloce) dell'accesso agli
elementi di una collections a dimensione variabile.

Gli array possono memorizzare sia oggetti (riferimenti a oggetti) sia tipi primitivi. Le
collections a dimensione variabile possono memorizzare solo oggetti2.
Un'altra caratteristica fondamentale degli array è che essi supportano una sintassi speciale per
l'accesso ai singoli elementi.
Alcuni esempi
Per dichiarare un array:
int hour; // A single int variable.
int[] hourCounts; // An int-array variable.
Creazione di oggetti di tipo array:
hourCounts = new int[24];
Definizione (dichiarazione e creazione di oggetto) di un array:
String[] names = new String[10];
Un elemento di un array si comporta come una variabile del suo tipo base:
hourCounts[hour]++;
hourCounts[hour] = hourCounts[hour] + 1;
hourCounts[hour] += 1;
L'iterazione su un array si può fare con un classico ciclo for, come nel seguente esempio:
for(int hour = 0; hour < hourCounts.length; hour++) {
System.out.println(hour + ": " + hourCounts[hour]);
}
oppure con un ciclo while
int hour = 0;
while(hour < hourCounts.length) {
System.out.println(hour + ": " + hourCounts[hour]);
hour++;
}
Sebbene sia possibile usare un ciclo for-each o un iteratore su un array in genere ciò è sconsigliato,
perché il for-each non fornisce la variabile indice che serve per accedere agli elementi di un array,
mentre l'iteratore costringe a usare una sintassi poco naturale nel caso di array.
4.10 Passaggio dei parameteri in java
http://docs.oracle.com/javase/tutorial/java/javaOO/arguments.html
Passing Primitive Data Type Arguments
Primitive arguments, such as an int or a double, are passed into methods by value. This means
that any changes to the values of the parameters exist only within the scope of the method. When
the method returns, the parameters are gone and any changes to them are lost. Here is an example:
public class PassPrimitiveByValue {
public static void main(String[] args) {
2
In effetti è possibile inserire oggetti che simulano valori primitivi mediante il meccanismo dell'autoboxing. Si veda
questo link per i dettagli.
int x = 3;
// invoke passMethod() with
// x as argument
passMethod(x);
// print x to see if its
// value has changed
System.out.println("After invoking passMethod, x = " + x);
}
// change parameter in passMethod()
public static void passMethod(int p) {
p = 10;
}
}
When you run this program, the output is:
After invoking passMethod, x = 3
Passing Reference Data Type Arguments
Reference data type parameters, such as objects, are also passed into methods by value. This means
that when the method returns, the passed-in reference still references the same object as before.
However, the values of the object's fields can be changed in the method, if they have the proper
access level.
For example, consider a method in an arbitrary class that moves Circle objects:
public void moveCircle(Circle
// code to move origin of
circle.setX(circle.getX()
circle.setY(circle.getY()
}
circle, int deltaX, int deltaY) {
circle to x+deltaX, y+deltaY
+ deltaX);
+ deltaY);
// code to assign a new reference to circle
circle = new Circle(0, 0);
Let the method be invoked with these arguments:
moveCircle(myCircle, 23, 56)
Inside the method, circle initially refers to myCircle. The method changes the x and y
coordinates of the object that circle references (i.e., myCircle) by 23 and 56, respectively.
These changes will persist when the method returns. Then circle is assigned a reference to a new
Circle object with x = y = 0. This reassignment has no permanence, however, because the
reference was passed in by value and cannot change. Within the method, the object pointed to by
circle has changed, but, when the method returns, myCircle still references the same Circle
object as before the method was called.
Altri esempi che spiegano il funzionamento del passaggio dei parametri si trovano in questo link:
http://zitogiuseppe.com/jsem/parametri.html
4.11 Per ripassare
(Par. 5.1) Iniziamo con l'esempio tech-support-complete per vedere cosa si può fare con
oggetti di tipo HashMap e HashSet.
5.2 Un risponditore banale: tech-support1
(Par. 5.2) Analizziamo la versione tech-support1 che comprende la versione di base del progetto
e implementa un risponditore automatico che risponde sempre con la stessa frase a ogni parola
chiave.
5.3 La documentazione Java
Apriamo la documentazione ufficiale Java su link Oracle (da BlueJ ) e in locale. Da BlueJ su può
aprire la documentazione selezionando Help>Java Class Libraries. Come esercizio troviamo
la documentazione per la classe java.lang.String.
Osserviamo la configurazione di BlueJ relativa alla documentazione.
Esercizi:
Exercise 5.3 Look up the startsWith method in the documentation for String. There are two versions. Describe in your own
words what they do and the differences between them.
Exercise 5.4 Is there a method in the String class that tests whether a string ends with a given suffix? If so, what is it called and
what are its parameters and return type?
endsWith()
Exercise 5.5 Is there a method in the String class that returns the number of characters in the string? If so, what is it called and
what are its parameters?
length()
Exercise 5.6 If you found methods for the two tasks above, how did you find them? Is it easy or hard to find methods you are
looking for? Why?
Concetto di interfaccia e di implementazione di una classe
L'interfaccia di una classe rappresenta cosa la classe fa e come può essere utilizzata dall'esterno.
L'interfaccia di un metodo rappresenta la segnatura del metodo con l'aggiunta del tipo di ritorno.
L'interfaccia di una classe è di norma descritta nella documentazione.
L'implementazione di una classe è data dal codice della classe.
5.4 Utilizzo delle funzioni di libreria
Gli oggetti di tipo stringa sono oggetti immutabili. Ciò significa che una volta creati non possono
più essere modificati. I metodi della classe String che servono per manipolare stringhe restituiscono
stringhe modificate che sono nuove stringhe, diverse da quelle di partenza. Ad esempio il metodo
toUpperCase() applicato a un oggetto di tipo stringa non modifica l'oggetto su cui è applicato,
ma restituisce una nuova stringa.
Le istruzioni:
String prova = “ciao Mondo”; → prova = new String(“ciao mondo”);
String prova2= prova.toUpperCase();
I metodi che restituiscono oggetti possono essere concatenati per ottenere l'esecuzione di più
metodi in sequenza. Ad esempio il metodo getInput() della classe reader dell'esempio tech-
support1 restituisce un oggetto di tipo stringa. Possiamo fare in modo da applicare la funzione
trim() e la funzione toLowerCase() per rendere il programma insensibile agli spazi e alle
variazioni di case. Nel codice del metodo start() possiamo scrivere:
while(!finished) {
String input = reader.getInput().trim().toLowerCase();
if(input.equals("bye")) {
finished = true;
//etc...
Esercizi 5.8 e 5.9
L'uguaglianza tra stringhe non va mai verificata con l'operatore ==. Infatti in Java l'operatore
== verifica se i due operandi ( a sinistra e destra) sono lo stesso oggetto e non se hanno lo stesso
valore. Per verificare l'uguaglianza tra oggetti di tipo stringa bisogna usare il metodo equals() che
verifica se il contenuto delle due stringhe è uguale. Ad esempio:
The following example shows the usage of java.lang.String.equals() method.
package com.tutorialspoint;
import java.lang.*;
public class StringDemo {
public static void main(String[] args) {
String str1 = "sachin tendulkar";
String str2 = "amrood admin";
String str3 = "amrood admin";
// checking for equality
boolean retval1 = str2.equals(str1);
boolean retval2 = str2.equals(str3);
// prints the return value
System.out.println("str2 is equal to str1 = " + retval1);
System.out.println("str2 is equal to str3 = " + retval2);
}
}
Let us compile and run the above program, this will produce the following result:
str2 is equal to str1 = false
str2 is equal to str3 = true
Esercizi 5.10 e 5.11
La classe java.util.Random
Esercizio 5.14 – creare la classe RandomTester. Attenzione al fatto che quando si utilizza un
oggetto della classe Random bisognerebbe utilizzare una singola istanza della classe Random (creata
nel costruttore di RandomTester) e memorizzarla in un campo. Ogni volta che si vuole un nuovo
valore casuale si dovrebbe invocare il metodo nextQualcosa() e non ricreare l'oggetto Random.
Esercizi 5.16, 5.17, 5.18, 5.20
Un generatore di risposte casuale – verso tech-support2: sviluppo del codice a partire dal
progetto tech-support1 (par. 5.4.3)
5.5 Utilizzo di package, import e archivi jar
Per utilizzare le classi bisogna istruire il compilatore sulle classi che si vogliono utilizzare tramite la
direttiva import. Siccome le classi delle librerie Java sono diverse migliaia, per organizzarle in
maniera ordinata si utilizzano i package. I package sono gruppi di classi logicamente correlate. Per
importare le classe all'interno di un package bisogna scrivere
import package-name.Class-name
nel file della classe che utilizza le classi della libreria.
I package possono essere organizzati in sub-package, come ad esempio java.util.
È possibile richiamare tutte le classi di un package scrivendo import package-name.*, ma nel
nostro corso preferiamo scrivere esplicitamente le classi che sono utilizzate per dare maggiore
chiarezza al codice.
Le classi del package java.lang sono automaticamente importate, infatti per usare oggetti di tipo
String non è necessario scrivere import java.lang.String.
Organizzazione delle classi in package
To make types easier to find and use, to avoid naming conflicts, and to control access, programmers
bundle groups of related types into packages.
Definition: A package is a grouping of related types providing access protection and
name space management. Note that types refers to classes, interfaces, enumerations, and
annotation types. Enumerations and annotation types are special kinds of classes and
interfaces, respectively, so types are often referred to in this lesson simply as classes and
interfaces.
The types that are part of the Java platform are members of various packages that bundle classes by
function: fundamental classes are in java.lang, classes for reading and writing (input and output) are
in java.io, and so on. You can put your types in packages too.
La creazione dei package in BlueJ è molto semplice:
http://people.cis.ksu.edu/~schmidt/300s05/bluej.packages.html
Say that you want to use BlueJ to construct a folder, Assign1, that contains a package named P. Within package P you
wish to insert a class, C.java. Here is what you do:
1.Click on the Project menu, and click on its New Project menu item. A file dialog appears that asks you the
name of the folder you wish to create---type Assign1 and press the create button.
Important: You can tell BlueJ where on your disk you wish to create the folder, Assign1. Remember where you
created it --- this will make your life easier when it is time to submit your work for grading.
2.As a result of the previous step, BlueJ creates a new folder named Assign1, and it opens a new window
presenting the folder to you. (Alas, in BlueJ, a folder (directory) is called a ``project''!)
Now, we are ready to create the package, P: Within the Assign1 window, click on the Edit menu, and click on
its New Package menu item. A dialog appears and asks you for the name of the package---type P and press
OK.
3.As a result of the previous step, a folder (package) named P has been created inside folder Assign1.
4.Now you are ready to include class C within package P. You can do this two ways:
1. Write it from scratch:
double-click on folder P; this opens it and displays a new window.
within the window for P, click on the New Class button. A dialog appears and asks for the name of
the class---type C and press OK.
The previous step creates a file, C.java, inside folder P. When you open C.java, you will find that
BlueJ has constructed an empty class that looks like this:
package P;
public class C
{ ... }
At this point, you can edit and compile the various java-files as usual.
2. Copy it from somewhere else:
Say that class C is already written and saved as the file, C.java, in another folder. You can copy it into the
package by
double-click on folder P; this opens the package and displays a new window.
click on the Edit menu and then click on the Add Class from File menu item.
A file dialog appears; use this to locate C.java; once you have located it, press the Add button.
On newer releases of BlueJ, you can copy the contents of an entire package all at once: Say that you want to copy
a package Q in its entirety into Assign1:
1.Open the window for Assign1.
2.Select Edit and then New Package. Type the name, Q, into the dialog.
3.Open the window for Q; select Project and then Import. Use the file dialog to locate the folder (package)
named Q on your file system.
BlueJ will then copy all the classes in folder Q into the BlueJ package Q you just constructed.
Per gli approfondimenti sui packages si veda http://docs.oracle.com/javase/tutorial/java/package/packages.html
Creazione di archivi jar
I file jar sono archivi complessi contenenti classi java, solitamente compilate. Il formato jar è il formato standard di
distribuzioni delle api java. Ad esempio nella cartella della JDK andando in Program Files\Java\jdk_numero_ver\jre\lib
si trovano diversi file jar e tra questi il file rt.jar che contiene le principali classi fornite nel java runtime environment.
In BlueJ è molto semplice creare un file jar del proprio progetto, basta andare in Project>Create Jar Files e qui
si apre il wizard che porta alla creazione del jar.
Per gli approfondimenti sugli archivi jar si rinvia al link http://docs.oracle.com/javase/tutorial/deployment/jar/
5.6 Uso di mappe per creare associazioni
Vogliamo creare un risponditore automatico che associ a ogni parola chiave una risposta
plausibile. Se il testo inserito dall'utente contiene una delle parole chiave gestite dal risponditore, la
risposta automatica sarà la frase associata alla parola chiave. Per fare questo tipo di risponditore
automatico utilizzeremo la classe HashMap, che è una particolare Map.
Esercizi 5.23 e 5.24: Cercare nella documentazione Java la classe HashMap e l'interfaccia Map
http://docs.oracle.com/javase/6/docs/api/java/util/HashMap.html
http://docs.oracle.com/javase/6/docs/api/java/util/Map.html
Concetto di Map: la classe HashMap
Una mappa è una collection che memorizza coppie key/value. I valori possono essere ricercati
per parola chiave.
Una prima differenza tra un ArrayList e una Map è che ogni entry di una Map è una coppia di
oggetti e non un singolo oggetto.
Una seconda differenza tra un ArrayList e una Map è che gli elementi di una Map non si
selezionano con un indice, ma specificando una chiave.
Un elenco telefonico è un esempio di Map: le chiavi sono i nomi degli utenti e i valori sono i
rispettivi numeri di telefono.
Le Map funzionano bene quando si conosce la chiave e si vuole conoscere il valore associato
(operazione nota come lookup). L'operazione inversa (reverse lookup) è possibile, ma molto meno
efficiente.
La classe HashMap è una classe che implementa l'interfaccia Map. I metodi più importanti della
classe HashMap sono put e get.
Il metodo put inserisce una coppia key/value nella mappa, mentre il metodo get restituisce il
valore associato a una chiave.
HashMap<String, String> phoneBook = new HashMap<String, String>();
//in Java 7 si può anche scrivere
//HashMap<String, String> phoneBook = new HashMap<>();
phoneBook.put("Charles Nguyen", "(531) 9392 4587");
phoneBook.put("Lisa Jones", "(402) 4536 4674");
phoneBook.put("William H. Smith", "(998) 5488 0123");
Ricercare un numero di telefono dal phoneBook per una data persona è semplice:
String number = phoneBook.get("Lisa Jones");
System.out.println(number);
Esercizio 5.25: metodo size();
Esercizio 5.25: sviluppare la classe MapTester.
Esercizi da 5.27 a 5.32
Come effettuare un ciclo sugli elementi di una Mappa? Esistono diversi modi:
ciclo for-each: http://stackoverflow.com/questions/1066589/java-iterate-through-hashmap
If you're only interested in the keys, you can iterate through the keySet() of the map:
Map<String, Object> map = ...;
for (String key : map.keySet()) {
// ...
}
If you only need the values, use values() :
for (Object value : map.values()) {
// ...
}
Finally, if you want both the key and value, use entrySet() :
for (Map.Entry<String, Object> entry : map.entrySet()) {
String key = entry.getKey();
Object value = entry.getValue();
// ...
}
One caveat: if you want to remove items mid-iteration, you'll need to do so via an Iterator
http://stackoverflow.com/questions/1066589/java-iterate-throughhashmap/1066603#1066603
Iterate through the entrySet like so:
public static void printMap(Map mp) {
Iterator it = mp.entrySet().iterator();
while (it.hasNext()) {
Map.Entry pairs = (Map.Entry)it.next();
System.out.println(pairs.getKey() + " = " + pairs.getValue());
it.remove(); // avoids a ConcurrentModificationException
}
}
Ad esempio per iterare un HashMap<String, String> phoneBook si potrebbe usare un ciclo
for-each come nel seguente esempio:
import java.util.HashMap;
import java.util.Map;
/**
*MapTester implementa un elenco telefonico mediante una classe HashMap.
*
* @author Prof. Malafronte
* @version 0.1
*/
public class MapTester
{
HashMap<String, String> phoneBook;
/**
* Crea un un elenco telefonico
*/
MapTester(){
phoneBook = new HashMap<String,String>();
}
/**
* Inserisce un numero di telefono nel phoneBook
* @param name rappresenta il nome dell'elenco
* @param number rappresenta il numero di telefono
*/
public void enterNumber(String name, String number){
phoneBook.put(name , number);
}
/**
* @param name il nome da ricercare nell'elenco
* @return il numero di telefono corrispondente a name
*/
public String lookupNumber(String name){
return phoneBook.get(name);
}
/**
* Stampa l'elenco dei nomi e dei numeri di telefono
*/
public void printMap(){
for (Map.Entry<String, String> entry : phoneBook.entrySet()) {
String key = entry.getKey();
String value = entry.getValue();
System.out.println("nome = " + key + " numero = " + value);
// ...
}
}
/**
* Stampa l'elenco dei nomi
*/
public void printMapKey(){
for ( String key : phoneBook.keySet()) {
System.out.println("nome = " + key);
// ...
}
}
/**
* Stampa l'elenco dei numeri di telefono
*/
public void printMapValues(){
for ( String value : phoneBook.values()) {
System.out.println("numero = " + value);
// ...
}
}
}
Esercizio: Modificare la classe Responder del progetto tech-support1 in modo da utilizzare un
HashMap per contenere le associazioni tra parole chiave e risposte. Questa versione funziona
qualora l'utente scrive una parola corrispondente a una chiave.
Come fare una versione del progetto che funziona anche quando l'utente scrive un'intera frase
contenente una parola chiave? Concettualmente dobbiamo trasformare la stringa inserita
dall'utente in un insieme di parole, e poi dobbiamo controllare se almeno una di queste parole
corrisponde ad una parola chiave. Tutto ciò sarà più semplice usando il concetto di Set e i metodi
predefiniti della classe String.
Concetto di Set: classe HashSet
Cosa rappresenta un Set? La documentazione standard afferma che: “A collection that contains no
duplicate elements. More formally, sets contain no pair of elements e1 and e2 such that
e1.equals(e2), and at most one null element. As implied by its name, this interface models the
mathematical set abstraction.”
La libreria Java standard fornisce diverse varianti di Set, quella che analizzeremo qui è quella
chiamata HashSet. Così come ArrayList è una particolare List, anche HashMap è una
particolare Map.
Qualche esempio di codice:
import java.util.HashSet;
...
HashSet<String> mySet = new HashSet<String>();
mySet.add("one");
mySet.add("two");
mySet.add("three");
Per iterare su un HashSet
for(String item : mySet) {
do something with that item
}
In un Set non c'è uno specifico ordine tra gli elementi e inserire un elemento più volte non ha
nessun effetto sul Set.
Suddivisione di stringhe
Il metodo getInput di InputReader può essere modificato in modo da restituire un HashSet di
parole anziché una stringa
private Scanner reader;
public InputReader()
{
reader = new Scanner(System.in);
}
public HashSet<String> getInput()
{
System.out.print("> "); // print prompt
String inputLine = reader.nextLine().trim().toLowerCase();
String[] wordArray = inputLine.split(" ");
// add words from array into hashset
HashSet<String> words = new HashSet<String>();
for(String word : wordArray) {
words.add(word);
}
return words;
}
Il metodo per dividere le stringhe in sotto-stringhe delimitate da un carattere è il metodo split(), che
in realtà accetta espressioni ben più complesse di un semplice delimitatore.
Si noti che l'utilizzo di un HashSet asicura che non ci siano duplicazioni nelle parole inserite
nell'insieme.
La creazione di una collection di tipo HashSet potrebbe essere fatta utilizzando la classe Arrays e
il metodo statico asList anziché utilizzare il for-each:
HashSet<String> words = new HashSet<String>(Arrays.asList(wordArray));
Rivediamo il progetto tech-support-complete.
Esercizi
Esercizio: creare la classe MyStack a partire dalla classe ArrayList. Implementare tutti i metodi
della classe Stack come descritti nella documentazione Java:
http://docs.oracle.com/javase/7/docs/api/java/util/Stack.html
La classe avrà come tipo base Track vista precedentemente. In aggiunta ai metodi definiti nella
documentazione Java la classe Mystack avrà anche un metodo shallowCopy e un metodo deepCopy.
//restituisce una copia dell'oggetto MyStack copiando campo per campo
public MyStack shallowCopy()
//restituisce una copia dell'oggetto ricreando gli oggetti di cui è composto lo stack
public MyStack deepCopy()
Esercizio: implementare la stessa classe dell'esercizio precedente, utilizzando un array come tipo
base per lo stack di Track.
Per approfondimenti sulla copia (cloning di oggetti) si veda il link:
http://howtodoinjava.com/2012/11/08/a-guide-to-object-cloning-in-java/
Esercizio: Creare la classe MyQueue usando un array per memorizzare gli elementi della coda. Gli
elementi base siano oggetti della classe Track. Ipotizzare di avere un array gestito come buffer
circolare: i puntatori al primo e all'ultimo elemento, rispettivamente head e bottom dovranno
essere incrementati in aritmetica modulo N dove N è la dimensione dell'array. Implementare i
metodi dell'interfaccia Queue come descritti nella documentazione Java:
http://docs.oracle.com/javase/7/docs/api/java/util/Queue.html
Esercizio: realizzare la classe Complesso che rappresenta un numero complesso. In particolare
realizzare i metodi che permettono di effettuare il prodotto, la somma, la sottrazione tra numeri
complessi e la conversione da coordinate cartesiane a polari e viceversa.
Esercizio: realizzare la classe Matrice che rappresenta le matrici di numeri interi NxM. Realizzare i
metodi: somma, differenza, prodotto righe per colonne, somma di tutti gli elementi, trasposta,
matrice ordinata (una nuova matrice con gli elementi disposti in ordine di riga). Modificare la classe
matrice in modo che gli elementi della matrice siano numeri complessi
5.7 La documentazione delle classi
Uso di javadoc
In BlueJ si può richiamare Javadoc per generare automaticamente la documentazione a partire dal
codice selezionando Tools>Project Documentation.
Le regole per scrivere documentazione con javadoc sono semplici:
I commenti per javadoc sono espressi così:
/**
This is a javadoc comment.
*/
Such a comment immediately preceding the class declaration is read as a class comment. If the
comment is directly above a method signature, it is considered a method comment.
In Java, using javadoc, several special key symbols are available for formatting the documentation.
These key symbols start with the @ symbol and include
@version
@author
@param
@return
Tutti i dettagli su javadoc si possono trovare nella documentazione ufficiale Java:
http://www.oracle.com/technetwork/java/javase/documentation/index-137868.html
http://stackoverflow.com/questions/8493352/how-to-make-documentation-with-netbeans-andjavadoc
http://docs.oracle.com/javase/6/docs/technotes/tools/windows/javadoc.html
Ad esempio:
A doc comment is written in HTML and must precede a class, field, constructor or method declaration. It is made up of
two parts -- a description followed by block tags. In this example, the block tags are , , and .
/**
* Returns an Image object that can then be painted on the screen.
* The url argument must specify an absolute {@link URL}. The name
* argument is a specifier that is relative to the url argument.
* <p>
* This method always returns immediately, whether or not the
* image exists. When this applet attempts to draw the image on
* the screen, the data will be loaded. The graphics primitives
* that draw the image will incrementally paint on the screen.
*
* @param url an absolute URL giving the base location of the image
* @param name the location of the image, relative to the url argument
* @return
the image at the specified URL
* @see
Image
*/
public Image getImage(URL url, String name) {
try {
return getImage(new URL(url, name));
} catch (MalformedURLException e) {
return null;
}
}
Notes:

The resulting HTML from running Javadoc is shown below

Each line above is indented to align with the code below the comment.


The first line contains the begin-comment delimiter ( ).
Starting with Javadoc 1.4, the leading asterisks are optional.

Write the first sentence as a short summary of the method, as Javadoc automatically places it in the method
summary table (and index).

Notice the inline tag , which converts to an HTML hyperlink pointing to the documentation for the URL class.
This inline tag can be used anywhere that a comment can be written, such as in the text following block tags.
If you have more than one paragraph in the doc comment, separate the paragraphs with a paragraph tag, as
shown.


Insert a blank comment line between the description and the list of tags, as shown.

The first line that begins with an "@" character ends the description. There is only one description block per doc
comment; you cannot continue the description following block tags.

The last line contains the end-comment delimiter ( ) Note that unlike the begin-comment delimiter, the end-comment contains only a single asterisk.
For more examples, see Simple Examples.
So lines won't wrap, limit any doc-comment lines to 80 characters.
Here is what the previous example would look like after running the Javadoc tool:
getImage
public Image getImage(URL url,
String name)
Returns an object that can then be painted on the screen. The argument must specify an absolute URL. The argument
is a specifier that is relative to the argument.
This method always returns immediately, whether or not the image exists. When this applet attempts to draw the image
on the screen, the data will be loaded. The graphics primitives that draw the image will incrementally paint on the screen.
Parameters:
- an absolute URL giving the base location of the image.
- the location of the image, relative to the argument.
Returns:
the image at the specified URL.
See Also:
Public vs. Private3
Fields, constructors, and methods can all be either public or private, although so far we have seen
mostly private fields and public constructors and methods. We shall come back to this below.
Access modifiers define the visibility of a field, constructor, or method. If a method, for example,
is public, it can be invoked from within the same class or from any other class. Private
methods, on the other hand, can be invoked only from within the class in which they are
declared. They are not visible to other classes.
3
Per i dettagli sui modificatori di accesso si veda
http://docs.oracle.com/javase/tutorial/java/javaOO/accesscontrol.html
The interface of a class is the set of details that another programmer using the class needs to see. It
provides information about how to use the class. The interface includes constructor and method
signatures and comments. It is also referred to as the public part of a class. Its purpose is to define
what the class does.
The implementation is the section of a class that defines precisely how the class works. The
method bodies, containing the Java statements, and most fields are part of the implementation.
The implementation is also referred to as the private part of a class. The user of a class does not
need to know about the implementation. In fact, there are good reasons why a user should
be prevented from knowing about the implementation (or at least from making use of
this knowledge).
This principle is called information hiding.
The public keyword declares an element of a class (a field or method) to be part of the interface
(i.e., publicly visible); the private keyword declares it to be part of the implementation (i.e.,
hidden from outside access).
Information Hiding
A programmer making use of a class should not need to know the internals; second, a
user should not be allowed to know the internals.
A class should not “know” (depend on) the internal details of another class. The programmer of
both classes might even be the same person, but the classes should still be loosely coupled.
It is important to understand that the private keyword enforces information hiding by not allowing
other classes access to this part of the class. This ensures loose coupling and makes an application
more modular and easier to maintain.
Regola generale:
I campi dovrebbero essere sempre privati per non esporre all'esterno la propria struttura.
Alcuni metodi di una classe possono essere privati, quando hanno senso solo come metodi di
servizio all'interno di una classe. Ad esempio metodi che rappresentano blocchi di codice che si
ripetono e sono utilizzati da altri metodi.
La parola chiave static
The keyword static is Java’s syntax to define class variables. Class variables are fields that are
stored in a class itself, not in an object. This makes them fundamentally different from instance
variables (the fields we have dealt with so far). Exactly one copy exists of a class variable
at all times, independent of the number of created instances.
Ad esempio: http://docs.oracle.com/javase/tutorial/java/javaOO/classvars.html
public class Bicycle {
private int cadence;
private int gear;
private int speed;
// add an instance variable for the object ID
private int id;
// add a class variable for the
// number of Bicycle objects instantiated
private static int numberOfBicycles = 0;
...
}
Class variables are referenced by the class name itself, as in
Bicycle.numberOfBicycles
This makes it clear that they are class variables.
Le costanti – static final
http://docs.oracle.com/javase/tutorial/java/javaOO/classvars.html
The static modifier, in combination with the final modifier, is also used to define constants.
The final modifier indicates that the value of this field cannot change.
For example, the following variable declaration defines a constant named PI, whose value is an
approximation of pi (the ratio of the circumference of a circle to its diameter):
static final double PI = 3.141592653589793;
Constants defined in this way cannot be reassigned, and it is a compile-time error if your program
tries to do so. By convention, the names of constant values are spelled in uppercase letters. If the
name is composed of more than one word, the words are separated by an underscore (_).
5.8 Per ripassare
 Jar file
6 Il progetto delle classi (cenni) - Design gudelines
Coupling (the lower is better)
The term coupling refers to the interconnectedness of classes. We have already discussed in
earlier chapters that we aim to design our applications as a set of cooperating classes that
communicate via well-defined interfaces. The degree of coupling indicates how tightly these
classes are connected. We strive for a low degree of coupling, or loose coupling.
The degree of coupling determines how hard it is to make changes in an application. In a
tightly coupled class structure, a change in one class can make it necessary to change several
other classes as well. This is what we try to avoid, because the effect of making one small change
can quickly ripple through a complete application. In addition, finding all the places where changes
are necessary and actually making the changes can be difficult and time consuming.
Cohesion (the higher is better)
The term cohesion relates to the number and diversity of tasks for which a single unit of an
application is responsible. Cohesion is relevant for units of a single class and an individual
method. Ideally, one unit of code should be responsible for one cohesive task (that is, one task
that can be seen as a logical unit). A method should implement one logical operation, and a class
should represent one type of entity.
The main reason behind the principle of cohesion is reuse: if a method or a class is responsible
for only one well-defined thing, then it is much more likely that it can be used again in a different
context. A complementary advantage of following this principle is that, when change is required to
some aspect of an application, we are likely to find all the relevant pieces located in the same unit.
Approfondimenti:
Patterns in Practice: Cohesion and Coupling by Jeremy Miller
http://en.wikipedia.org/wiki/Coupling_(computer_programming)
http://en.wikipedia.org/wiki/Cohesion_(computer_science)
6.2 Duplicazione del codice (da evitare)
Code duplication is an indicator of bad design. The problem with code duplication is that any
change to one version must also be made to another if we are to avoid inconsistency. This increases
the amount of work a maintenance programmer has to do, and it introduces the danger of bugs.
Per evitare la duplicazione del codice basta racchiudere il codice utilizzato più volte in metodi
e/o classi che sono poi richiamate quando serve.
6.3 Incapsulamento e dipendenza (information hiding enforces
decoupling)
Proper encapsulation in classes reduces coupling and thus leads to a better design.
The encapsulation guideline (hiding implementation information from view) suggests that only
information about what a class can do should be visible to the outside, not about how it does it.
This has a great advantage: if no other class knows how our information is stored, then we can
easily change how it is stored without breaking other classes.
We can enforce this separation of what and how by making the fields private and using an
accessor method to access them.
6.4 Responsability driven design (to redouce coupling)
We have seen in the previous section that making use of proper encapsulation reduces coupling and
can significantly reduce the amount of work needed to make changes to an application.
Encapsulation, however, is not the only factor that influences the degree of coupling. Another
aspect is known by the term responsibility-driven design.
Responsibility-driven design expresses the idea that each class should be responsible for
handling its own data. Often, when we need to add some new functionality to an application, we
need to ask ourselves in which class we should add a method to implement this new function.
Which class should be responsible for the task? The answer is that the class that is responsible for
storing some data should also be responsible for manipulating it.
6.5 Refactoring
Refactoring is the activity of restructuring existing classes and methods to adapt them to
changed functionality and requirements. Often in the lifetime of an application, functionality is
gradually added. One common effect is that, as a side-effect of this, methods and classes slowly
grow in length.
Refactoring is the rethinking and redesigning of class and method structures. Most commonly
the effect is that classes are split in two or that methods are divided into two or more methods.
Refactoring can also include the joining of multiple classes or methods into one, but that is less
common than splitting.
Refactoring per supporto multilingua (esempio)
Tipo enumerativo Java
http://docs.oracle.com/javase/tutorial/java/javaOO/enum.html
public enum CommandWord
{
// A value for each command word, plus one for unrecognized
// commands.
GO, QUIT, HELP, UNKNOWN;
}
In un frammento di codice il tipo enumerativo potrebbe essere utilizzato come nel seguente
esempio4:
switch (commandWord) {
case UNKNOWN:
System.out.println("I don’t know what you mean...");
break;
case HELP:
4
As of Java 7, strings can also be used as values in switch statements. In Java 6 and earlier, strings cannot be used in switch
statements.
printHelp();
break;
case GO:
goRoom(command);
break;
case QUIT:
wantToQuit = quit(command);
break;
}
La gestione comandi testuali inseriti da un utente potrebbe essere fatta associando i comandi
(stringhe) inserite dall'utente con i valori di tipo enumerativo.
public makeCommads()
{
validCommands = new HashMap<String, CommandWord>();
validCommands.put("go", CommandWord.GO);
validCommands.put("help", CommandWord.HELP);
validCommands.put("quit", CommandWord.QUIT);
}
Con il procedimento ora indicato diventerebbe molto semplice effettuare un supporto multilingua
per l'applicazione. Basterebbe creare una mappa per ogni lingua.
6.6 Metodi statici (keyword static)
Oltre alle variabili static viste in § 5.7 esistono anche i metodi static. Un metodo static può essere
invocato riferendosi al nome della classe e non al riferimento di un oggetto di quella classe. Ad
esempio:
http://www.tutorialspoint.com/java/java_nonaccess_modifiers.htm
public class InstanceCounter {
private static int numInstances = 0;
public static int getCount() {
return numInstances;
}
private static void addInstance() {
numInstances++;
}
InstanceCounter() {// nel costruttore richiamo il metodo addInstance
//riferendomi alla classe InstanceCounter
InstanceCounter.addInstance();
}
public static void main(String[] arguments) {
System.out.println("Starting with " +
InstanceCounter.getCount() + " instances");
for (int i = 0; i < 500; ++i){
new InstanceCounter();
}
System.out.println("Created " +
InstanceCounter.getCount() + " instances");
}
}
This would produce the following result:
Started with 0 instances
Created 500 instances
Il metodo Main (rivisitato)
Un programma Java che non sia eseguito da BlueJ, ma ad esempio da console deve avere un
metodo main che rappresenta il primo metodo eseguito quando si lancia l'applicazione. Tale
metodo è un metodo static perché esso deve essere eseguito prima ancora che si possa creare
alcun oggetto. Il metodo main di Java è simile al Main di C# visto in precedenza.
http://docs.oracle.com/javase/tutorial/getStarted/application/index.html
/**
* The HelloWorldApp class implements an application that
* simply displays "Hello World!" to the standard output.
*/
class HelloWorldApp {
public static void main(String[] args) {
System.out.println("Hello World!"); //Display the string.
}
}
La classe Math
Un esempio di classe che contiene tanti (e solo) metodi statici è la classe java.lang.Math
http://docs.oracle.com/javase/7/docs/api/java/lang/Math.html
Ad esempio, per utilizzare il metodo che effettua il logaritmo naturale di un numero double basta
scrivere Math.log(myNumber). Si noti che Math essendo in java.lang non richiede di
utilizzare import java.lang.Math,
Testing is an activity that is concerned with finding out whether a segment of code contains
any errors. Testing well is not easy, and there is much to think about when testing a program.
Debugging comes after testing. If tests have shown that an error is present, we use debugging
techniques to find out exactly where the error is and how to fix it. There can be a significant
amount of work between knowing that an error exists and finding the cause and fixing it.
Writing for maintainability is maybe the most fundamental topic. It is about trying to write code
in such a way that errors are avoided in the first place and, if they still slip in, that they can be
found as easily as possible. Code style and commenting are part of it, as are the code quality
principles that we have discussed in the previous chapter. Ideally, code should be easy to understand
so that the original programmer avoids introducing errors and a maintenance programmer can easily
find possible errors.
In practice, this is not always simple. But there are big differences between few and many errors
and also between the effort it takes to debug well-written code and not-so-well-written code.
7.1 Testing con BlueJ
Aprire il progetto online-shop. Ispezionare il codice per capire cosa fa. Provare a usare il codice
creando qualche oggetto SalesItem e inserire alcuni commenti per ogni oggetto SalesItem.
Effettuare i test riportati negli esercizi 7.1 fino a 7.10.
Quando si testa un'applicazione è possibile eseguire due tipologie di testing. Il test positivo e il test
negativo.
Test positivo: è un test fatto per verificare che le funzionalità dell'applicazione siano quelle attese.
Ad esempio per verificare che un metodo restituisca un valore atteso per una data lista di valori
dell'input.
Test negativo: è un test fatto per verificare che le funzionalità dell'applicazione non diano il
risultato atteso quando i valori dell'input non rientrano nei limiti previsti per l'imput. Ad esempio un
metodo che dovrebbe accettare un numero compreso tra un valore minimo e un valore massimo,
non dovrebbe dare il risultato atteso quando il valore dell'input non è compreso nell'intervallo dei
valori ammessi.
7.2 Test automatici
I test sul software sono una parte molto importante dello sviluppo del software, ma richiedono
molto tempo e talvolta, essendo ripetitivi, sono molto noiosi. È importante avere degli strumenti che
permettano di effettuare test ripetitivi automatici. In particolare i test di regressione sul software
vanno a verificare che alcune funzionalità di un'applicazione continuino a funzionare anche quando
si apportano modifiche o si introducono funzionalità aggiuntive.
JUnit
BlueJ utilizza il framework JUnit ( http://junit.org/ ), largamente impiegato anche in altri ambienti
di sviluppo per effettuare test automatici sul codice java. È un framework che semplifica e
automatizza la creazione di test sulle classi. L'aspetto veramente interessante di JUnit è che esso
rende possibile creare test sulle classi sin dalla stesura delle prime funzionalità permettendo di
testare tutto il codice prodotto, durante la sua creazione.
Per imparare a usare JUint apriamo il progetto online-shop-junit. Questo progetto contiene le
stesse classi del progetto online-shop con l'aggiunta della classe SalesItemTest. La classe
SalesItemTest è una classe annotata come <<unit test>> ed è colorata in maniera differente
dalle normali classi. Spostando la classe SalesItem si sposta anche la classe SalesItemTest dal
momento che quest'ultima è una classe di testing associata alla classe SalesItem.
Per utilizzare Junit in BlueJ bisogna abilitare i tools per i test di regressione andando in
Tools>Preferences>Interfaces, spuntando l'opzione “show unit testing tools” e confermando la
selezione su ok.
Dopo aver abilitato i tools per il testing è possibile effettuare i test o cliccando su “Run Tests”
oppure facendo clic col tasto sinistro del mouse sulla classe SalesItemTest e selezionando il test che
si vuole effettuare.
Nel progetto online-shop-junit la classe SalesItemTest è già stata creata e contiene già
alcuni test di regressione. Possiamo lanciare i test cliccando su RunTests. Otteniamo lo stesso
risultato se selezioniamo “Test All” facendo click con il tasto sinistro del mouse sulla classe
SalesItemTest. Facendo click con il tasto sinistro del mouse su SalesItemTest possiamo
anche lanciare in maniera selettiva uno dei test di regressione presenti.
Analizziamo il codice di un test, ad esempio il test che verifica i commenti per inseriti per un
articolo:
/**
* Test that a comment can be added, and that the comment count is correct afterwards.
*/
@Test
public void testAddComment()
{
SalesItem salesIte1 = new SalesItem("Java for complete Idiots", 21998);
assertEquals(true, salesIte1.addComment("James Duckling", "This book is great. I learned
all my Java from it.", 4));
assertEquals(1, salesIte1.getNumberOfComments());
}
Il metodo testAddComment crea un oggetto SalseItem chiamato salesIte1 e poi vi aggiunge
un commento, verificando che il valore restituito da addComment sia true. In questo codice è
fondamentale il metodo assertEquals che verifica l'uguaglianza tra il valore restituita da un
metodo e il valore atteso. Il metodo assertEquals è poi utilizzato per verificare che il metodo
getNumberOfComments restituisca un solo commento per l'articolo salesIte1.
I test di regressione possono essere scritti manualmente seguendo lo schema del metodo
testAddComment (usando l'annotazione @Test prima del metodo e poi usando gli assert di
Junit), ma uno degli aspetti più interessanti dell'uso di Junit in BlueJ è che la scrittura dei test
di regressione può essere automatizzata registrando una macro.
Una fixture è un insieme di oggetti in un determinato stato che servono da base per l'esecuzione di
tutti i test di una unit test. Supponiamo che per eseguire i test bisogna creare due oggetti SalesItem e
che su uno di questi bisogna aggiungere un commento. Anziché creare gli oggetti prima di ogni test
è possibile creare una fixture nel seguente modo: si creano gli oggetti nel solito modo nell'object
bench e poi facendo click con il tasto sinistro del mouse sulla classe di test si seleziona l'opzione
“Object Bench to Test Fixture”. Il risultato sarà che gli oggetti scompaiono dall'object bench e
compaiono nel metodo setUp della classe di test. Se in seguito si volesse modificare lo stato degli
oggetti della fixture basterebbe selezionare sulla classe di test l'opzione “Test Fixture to Object
Bench” effettuare le modifiche volute e poi richiamare “Object Bench to Test Fixture”.
7.3 Debugging
Quando un test fallisce o ci si accorge che il programma non funziona bisogna trovare l'errore (o gli
errori). Questa attività si chiama debugging e può essere svolta con varie tecniche che possono
andare dall'analisi del codice all'uso del debugger come già mostrato in precedenza.
7.4 Per ripassare
Documentazione ufficiale Oracle - Learning the Java Language: Table of Contents:
http://docs.oracle.com/javase/tutorial/java/TOC.html
Guida rapida con esempi: Tutorialspoint.com
http://www.tutorialspoint.com/java/
La documentazione ufficiale delle API e dei tools Java:
http://docs.oracle.com/javase/7/docs/
Scarica