Documenti di Didattica
Documenti di Professioni
Documenti di Cultura
CARATTERISTICHE DI UML
UML consente di modellare i sistemi software come insiemi di oggetti che collaborano tra di loro.
UML ha due aspetti:
- Struttura statica: riguarda i tipi di oggetti necessari per modellare il sistema e como sono tra
loro correlati;
- Comportamento dinamico: riguarda il ciclo div ita di questi oggetti e come collaborano per
fornire le funzionalità richieste al sistema.
STRUTTURA DI UML
- Costituenti fondamentali:
o Entità: elementi che verranno modificati;
o Relazioni: specificano come due o più entità sono correlate;
o Diagrammi di base: modi di visualizzazione del nostro sistema
- Meccanismi comuni: tecniche comuni per raggiungere specifici obbiettivi con UML;
- Architettura: il modo in cui UML esprime l’architettura del sistema;
DIAGRAMMI DI UML
Il modello statico fissa le entità̀ e le relazioni strutturali tra le entità. Il modello dinamico fissa il
modo in cui le entità interagiscono per generare il comportamento richiesto al sistema software.
Non è necessario seguire un determinato ordine nella creazione dei diagrammi UML.
I diagrammi costituiscono non solo una vista del modello ma anche il principale strumento per
aggiungere nuove informazioni al modello. Ogni diagramma può avere un frame. UML 2 introduce
una nuova sintassi per i diagrammi, illustrata nella seguente figura:
I diagrammi fondamentali che useremo saranno: diagramma delle classi, diagramma degli oggetti,
diagramma dei package, diagramma di sequenza
1
MECCANISMI COMUNI DI UML
UML prevede quattro meccanismi comuni che vengono applicati in modo consistente in tutto il
linguaggio, essi descrivono quattro diverse strategie della modellizzazione ad oggetti:
- Specifiche: sono la componente testuale del modello, che descrive la semantica degli
elementi;
- Ornamenti: rendono visibili specifiche delle entità del diagramma;
- Distinzioni comuni: descrivono modi diversi di ragionare sul mondo e sono essenzialmente
classificatore-istanza, interfaccia-implementazione;
- Meccanismi di estensibilità: servono per andare incontro all’esigenze di tutti, possono
essere:
o Vincoli: estendono la semantica di un elemento, è una frase di testo racchiusa tra
parentesi graffe che definisce una condizione o una regola che riguarda l’elemento di
modellizzazione e che deve risultare sempre vera.
Una classe può essere rappresentata senza ornamenti, con il semplice rettangolo e il nome.
La nozione astratta di un’entità è differente da una sua istanza. L’interfaccia rappresenta cosa fa un
oggetto ma non dice come lo fa, ossia la sua implementazione.
Un oggetto può essere definito come un’entità discreta che incapsula stato, comportamento.
Mascherare la parte di un oggetto sotto forma di strato di funzioni si chiama incapsulamento, ogni
oggetto è l’istanza di una classe. Tutti gli oggetti hanno
- Identità: è la peculiarità dell’esistenza ovvero ciò che lo distingue da tutti gli altri oggetti;
- Stato: viene stabilito dai valori degli attributi, ovvero è l’insieme dei valori degli attributi;
- Comportamento: sono le azioni che un oggetto può eseguire.
2
L’implementazione di un comportamento si chiama metodo, l’esecuzione di questi metodi può
portare variazioni agli attributi.
Per incapsulamento intendiamo l’avvolgere gli attributi ed i metodi degli oggetti in una singola
unità. Gli oggetti collaborano tra di loro stabilendo collegamenti e scambiandosi messaggi, quando
un oggetto riceve un messaggio, esso esamina le sue operazioni per trovare una la cui segnatura
corrisponda alla segnatura del messaggio, se tale operazione esiste allora l’oggetto la esegue.
Queste segnature sono composte come dal nome del messaggio, dai tipi di parametri e dal valore
restituito.
I nomi degli oggetti e dei metodi vengono scritti in lowerCamelCase, ogni valore di un attributo di
un oggetto si rappresenta come ‘nome: tipo = valore’
CLASSE
Una classe può essere definita come il descrittore di un insieme di oggetti che condividono gli stessi
attributi, le stesse operazioni, gli stessi metodi, le stesse relazioni e lo stesso comportamento.
RELAZIONI
Una relazione può essere definita come una connessione tra elementi del modello. Formata da una
classe con determinati attributi e metodi, che tramite un collegamento detto istanzia attribuisce ad
ogni oggetto della classe un valore agli attributi. Questa istanzia viene rappresentata con una linea
tratteggiata che indica una relazione di dipendenza dell’oggetto alla classe, una dipendenza è
definita come una relazione tra due elementi in cui un cambiamento in un elemento può influenzare
l’altro elemento.
L’istanziazione è la creazione di nuove istanze di elementi nel modello, se applicata alle classi
porta la formazione degli oggetti. I metodi costruttori indicano dei metodi associati alle classi che
hanno lo scopo di inizializzare le variabili di istanza. In un modello di analisi sono fondamentali le
informazioni: quelle che non possono mancare sono: nome della classe, attributi fondamentali,
operazioni fondamentali, stereotipi.
SCRITTURA
La visibilità: viene applicata agli attributi e alle operazioni delle classi ed è uno dei possibili
ornamenti:
3
Il tipo: aspetto molto importante per gli attributi che specificano la natura di quell’attributo,
abbiamo:
La molteplicità: usata per la progettazione ma anche per l’analisi indica da cosa sia composto un
attributo, per esempio
il valore iniziale consente di specificare il valore che un attributo assume quando si istanzia un
oggetto della classe.
OPERAZIONI
Le operazioni sono funzioni associate ad una certa classe, hanno tutte le caratteristiche delle
funzioni. La loro segnatura è la seguente:
Ogni operazione può avere un valore di ritorno (return) ed è scritto nel seguente modo:
Per restituire due valore possiamo scrivere: restituisce il valore massimo e il valore minimo
maxMin (in a : Integer, in b : Integer, return valoreMax : Integer, return valoreMin : Integer)
oppure per renderlo più ordinato non scriviamo il return e applichiamo come prima:
AMBITO
Generalmente gli oggetti hanno una propria copia degli attributi e delle operazioni definiti dalla loro
classe, si dice che hanno un ambito di istanza. Possiamo anche definire attributi e operazioni
condivisi tra tutti gli oggetti di una stessa classe, in questo caso si dice che essi hanno ambito di
classe.
4
COLLEGAMENTI
È una connessione tra due oggetti che consente loro di scambiarsi messaggi, per stabilire un
collegamento bisogna che almeno uno dei due oggetti disponga di un riferimento dell’altro. Un
diagramma degli oggetti mostra gli oggetti con le loro relazioni. Gli oggetti si organizzano in
gerarchie o reti, le gerarchie organizzano gli oggetti in modo molto ordinato e strutturato ma molto
rigido, ogni gerarchia ha infatti in nodo radice e ogni altro nodo ha un solo oggetto al di sopra di se.
Con le reti invece non abbiamo un oggetto radice ma ogni aspetto può essere direttamente connesso,
le reti hanno strutture molto flessibili e non esiste un concetto implicito e nessun nodo ha la
supremazia sugli altri.
ASSOCIAZIONE
È una connessione tra due classi e indica che si possono quindi avere dei collegamenti tra i rispettivi
oggetti. È comune anche che una classe abbia un’associazione con se stessa e questa viene chiamata
associazione riflessiva. Per ciascuna associazioni è possibili definire:
- un nome: dovrebbero essere dei verbi o frasi verbali, può essere preceduto da una freccia
che indica la direzione in cui si legge, e vengono scritti in lowerCamelCase
- i nomi dei ruoli
- le molteplicità: è uno dei vincoli che può avere un associazioni e limita il numero di oggetti
di una classe che possono partecipare in una relazione in un dato istante.
- la navigabilità: indica che è possibile spostarsi da un qualsiasi oggetto della classe origine a
uno o più oggetti della classe destinazione, viene segnata aggiungendo una croce o una
freccia all0estremità della relazione, possiamo usare tre modi:
o completamente esplicita: tutte le frecce e le croci sono visualizzate;
o completamente invisibile: non vengono visualizzate ne croci ne frecce;
o eliminare tutte le croci: le assunzioni bidirezionali non hanno frecce, le assunzioni
unidirezionali ne hanno solo una
CLASSI ASSOCIAZIONE
Sono classi associate in una relazione tra due classi, sono costituite dalla classe, dall’associazione e
dalla linea tratteggiate
GENERALIZZAZIONE
La generalizzazione è una relazione tra un elemento e uno più specializzato in cui l’elemento più
specializzato è completamente consistente con quello più generico ma contiene più informazioni.
La generalizzazione divide le classi in superclass (quelle più generiche) e subclass (quelle più
specifiche), tramite questa partizione parliamo di ereditarietà.
EREDITARIETÁ
Le subclass ereditano dalla superclass tutti gli attributi, le operazioni, le relazioni e vincoli ed è
possibile che queste aggiungano altre caratteristiche. Può succedere che alcune operazioni e metodi
della superclass non vengano implementate nella subclass e allora diremo che l’operazione è
astratta, una gerarchia definisce dei livelli di astrazione. In UML una classe può ereditare anche da
due superclass e questo viene chiamato caso di ereditarietà multipla.
5
POLIMORFISMO
È la capacità di presentarsi sotto molte forme, è uno dei pilastri della programmazione insieme
all’ereditarietà e all’incapsulamento. Permette di progettare sistemi più semplici perché consente di
trattare oggetti differenti allo stesso modo, ovvero permette di inviare lo stesso messaggio a oggetti
di diverse classi.
PACKAGE
È l’entità di raggruppamento in UML, ogni package possiede un suo spazio dei nomi, al cui interno
i nomi degli elementi devono essere univoci. Un package è un meccanismo generalizzato per
organizzare e raggruppare elementi e diagrammi. Un package può essere utilizzato per:
- fornire spazio dei nomi incapsulato al cui interno tutti i nomi devono essere univoci;
- raggruppare gli elementi semanticamente correlati;
UML mette a disposizione lo stereotipo <<topLevel>> per identificar il package di livello più alto.
La visibilità per gli elementi di un package può essere solo pubblica o privata.
Un elemento di uno spazio di nomi per referenziare un elemento di un altro spazio dei nomi, deve
indicare oltre al nome del destinatario, anche un cammino per arrivarci ed è chiamato pathname o
nome qualificato. Si crea un nome qualificato premettendo al nome dell’elemento i nomi dei
package in cui risiede, separati da una coppia di due punti (::)
Una relazione di dipendenza tra package indica che uno di questi dipende da un altro tramite
qualche modo.
Allo stesso modo delle classi anche tra package esiste la generalizzazione e l’ereditarietà con
superpackage e subpackage.
- diagrammi delle classi di analisi: mostrano le classi di analisi che interagiscono per
realizzare il caso d’uso;
- diagrammi di interazione: mostrano le collaborazioni e le interazioni tra le istanze specifiche
che realizzano il caso d’uso;
- requisiti speciali: formulano i requisiti del caso d’uso eventualmente emersi durante il
processo di realizzazione dei casi d’uso;
- raffinamento del caso d’uso: aggiornare il caso d’uso qualora si ottengano nuove
informazioni
6
LINEE DI VITA
La loro rappresentazione nei diagrammi è composta da una coda a forma di riga verticale
tratteggiata.
MESSAGGI
Un messaggio rappresenta un tipo specifico di comunicazione tra le due linee di vita in interazione,
quando una linea di vita riceve un messaggio di chiamata vuol dire che viene invocata
un’operazione che ha la stessa segnatura del messaggio, per ogni messaggio di chiamata ricevuto da
una linea di vita ci deve essere un’operazione corrispondente. Quando una linea adi vita esegue un
messaggio si dice che ha il focus di controllo o di attivazione (segnate da piccoli rettangoli sulla
linea di vita), un focus di controllo può essere annidato in un altro focus di controllo.
DIAGRAMMI DI INTERAZIONE
- diagrammi di sequenza: mostrano le interazioni tra le linee di vita come una sequenza di
eventi ordinati temporalmente.
- diagrammi di comunicazione
- diagrammi di interazione generale
- diagrammi di temporizzazione
I diagrammi di sequenza possono esser divisi in aree chiamate frammenti combinati, ogni
frammento è composto da:
7
OPERATORI
- opt (option): c’è un singolo operando che viene eseguito se la condizione è vera (if…then);
- alt (alternatives): viene eseguito l’operando la cui condizione è vera (else);
- loop (loop): esegue un loop di volte una determinata condizione (while);
- break (break): se la condizione di guardia è vera, viene eseguito l’operando, non il resto
dell’interazione;
- ref (reference): il frammento combinato fa riferimento a un’altra interazione
PROGETTAZIONE
L’aggregazione è una relazione tra oggetti poco forte, calcolatore e periferiche, è del tipo tutto-
parte per cui un aggregato è costituito da molte parti, è transitiva, asimmetrica e riflessiva.
INTERFACCIA
Dichiarazione di una variabile: è formata da un tipo e da un nome, abbiamo 8 tipi primitivi, i quali
comprendono:
Questi due passaggi possono essere eseguiti sia separatamente uno dietro l’altro oppure incorporati
numero = 0 //inizializzazione
8
Quando una variabile può assumere uno tra un sottoinsieme definito di valori usiamo un enum:
Size s = Size.small;
If (s == Size.extralarge) {
Per le stringhe non abbiamo un tipo primitivo, ma una classe predefinita chiamate String che viene
inizializzata tramite l’associazione di una stringa di caratteri racchiusa in “ “ tramite l’operatore
new che appunto indica la creazione di una nuova stringa:
Possiamo comparare due stringhe per vedere se sono uguali tramite il metodo equals()
La stringa vuota “ “ è una stringa di lunghezza 0. Una variabile di tipo String può assumere un
valore specifico chiamato null, questo valore indica che non vi è un oggetto associato alla variabile.
ISTRUZIONI CONDIZIONALI
Ciclo if…else, “se la condizione è soddisfatta eseguire lo statement altrimenti eseguire il resto”
If (condition) {
statement 1
} else
statement 2
9
per una selezione di condizioni multiple abbiamo anche il costrutto switch con i vari case
switch (state) {
case 0:
case 1:
break
default //interruzione del ciclo finale, rappresenta l’ultimo case se gli altri non sono
verificati
Per una ripetizione di n volte finchè una condizione non viene verificata usiamo il ciclo while
While (condition)
Statement;
per una una ripetizione di n volte ‘controllata’ ovvero tramite l’uso di un contatore usiamo il ciclo
for. Per un valore inizializzato i = 0, incrementarlo di1 (i++) a ogni fine del ciclo fino a quando la
condizione (i<5) è soddisfatta’ significa che quando i tramite l’incremento di 1 supera 5 il ciclo
finisce.
System.out.println(i)
ARRAY
Gli array sono una sequenza omogenea di elementi identificati da un unico identificatore, usiamo
l’operatore [ ]. Per riempire un array abbiamo bisogno di un’inizializzazione. Gli array hanno varie
proprietà, la più importante è length che permette di leggere la lunghezza dell’array
10
AVVIO ALLA SCRITTURA DI UN CODICE
Funzione main, identifica la classe principale del mio programma quella dal quale viene eseguito
tutto il processo, per la stesura del codice bisogna innanzitutto procedere con:
Ogni classe può accedere alle classi pubbliche predefinite tramite import java.
Per inserire una classe in un package è sufficiente scriver il nome del package in cima al codice,
prima dei blocchi in cui si definisce la classe stessa.
Il class path è l’insieme dei percorsi che possono contenere file delle classi, viene utilizzato nel
processo di ricerca delle classi da parte del compiler.
11
SUGGERIMENTI SULLA CREAZIONE DELLE CLASSI
EREDITARIETÁ
L’idea principale è quella di creare nuove classi costruite su classi esistenti, ereditare significa
proprio riusare metodi e proprietà di una classe in un’altra con la possibilità di aggiungere altre
caratteristiche.
public class Manager extends Employee{ … //la classe manager eredita da employee
Diremo che Manager è una subclass e employee la superclass, una subclass o classe derivata può
aggiungere campi, metodi e fare override (s’intende la modifica di un metodo appartenente ad una
superclass). Per accedere alle informazioni della superclass si usa il keyword super, può essere
usata anche per riferirsi ad un costruttore della superclass.
Con dynamic binding si intende il meccanismo di selezioni del metodo relativo alla classe a cui si fa
riferimento a tempo di esecuzione (run time)
I metodi e i campi di una classe sono accessibili ai membri della stessa e ad altre classi nello stesso
package. I campi e i metodi dichiarati come private sono accessibili soltanto dall’interno della
classe, mentre quelli dichiarati come public sono accessibili da qualunque classe in qualsiasi
package. Un ulteriore modificatore di accesso e il protected i quali metodi e campi dichiarati sono
visibili sono dalle subclass anche se definiti in package differenti.
Buona regola per accertarsi che l’ereditarietà sia una buona scelta è il metodo is-a ovvero afferma
che ogni oggetto della subclass è anche oggetto della superclass, viene formulata anche con il
principio di sostituzione, ovvero si può usare l’istanza di una subclass ogni volta che il programma
si aspetta l’istanza di una superclass.
Possiamo decidere quali classi non possono essere ereditate dette classi finali, tramite l’uso del
modificatore di non accesso final, se viene applicato ad un metodo quel metodo non sarà possibile
fare override. Metodi di classe dichiarate con final hanno automaticamente metodi final.
12
Il processo di conversione forzata da un tipo ad un altro è chiamato casting, la sintassi del cast in
java è il seguente: T x = (T) y; e vale per i tipi primitivi. Prima di eseguire un cast è buona norma
verificare che questo sia possibile per non ricadere in errore di ClassCastException quindi useremo
il termine istanceof per verificare che l’oggetto sia istanziato nella determinata classe.
CLASSI ASTRATTE, prese ad esempio la classe Employee e la classe Student possiamo astrarre il
concetto e dire che entrambi ereditano da una classe Person: quindi bisogna creare un accessore
abstract, che però non va implementato, resta scritto ma non associato, è possibile applicarlo anche
ai metodi per intendere che quei metodi non hanno un’implementazione. Una classe astratta però
può tranquillamente avere anche campi e metodi concreti.
I metodi dichiarati astratti vengono poi implementati in una subclass che eredita dalla classe
astratta, se questa subclass non implementa i metodi astratti anche lei viene definita come subclass
astratta.
Madre di tutte le super class è la classe Object e fortunatamente non va scritta nella stesura del
codice, utilizziamo la variabile di tipo Object in una classe per riferirci a ciascun tipo di oggetto.
Questa superclass ha in essa molti metodi che vengono automaticamente ereditati dalle altre classi
come ad esempio: equals il quale determina se due riferimenti ad oggetti sono uguali tra loro,
toString classico esempio di una classe che usiamo spesso che è derivata da Object la quale
restituisce una stringa che rappresenta il valore dell’oggetto
INTERFACCE
Tramite le interfacce possiamo descrivere che cosa delle classi devono fare, senza specificare come
lo devono fare. Sono un insieme di requisiti che le classi dovranno rispettare per essere conformi
all’interfaccia
Esempio: il metodo sort della classe Arrays promette di ordinare un array di oggetti, purché questi
appartengano a classi che implementano l’interfaccia Comparable. Ogni classe che implementa
l’interfaccia Comparable dovrà disporre di un metodo compareTo che prende un parametro Object
e restituisce un intero
Per far si che una classe posso implementare un’interfaccia dobbiamo fare due cose:
L’operatore new non può essere usato per istanziare un’interfaccia, possiamo usare variabili
interfaccia, una variabile interfaccia deve riferirsi ad oggetti di una classe che la implementa.
13
INTERFACCIA COMPARATOR
Per confrontare due stringhe sulla base della loro lunghezza invece che su base alfabetica, diventa
utile l’utilizzo di un comparatore, il quale è un’istanza che implementa l’interfaccia comparator
INTERFACCIA CLONEABLE
Indica che una classe ha un metodo clone, tramite il quale può essere può essere fatta una copia di
un oggetto inizialmente identico ad un altro ma che potrà divergere dallo stato dell’originale nel
corso del tempo. Il metodo clone della classe Object è di tipo protetto. Una classe che intende usare
il metodo clone dovrà:
Una classe interna è una classe definita dentro un’altra classe, i motivi per cui implementare in
questo modo le classi possono essere:
- Le inner class possono essere nascoste dalle altre classi nello stesso package;
- I metodi delle inner class possono accedere ai dati dello scope dove sono definiti
- Se non sono statiche contengo un riferimento implicito all’oggetto della classe esterna che lo
ha stanziato, tramite questo riferimento hanno acceso allo stato dell’oggetto esterno.
In altre parole, un metodo di una classe interna ottiene l’accesso a tutti i campi propri dell’oggetto
esterno che lo ha creato. Il compilatore modifica tutti i costruttori delle classi interne, aggiungendo
un parametro per il riferimento alla classe esterna
GENERICS
Il modo più semplice per implementare generalizzazioni in un linguaggio orientato agli oggetti è il
polimorfismo. Con generic programming si intende sviluppare e scrivere un codice che può essere
riusato per oggetti di diversi tipi. I generics implementano il concetto di tipo parametrizzato in quale
permette di avere più tipo, l’intento è quello di estendere l’espressività di una classe o di un metodo.
Il tipo parametrizzato associato ad una classe o ad un metodo indica un tipo non specificato che può
essere deciso all’occorrenza. Ha sintassi del tipo: Foo<T> con Foo che indica una classe e T
rappresenta il tipo non specificato (indica la dichiarazione del parametro) mentre l’istanziazione sta
nel sostituire il tipo T con quello scelto, ad esempio Foo<String>, il risultato di questa istanziazione
è un oggetto ordinario. Possiamo adoperare questa metodologia anche per dichiarare due type
parameter del tipo Foo<T, U>. Possiamo associare il tipo parametrizzato oltre che alle classi anche
ai metodi il quale prenderà il nome di metodo generico che può appartenere ad una classi ordinaria,
per invocazioni a metodi generici che usano tipi primitivi, usiamo l’autoboxing che si occupa di
wrappare (avvolgere) automaticamente i tipi primitivi nelle loro rispettive classi associate.
Quando definiamo un tipo generico, viene automatico identificare il tipo raw corrispondente,
ovvero una versione della classe generica che non specifica l’argomento nelle parentesi angolari.
Un tipo parametrizzato è senza bound allora il tipo raw è Object, altrimenti è un tipo bounding.
14
Per Bound intendiamo che il tipo di argomento generico deve essere una classe o implementare
l’interfaccia specificata.
In questo caso T può essere sostituito con tipo che estendono Comparable.
I tipi wildcard vengono descritti da tipi il cui parametro può cambiare, ad esempio
Pair< ?extends Employee> è un tipo wildcard e denota un tipo generico Pair il cui parametro è una
sottoclasse di Employee. I bound per i tipi wildcard sono simili ai bound per i tipi parametrizzati ma
hanno un fattore addizionale ovvero il supertype bound: super. Si possono usare i tipi wildcard
senza bpund, semplicemente con il simbolo ?, ovvero Pair <?> questo presenta i metodi getFirst() e
void seFirst(?); dove il valore getFirst può essere assegnato ad un Object e il metodo setFirst non
potrà mai essere invocato neppure da un Object.
Allora la differenza principale con il tipo raw di Pair è che in questo possiamo invocare il metodo
setFirst con ogni possibili Object.
A volte si ha bisogno di convertire un tipo primitivo in un oggetto. Tutti i tipi primitivi hanno una
controparte classe: Integer, Long, Float, Double, Short, Byte, Charachter, Boolean. Esse vengono
chiamate classi wrapper e sono immutabili oltre che ad essere final.
Una istanza di una classe wrapper può essere creata a partire dalla controparte primitiva.
Con il termine autoboxing si intende la traduzione automatica del passaggio tra valore primitivo ad
istanza di classe wrapper.
Le classi wrapper offrono molti metodi tra cui: Integer.parseInt(s) che permette di interpretare una
stringa s come un int.
15
COLLECTIONS
Le collections rappresentano strutture dati utili per diversi scopi, una struttura dati è una classe
dedicata a memorizzare e manipolare dei dati. Quindi diremo che le collections rappresentano
strutture dati generiche.
Oltre l’interfaccia Collection, altra interfaccia molto importante è Map la quale rappresenta una
collezione dove ogni elemento è una coppia (k,v) dove k rappresenta una chiave e v un valore, gli
elementi vengono aggiunti tramite v put(K key, V value). Gli elementi di una Map si dicono
indicizzati e si accede ad essi tramite la chiave, utilizzando il metodo V get(K key)
Map<String, Integer> conteggioValori = new HashMap<>(); inizializza una mappa la cui chiave è
una stringa e il valore è un intero chiamato conteggioValori
List<String> elenco = new ArrayList<>(); inizializza una sequenza di stringhe con accesso random
chiamata elenco
Andremo a riempire le nostre mappe tramite il metodo put dopo aver dichiarate ad esempio le
nostre variabili scriveremo alla fine del ciclo: conteggioValore.put(stringa1, valore1)
Andremo a riempire la nostra lista tramite add, dopo aver ricavato i valori da inserire scriveremo:
elencoadd(valori)
16
ERRORI ED ECCEZIONI
Obiettivo del programma quando un’operazione non può essere completata a causa di un errore:
- Ritornare a uno stato sicuro e consentire all’utente di eseguire gli altri comandi;
- Consentire all’utente di salvare tutto il lavoro e terminare il programma senza problemi
La gestione delle eccezioni è quella di trasferire il controllo da dove l’errore è accaduto al gestore di
errori che può affrontare la situazione. Java consente che ciascun metodo abbia un percorso
alternativa di uscita (il metodo esce immediatamente o inizia la ricerca della gestione dell’errore)
La specifica dl linguaggio java chiama qualsiasi eccezione che deriva dalla classe Error o da
RuntimeException come un’eccezione unchecked ovvero non controllata. Tutte le altre eccezioni
sono denominate checked (verificate). Un metodo per gestire le eccezioni è il throw usato alla
subito dopo aver implementato il pezzo di codice che potrebbe generare l’eccezione:
quindi nel caso in cui il file non viene trovato viene gestita l’eccezione
Un’alternativa può essere l’uso della ricerca di eccezioni tramite il try / catch, un metodo che
cattura l’eccezione e la gestisce.
Try {
Code
More code
} catch (ExceptionType e) {
Handler for this type
}
Se un qualunque commando dentro al try lancia un’eccezione del tipo specificato nella clausola
allora il programma salta il resto del try ed esegue la gestione dell’eccezione all’interno del catch.
Se nessuna eccezione viene lanciata all’interno del try allora il codice del catch viene saltato
In aggiunta possiamo usare anche la clausola del finally che viene eseguita sia quando l’eccezione
viene catturata e sia quando non viene catturata. Questa clausola risolve il problema di quando il
nostro codice incontrando un’eccezione termina la sua esecuzione e crea problematiche alle
variabili locali.
17
Uno stack trace è un elenco di chiamate ad un metodo in sospeso in un punto particolare
dell’esecuzione di un programma.
ALBERI
È una delle strutture dati non lineari più importanti, con ‘struttura dati non lineari’ si intende il fatto
che la relazione che organizza i dati all’interno della struttura è più ricca. Avendo i dati organizzati
ad albero riusciamo nello specifico a migliorare l’efficienza di alcuni algoritmi.
Un albero è un tipo astratto che memorizza elementi in modo generico, ad eccezione dell’elemento
in cima, radice, ogni elemento ha un elemento genitore, parent, e zero o più elementi figli,
children.
Definiamo albero T come un insieme di nodi che memorizzano elementi, tra i nodi esiste una
relazione di tipo genitore-figlio. Due nodi che siano figli dello stesso genitore si dicono fratelli.
Un nodo v è esterno se non ha figli, e prendono il nome di foglie, mentre è interno se ha uno o più
figli.
Un ramo, edge, di un albero T è una coppia di nodi (m, v) tali che m è il genitore di v, o viceversa.
Un percorso, path, di un albero T è una sequenza di nodi tale che ciascuna coppia di nodi
consecutivi sia un ramo.
Definiamo il tipo di dato astratto ‘albero’ usando il concetto di posizione come astrazione di un
nodo dell’albero, in ogni posizione è memorizzato un elemento e le posizioni soddisfano le
relazioni genitore-figlio che definiscono la struttura dell’albero. Un oggetto che rappresenta una
posizione in un albero mette a disposizione il metodo getElement() che restituisce l’elemento
memorizzato in questa posizione.
Gerarchia delle classi: interfaccia Tree classe astratta AbstractTree per creare una classe
concreta bisogna implementarre l’interfaccia e fornire l’implementazione dei tre metodi root(),
parent(p), children(p) tutto il resto è ereditabile da abstractTree
Chiamiamo livello d dell’albero T l’insieme di tutti i nodi di T che hanno la stessa profondità d.
È possibile pensare ad un albero binario come struttura concatenata:
I metodi suggeriti per una struttura concatenata di albero binario sono i seguenti:
- attraversamento in pre-ordine: viene visitata per prima cosa la radice e poi si attraversano i
sotto-alberi aventi radice nei suoi figli;
- attraversamento in post-ordine: vengono visitati prima i sotto-alberi aventi radice nei figli
della radice e poi viene vista la radice;
- attraversamento in ampiezza: prevede che vengano visitate tutte le posizioni aventi
profondità d prima di visitare qualsiasi posizione avente profondità d + 1;
- attraversamento in ordine simmetrico: prevede che venga visitata la posizione in esame dopo
aver attraversato il suo sotto-albero sinistro e prima di attraversare il suo sotto-albero destro;
Un albero di ricerca binario è un albero binario che memorizza una sequenza ordinata di elementi.
Possiamo usare l’albero di ricerca binario T associato all’insieme S per verificare se un determinato
valore v sia presente in S, navigando lungo un percorso che scende nell’albero T a partire dalla
radice. Preso un insieme di elementi privi di duplicati, un albero di ricerca binario relativo
all’insieme è un albero binario tale che per ogni posizione interna p sia vero che:
GRAFI
Un grafo è un modo per rappresentare relazioni esistenti tra coppie di entità, è un insieme di entità
chiamati vertici o nodi e una raccolta di collegamenti tra coppie di vertici chiamati archi o lati.
I grafi è anche una struttura dati che permette di rappresentare entità e relazioni diadiche tra esse.
Un grafo G è una coppia G(V,E), dove V è l’insieme dei nodi di G ed E = {{u,v} : u ∈ V, v ∈V} è
l’insieme di archi del grafo G.
Un grafo indiretto è un grafo che non ha auto archi e archi multipli. È definito dal suo insieme di
vertici e dal suo insieme di archi.
Un grafo diretto è un grafo i cui archi sono orientati e sia dato un arco (u,v) i due vertici vengono
chiamati rispettivamente origine e destinazione. L’arco viene detto uscente di u, entrante di v.
20
Un grafo pesato G (V, E, 𝜔) è un grafo, diretto o indiretto, in cui il valore chiamato peso è
assegnato ad ogni arco tramite 𝜔. Con 𝜔 : E R (valore reale)
Consideriamo un grafo come tipo astratto e modelliamo la sua astrazione tramite tre tipi:
Lista di archi: si utilizza una lista non ordinata contenente tutti gli archi
Lista di adiacenze: si utilizza una lista ordinata di vertici, e ad ogni vertice è associata la lista di
archi adiacenti a quel vertice
Mappa di adiacenze: si utilizza una lista ordinata di vertici e ad ogni vertice è associata una mappa
dove gli elementi hanno come chiave un vertice e ad esempio l’arco incidente
Matrice di adiacenze: si utilizza una matrice | V | x | V | ddove (i,j) ≤ i,j ≤ | V |, rappresenta l’arco
incidente ai vertici i e j.
Nota: per ogni vertice v si gestisce una collezione I(v) chiamato insieme di incidenza di v, il quale
contiene tutti gli archi incidenti a v. nel caso del grafo orientato, tutti gli archi entranti e uscenti
vengono memorizzati in due insiemi Iin(v) e Iout(v), di solito l’insieme di incidenza viene
rappresentato tramite una lista e la sua implementazione deve consentire di accedere, dato un
vertice v, all’insieme I(v) con complessità O(1).
I vertici di un grafo possono essere ritenuti vicini o lontani rispetto alla definizione di distanza.
Chiameremo cammino di un grafo una sequenza finita di archi in cui due archi contigui hanno
esattamente un vertice in comune. Il path è un cammino in tutti i vertici sono distinti.
21
La lunghezza di un cammino è il numero di archi di cui consiste.
Un grafo è detto connesso se per ogni coppia di vertici nel grafo, questi due sono connessi
altrimenti si dirà che il grafo è disconnesso. Un grafo orientato è fortemente connesso se per ogni
coppia di vertici u e v, esistono gli archi (u,v) e (v,u).
INPUT/OUTPUT
Chiamiamo in java input stream un oggetto dal quale possiamo leggere una sequenza di byte.
Chiamiamo invece output stream un oggetto sul quale possiamo scrivere una sequenza di byte.
Le classi astratte InputStream e OutputStream sono la base per la gerarchia delle classi degli
input/output.
InputStream ha un metodo astratto abstract int read() che legge un byte e lo restituisce, o -1 se
incontra la fine dell’input stream. Ad esempio System.in permette la lettura di un file input inserito
direttamente dalla console tramite la chiamate di uno Scanner
22
OutputStrem ha un metodo astratto abstract void write(int b) scrive un byte su una location di
output.
Sia per InputStream che per OutputStream esiste una vasta gerarchia di classi che ne derivano come
esiste una vasta gerarchia per le classi Reader e Writer.
Poi compaiono anche FilterInputStrem e FilterOutputStream che vengono utilizzate per aggiungere
funzionalità ai flussi input e output
Quando salviamo dei dati, è possibile scegliere in che formato salvarli, se in binario o di testo.
Quando viene utilizzato il formato testuale va considerato il character encoding (UTF-16).
La classe InputStramWriter trasforma un flusso di input contenente byte in un lettore che emette
unità di codice Unicode.
Il modo più veloce per leggere un input resta però con Scanner
try {
FileInputStream fin = new FileInputStream("traccia_B.txt");
while (scanner.hasNextLine()) {
String riga = scanner.nextLine();
altro metodo per leggere da un file può essere BufferedReader, però non permette la lettura di
numeri.
try {
FileInputStream fin = new FileInputStream("traccia_B.txt");
String line;
while ((line = in.readLine()) != null) {
//fai qualcosa con la riga letta
A volte potrebbe risultare utile salvare gli oggetti creati in file di contenuto testuale. Per scrivere su
un text file usiamo PrintWriter, e può risultare conveniente abbinare all’interno della classe un
metodo per la scrittura come ad esempio scriviEmployee
23