AOT AOT LAB LAB

Testo completo

(1)

Agent and Object Technology Lab Dipartimento di Ingegneria dell’Informazione

Università degli Studi di Parma

AOT AOT LAB LAB

Ingegneria del software A

Sviluppo basato su contratti (contratti, eccezioni, asserzioni)

Michele Tomaiuolo

(2)

Agent and Object Technology Lab Dipartimento di Ingegneria dell’Informazione

Università degli Studi di Parma

AOT AOT LAB LAB

Contratti - Sommario

Specifica dei requisiti

Pre- e post-condizioni, invarianti

Responsabilità e contratti

Linguaggi

(3)

3

AOT AOT

LAB LAB Correttezza

Rispetto a cosa valutiamo la correttezza di un programma?

Idea del programmatore

Non formulata, non documentata, facilmente dimenticata

A volte incompleta, mutevole

Specifiche

Formulate, scritte

Studiate attentamente e condivise

Formali o informali

Parte del programma

(4)

AOT AOT

LAB LAB Specifiche formali

 Tecniche formali per la specifica di tipi di dati astratti 1. Specifiche algebriche

Equazioni che definiscono come i metodi operano sui dati

2. Specifiche assiomatiche

Espressioni logiche (asserzioni) associate a classi e metodi

Spesso distinte in invarianti, precondizioni e postcondizioni

(5)

5

AOT AOT

LAB LAB Precondizioni and postcondizioni

Precondizioni

Stabiliscono se è possibile chiamare un metodo

Prerequisiti per l’attivazione

Postcondizioni

Stabiliscono se il metodo restituisce il valore atteso, o ha l’effetto desiderato

… In relazione ai parametri (che soddisfano le precondizioni)

Definiscono il significato del metodo

(6)

AOT AOT

LAB LAB Linguaggio per asserzioni

Espressioni logiche

Espressioni e funzioni booleane del linguaggio di programmazione

Semplici, ma problema se errori al loro interno

Quantificatori

Universali (per ogni…) ed esistenziali (esiste…)

Richiedono programmazione, cicli ecc.

Possono essere dispendiosi da valutare

Strumenti speciali

 old expr – Il valore dell’espressione all’inizio del metodo

 nochange – Modo per imporre che il metodo non cambi lo stato dell’oggetto

Altrimenti asserzioni informali

Scritte in linguaggio naturale

(7)

7

AOT AOT

LAB LAB Divisione delle responsabilità

Una classe gestisce certe funzionalità, da esprimenre come responsabilità a cui non dovrebbe venir meno

Dividere le responsabilità ed evitare sovrapposizioni

Senza divisione ben definita delle responsabilità

Tutte le classi assumono grosse responsabilità

Tutte le parti del programma controllano tutte le possibili condizioni (programmazione difensiva)

Un grosso programma viene ancora più grosso

Con divisione ben definita delle responsabilità

Metodi possono operare con sicurezza sotto certe assunzioni

È chiaro quali parti dovrebbero controllare certe condizioni

Simplifica il programma

(8)

AOT AOT

LAB LAB Oggetti e loro responsabilità

Pre- e post-condizioni usate per dividere le

responsabilità tra classi in programmi object-oriented

Soddisfare le precondizioni è responsabilità dell’oggetto chiamante, o client

Soddisfare le postcondizioni è responsabilità dell’oggetto chiamato, o server

Errore del chiamante se una precondizione di un metodo non è soddisfatta

Errore del metodo stesso se una delle sue postcondizioni non è soddisfatta

(9)

9

AOT AOT

LAB LAB Responsabilità e contratti

Precondizioni + postcondizioni = contratto

… tra classe chiamante e classe chiamata

L’infrazione di un contratto dovrebbe essere trattata come problema serio

Un errore rispetto alle specifiche

Dovrebbe sollevare una eccezione

Con tutta probabilità interrompere l’esecuzione

(10)

AOT AOT

LAB LAB Esempio di contratto

sqrt(x : float) : float

Precondizioni: x >= 0

Postcondizioni: abs(result * result - x) <= 0.000001

Oggetto chiamante

Obblighi: deve passare un numero non negativo

Benefici: riceve la radice del numero

Oggetto chiamato

Obblighi: restituisce un numero r tale che r * r = x

Benefici: può assumere che x non è negativo

(11)

11

AOT AOT

LAB LAB Invariante di classe

Invariante di classe: vincolo che deve valere per ogni stato stabile di un oggetto, durante tutto il suo ciclo di vita

Rafforzamento generale di pre- e post-condizioni

“Criterio di sanità” dell’oggetto

Deve essere soddisfatto dal costruttore

Deve essere mantenuto dai metodi pubblici

Ma non necessariamente da metodi privati o protetti

(12)

AOT AOT

LAB LAB Ereditarietà e contratti

Classe A { op(. . .) {

require pre-cond-1 . . .

ensure post-cond-1 }

invariant inv-cond-1 }

Classe B : A { op(. . .) {

require pre-cond-2 . . .

ensure post-cond-2 }

invariant inv-cond-2 }

Che relazione c’è tra le asserzioni di una classe e quelle dei suoi discendenti?

?

?

?

(13)

13

AOT AOT

LAB LAB Ereditarietà e contratti

 Polimorfismo: possibile invocazione del metodo di una sottoclasse, anzichè quello della superclasse

 I metodi delle sottoclassi non possono reidefinire arbitrariamente i metodi delle superclassi

 I contratti della sottoclasse devono rispettare i contratti della superclasse, devono essere loro sottocontratti

1. Le precondizioni non devono essere più forti

2. Le postcondizioni non devono essere più deboli

3. Gli invarianti di classe non devono essere più deboli

(14)

AOT AOT

LAB LAB Invarianti di ciclo

Invarianti non limitati a classi

Invarianti di ciclo importante strumento di controllo

int div(int x, int y) { // division by repeated subtraction // require x >= 0 && y > 0;

int rest = x;

int quotient = 0;

while (rest >= y) {

// invariant rest + quotient * y = x;

rest = rest - y;

quotient = quotient + 1;

}

return quotient;

// ensure rest + quotient * y = x && rest < y && rest >= 0;

(15)

15

AOT AOT

LAB LAB Design by contract

Design by Contract (DBC): uso di asserzioni in varie vasi di sviluppo

Progetto: approccio pragmatico alle specifiche

Implementazione: guida e limita la programmazione

Documentazione: importanti informazioni aggiunte alle interfacce

Test: controllo a run time per rispetto delle specifiche

Le precondizioni limitano il lavoro di test

Le postcondizioni e gli invarianti di classe aiutano a trovare errori

Uso finale: sollevate eccezioni se le asserzioni sono violate

(16)

AOT AOT

LAB LAB Linguaggi e contratti

Eiffel è il linguaggio che supporta meglio il paradigma Design by Contract

Paradigma proposto e sviluppato da Betrand Meyer (creatore del linguaggio Eiffel)

Implementazioni per Java disponibili come estensioni

Spesso sfruttano il meccanismo delle annotazioni

JContract, JContractor, Contract4J, C4J, DBCProxy…

Implementazioni per C# e altri linguaggi .NET

Molti altri…

(17)

Agent and Object Technology Lab Dipartimento di Ingegneria dell’Informazione

Università degli Studi di Parma

AOT AOT LAB LAB

Eccezioni - Sommario

Stack delle chiamate

Tipi di eccezione

Gestione delle eccezioni

Lancio di eccezioni

(18)

AOT AOT

LAB LAB Cos’è un’eccezione?

Il termine eccezione è un’abbreviazione per “evento eccezionale”

Evento che si verifica durante l’esecuzione di un

programma e rompe il suo normale flusso di istruzioni

Quando si verifica un errore in un metodo, il metodo lancia (throw) un’eccezione

Il metodo crea un oggetto eccezione con informationi sull’errore, il suo tipo e le condizioni in cui si è verificato

… e lo consegna all’ambiente di runtime

La piattaforma cerca qualcosa che gestisca l’eccezione

(19)

19

AOT AOT

LAB LAB Stack delle chiamate

Call stack

Lista ordinata di metodi invocati al momento

dell’errore

Exception handler

La piattaforma cerca nel call stack un metodo che contenga un blocco di codice che possa gestire l’eccezione

(20)

AOT AOT

LAB LAB Ricerca del gestore di eccezioni

 La ricerca comincia nel metodo dove si verifica l’errore, e prosegue in ordine inverso rispetto alle invocazioni

1. Se c’è un gestore

appropriato per il tipo di eccezione…

Il gestore cattura (catch) l’eccezione

2. Se non c’è un gestore appropriato…

(21)

21

AOT AOT

LAB LAB Catch or specify

 I programmi Java, per essere compilati, devono rispettare la regola:

“Gestisci o specifica le eccezioni”

 Codice che può lanciare una eccezione racchiuso in:

1. Un blocco try che catturi l’eccezione (handler) 2. Un metodo che specifichi il lancio dell’eccezione:

clausola throws che includa l’eccezione

La regola non vale per tutte le eccezioni

Tre categorie fondamentali di eccezioni

Solo una soggetta alla regola

(22)

AOT AOT

LAB LAB Gerarchia di eccezioni

(23)

23

AOT AOT

LAB LAB Eccezioni controllate

Condizioni eccezionali che una applicazione ben scritta (affidabile) dovrebbe prevedere e risolvere

Es. Richiesto nome file per costruire un FileReader

Ma file non esistente

Il costruttore lancia FileNotFoundException

Un programma ben scritto cattura l’eccezione, notifica all’utente l’errore e chiede un nuovo nome di file

Le eccezioni controllate (checked) sono soggette alla regola “cattura o specifica”

Tutte le eccezioni sono controllate

Eccetto Error, RuntimeException, e sottoclassi

(24)

AOT AOT

LAB LAB Errori

Condizioni eccezionali esterne all’applicazione, che l’applicazione spesso non può prevedere o risolvere

Non soggetti alla regola “cattura o specifica”

 Error e sottoclassi

Es. Si apre un file in lettura

Ma c’è un guasto hardware o di sistema che impedisce la lettura

Viene lanciato IOError

L’applicazione potrebbe catturare l’eccezione, ma potrebbe anche andar bene terminare l’esecuzione (con messaggio o stack trace)

(25)

25

AOT AOT

LAB LAB Eccezioni di runtime

Condizioni eccezionali interne all’applicazione, ma che non si riesce a prevedere o risolvere (spesso bug)

Non soggette alla regola “cattura o specifica”

Bug o uso scorretto di API

 RuntimeException e sottoclassi

Es. Nome file per creare FileReader

A causa di un errore logico si passa null al costruttore…

Che lancia NullPointerException

L’applicazione può catturare l’eccezione, ma probabilmente…

Ha più senso eliminare il bug che provoca l’accezione!

Errori ed eccezioni di runtime sono noti assieme come eccezioni non controllate (unchecked)

(26)

AOT AOT

LAB LAB ListOfNumbers

public class ListOfNumbers { // This class won't compile by design!

private List vector;

private static final int SIZE = 10;

public ListOfNumbers () {

vector = new ArrayList(SIZE);

for (int i = 0; i < SIZE; i++) { list.add(i); // autoboxing

} }

public void writeList() {

PrintWriter out = new PrintWriter(new FileWriter("out.txt"));

for (int i = 0; i < SIZE; i++) {

out.println("Value at: " + i + " = " + vector.get(i));

}

out.close();

} }

(27)

27

AOT AOT

LAB LAB Errori di compilazione

Costruttore FileWriter

Apre un file testuale in scrittura

Lancia IOException

Se il file non può essere aperto

Errore di compilazione (checked)

Metodo List.get

Lancia ArrayIndexOutOfBoundsException

Se l’indice è fuori range

 index < 0 || index >= size()

Ma non genera un errore a tempo di compilazione (unchecked)

(28)

AOT AOT

LAB LAB Blocco try

1. Blocco try per ogni istruzione che genera eccezione 2. Blocco try unico che cattura tipi diversi di eccezioni

try {

System.out.println("Entered try statement");

out = new PrintWriter(new FileWriter("OutFile.txt"));

for (int i = 0; i < SIZE; i++) {

out.println("Value at: " + i + " = "

+ vector.get(i));

} }

(29)

29

AOT AOT

LAB LAB Blocchi catch

Ogni blocco catch è un gestore d’eccezioni…

Per il tipo d’eccezione indicato come argomento

La piattaforma invoca il primo gestore nello stack…

Il cui tipo di argomento generalizza il tipo dell’eccezione lanciata

try { // …

} catch (FileNotFoundException e) {

System.err.println("FileNotFoundException: " + e.getMessage());

} catch (IOException e) {

System.err.println("Caught IOException: " + e.getMessage());

}

(30)

AOT AOT

LAB LAB Gestire una eccezione

Il gestore può fare più che scrivere messaggi

Error recovery

Chiedere all’utente di prendere una decisione

Propagare l’errore all’esterno usando eccezioni concatenate…

Possibile visualizzare lo stack dei metodi

Utile in fase di debugging

Throwable.printStackTrace

(31)

31

AOT AOT

LAB LAB Blocco finally

Eseguito sempre

Impedisce che le istruzioni di cleanup siano scavalcate

Es. Il file dovrebbe venir chiuso in tutti e tre i casi

 IOException, ArrayIndex…, nessuna eccezione

try { // …

} catch { // … } finally {

if (out != null) {

System.out.println("Closing PrintWriter");

out.close();

} else {

System.out.println("PrintWriter not open");

} }

(32)

AOT AOT

LAB LAB Try, catch, finally

public void writeList() { PrintWriter out = null;

try {

System.out.println("Entering try statement");

out = new PrintWriter(new FileWriter("out.txt"));

for (int i = 0; i < SIZE; i++) {

out.println("Value at: " + i + " = " + vector.get(i));

}

} catch (ArrayIndexOutOfBoundsException e) {

System.err.println("Wrong array index: " + e.getMessage());

} catch (IOException e) {

System.err.println("Caught IOException: " + e.getMessage());

} finally {

if (out != null) {

System.out.println("Closing PrintWriter");

out.close();

} else {

System.out.println("PrintWriter not open");

}

(33)

33

AOT AOT

LAB LAB Possibili esecuzioni

1. new FileWriter lancia IOException

2. vector.get lancia ArrayIndexOutOfBounds…

3. out.println lancia IOException 4. Nessuna eccezione

(Seguire il flusso di istruzione nei diversi casi)

(34)

AOT AOT

LAB LAB Altrimenti: throws

Se un metodo non cattura le eccezioni controllate che possono verificarsi al suo interno…

Deve specificare che può lanciarle

public void writeList() throws IOException, ArrayIndexOutOfBoundsException { . . . }

Per eccezioni non controllate non è obbliatorio

public void writeList() throws IOException { . . . }

(35)

35

AOT AOT

LAB LAB Lanciare eccezioni

Una eccezione può essere lanciata da

Codice utente, librerie esterne, librerie Java, piattaforma

Sempre lanciata con l’istruzione throw

Disponibili in Java numerose classi di eccezioni

Tutte discendenti di Throwable

Possibile crearne di nuove, per diversi contesti applicativi

public Object pop() { // in a typical Stack class Object obj;

if (size == 0) {

throw new EmptyStackException(); // unchecked }

obj = get(size - 1); set(size - 1, null); size--;

return obj;

}

(36)

AOT AOT

LAB LAB Eccezioni concatenate

Una applicazione può rispondere ad una eccezione lanciandone un’altra

Si dice che la prima eccezione causa la seconda

Metodi e costruttori utili

Throwable getCause()

Throwable initCause(Throwable)

Throwable(String, Throwable)

Throwable(Throwable)

try { // …

} catch (IOException e) {

(37)

37

AOT AOT

LAB LAB Scegliere le eccezioni

 Lanciare un’eccezione, o restituire un valore?

1. Situazione realmente fuori dell’ordinario?

2. Possibile per il chiamate ignorare il problema?

3. Oggetto in stato inconsistente?

 Creare un nuovo tipo di eccezione, o riutilizzare uno di quelli esistenti?

1. Errore concettualmente simile ad una eccezione esistente?

2. Eccezione esistente, controllata o no, di tipo soddisfacente?

3. Nuova eccezione riconducibile ad un tipo di base, da estendere?

(38)

AOT AOT

LAB LAB Aggirare la gestione delle eccezioni

Java non impone ai metodi di catturare o specificare le eccezioni non controllate (RuntimeException, Error e sottoclassi)

I programmatori possono essere tentati di scrivere codice che lancia solo eccezioni non controllate

Scrivere tutte le eccezioni come sottoclassi di RuntimeException

Permettono di scrivere codice senza curarsi di errori di compilazione e senza curarsi di specificare o catturare eccezioni

Può sembrare conveniente, ma si perdono tutti i vantaggi del controllo delle eccezioni, legati alla divisione delle

(39)

39

AOT AOT

LAB LAB Perché specificare le eccezoni?

Perchè i progettisti Java hanno imposto ai metodi di

specificare tutte le eccezioni lanciate al suo interno e non catturate?

Eccezioni lanciate da un metodo sono parte della loro interfaccia pubblica

Chi chiama un metodo deve sapere quali sono le eccezioni lanciate per poter decidere cosa farne

Queste eccezioni sono parte dell’interfaccia pubblica di un metodo al pari dei parametri e del valore di ritorno

(40)

AOT AOT

LAB LAB E perché alcune non specificate??

Se è bene documentare un metodo, includendo le sue eccezioni… allora perchè non specificare anche le

eccezioni di runtime?

Risultato di problemi di programmazione, bug

Al codice client non è richiesto di risolverli o gestirli

Eccezioni aritmetiche, come divisione per zero

Eccezioni sui riferimenti, come accesso a metodi su riferimenti a null

Eccezioni sugli indici di array e liste

Il compilatore non richiede che esse siano catturate o specificate (anche se si può)

Molto numerose e diffuse

Altrimenti programmi meno chiari

(41)

41

AOT AOT

LAB LAB Linee guida

Esempio tipico: se uno dei parametri richiesti è null, il metodo lancia NullPointerException

La chiamata al metodo è errata, bisogna correggere il bug

Non lanciare una eccezione di runtime o creare

sottoclassi di RuntimeException solo per evitare di doverle specificare

Se un client può ragionevolmente risolvere l’eccezione, allora dovrebbe essere controllata

Se un client non può far nulla per risolverla, allora dovrebbe essere non controllata

(42)

AOT AOT

LAB LAB Vantaggi

Gestione errori separata dal codice “regolare”

Propagazione errori attraverso lo stack delle chiamate

Classificazione dei tipi d’errore

(43)

43

AOT AOT

LAB LAB Gestione errori separata

errorCodeType readFile { initialize errorCode = 0;

open the file;

if (theFileIsOpen) {

determine file length;

if (gotTheFileLength) { allocate memory;

if (gotEnoughMemory) { read file into mem;

if (readFailed) { errorCode = -1;

}

} else { errorCode = -2; } } else { errorCode = -3; } close the file;

if (theFileDidntClose &&

errorCode == 0) { errorCode = -4;

} else {

errorCode = errorCode and -4;

}

} else { errorCode = -5; } return errorCode;

}

readFile { try {

open the file;

determine its size;

allocate that much memory;

read the file into memory;

close the file;

} catch (fileOpenFailed) { doSomething;

} catch (sizeDeterminationFailed) { doSomething;

} catch (memoryAllocationFailed) { doSomething;

} catch (readFailed) { doSomething;

} catch (fileCloseFailed) { doSomething;

} }

(44)

AOT AOT

LAB LAB Propagazione errori

method1 {

errorCodeType error;

error = call method2;

if (error) doErrorProcessing;

else proceed;

}

errorCodeType method2 { errorCodeType error;

error = call method3;

if (error) return error;

else proceed;

}

errorCodeType method3 { errorCodeType error;

error = call readFile;

if (error) return error;

else proceed;

method1 { try {

call method2;

} catch (exception e) { doErrorProcessing;

} }

method2 throws exception { call method3;

}

method3 throws exception { call readFile;

}

(45)

45

AOT AOT

LAB LAB Classificazione degli errori

Le eccezioni sono oggetti, istanze di classi in una gerarchia

Es. Eccezioni per I/O discendono tutte da IOException

Discendenti per errori più specifici

 FileNotFoundException se il file non si trova

catch (FileNotFoundException e) { // ...

} catch (IOException e) { // ...

}

(46)

AOT AOT

LAB LAB Costo dei bug

Trovare bug nei programmi non è un compito facile, e nemmeno una esperienza eccitante…

Molti bug possono capitare a causa di specifiche non ben chiare e capite

Barry Boehm: se trovare e correggere un problema in fase di specifica dei requisiti costa 1$, il costo passa a 5$ durante il progetto, $10 durante la programmazione,

$20 durante lo unit testing, e fino a $200 dopo la consegna del sistema

Meglio far emergere i bug nelle prime fasi dello sviluppo!

(47)

Agent and Object Technology Lab Dipartimento di Ingegneria dell’Informazione

Università degli Studi di Parma

AOT AOT LAB LAB

Asserzioni - Sommario

Sintassi

Precondizioni

Postcondizioni

Invarianti di classe

Abilitazione

(48)

AOT AOT

LAB LAB Asserzioni in Java

Nelle prime versioni di Java, non esisteva un

meccanismo per le asserzioni, occorreva ricorrere a soluzioni ad hoc

Asserzioni aggiunte a Java a partire dalla versione 1.4

Possibile attivarle o disattivarle a runtime

Non attraverso una libreria, ma un costrutto del linguaggio, nuova parola riservata: assert

Non si tratta di una soluzione completa di tipo design-by- contract, ma una forma limitata

Altrimenti cambi sostanziali al linguaggio, alterando la semplicità di Java

(49)

49

AOT AOT

LAB LAB Sintassi delle asserzioni

 L’istruzione di asserzione può assumere due forme 1. assert expr1;

 expr1: espressione booleana, se falsa lanciata AssertionError senza messaggio dettagliato

2. assert expr1 : expr2;

 expr2 espressione con un valore

Può includere chiamate a metodi, ma non void

Usata per fornire dettagli al costruttore diAssertionError

(50)

AOT AOT

LAB LAB Inserire asserzioni nel codice

Ci sono situazioni in cui è utile inserire asserzioni

Invarianti interne e di controllo del flusso

Precondizioni, postcondizioni e invarianti di classe

Ci sono anche situazioni in cui sono inappropriate Non usare le asserzioni per

controllare gli argomenti di metodi pubblici

Tipicamente parte delle specifiche (o contratto) del metodo

Da rispettare con asserzioni attive o no

Argomenti sbagliati => eccezioni di runtime appropriate

 IllegalArgumentException,

(51)

51

AOT AOT

LAB LAB Effetti collaterali

Non usare le asserzioni per qualsiasi cosa

necessaria al corretto funzionamento dell’applicazione

Le asserzioni possono essere disabilitate

L’espressione booleana potrebbe non venir valutata

Le espressione dovrebbero essere prive di effetti collaterali

Non dovrebbero avere effetti visibili successivi alla sua valutazione

Possono modificare stato usato solo in altre asserzioni

(52)

AOT AOT

LAB LAB Effetti collaterali

Programma che funziona solo con asserzioni attivate

// Broken! - action is contained in assertion assert names.remove(null);

Forma corretta: eseguire l’azione prima dell’asserzione

// Fixed - action precedes assertion

boolean nullsRemoved = names.remove(null);

assert nullsRemoved;

(53)

53

AOT AOT

LAB LAB Invarianti interne

switch (suit) { case Suit.CLUBS:

...

break;

case Suit.DIAMONDS:

...

break;

case Suit.HEARTS:

...

break;

case Suit.SPADES:

...

default: // add default just to assert: it should not happen!

assert false : suit;

// throw new AssertionError(suit);

// alternative: offers protection // even if assertions are disabled }

(54)

AOT AOT LAB LAB

if (i % 3 == 0) { . . .

} else if (i % 3 == 1) { . . .

} else {

assert i % 3 == 2 : i;

// to state an assumption, here

// instead of a comment, use an assertion!

. . .

Invarianti interne e sul flusso

void foo() { for (...) {

if (...) return;

}

assert false; // Execution should never reach this point!

}

(55)

55

AOT AOT

LAB LAB Precondizioni

Per convenzione, controlli espliciti su precondizioni di metodi pubblici, lancio specifiche eccezioni

Convenzione sempre valida: non usare asserzioni per controllare i parametri di un metodo pubblico

Controllare sempre gli argomenti, anche se asserzioni disabilitate

Asserzioni non lanciano eccezioni specifiche, ma solo AssertionError

/**

* Sets the refresh rate.

* @param rate refresh rate, in frames per second.

* @throws IllegalArgumentException if rate <= 0 or rate > MAX_REFRESH_RATE.

*/

public void setRefreshRate(int rate) {

// Enforce specified precondition in public method if (rate <= 0 || rate > MAX_REFRESH_RATE)

throw new IllegalArgumentException("Illegal rate: " + rate);

setRefreshInterval(1000/rate);

}

(56)

AOT AOT

LAB LAB Precondizioni

Le asserzioni, invece, vanno bene per testare precondizioni di metodi non pubblici

/**

* Sets the refresh interval (which must correspond to a legal frame rate).

* @param interval refresh interval in milliseconds.

*/

private void setRefreshInterval(int interval) {

// Confirm adherence to precondition in nonpublic method

assert interval > 0 && interval <= 1000/MAX_REFRESH_RATE : interval;

... // Set the refresh interval }

(57)

57

AOT AOT

LAB LAB Postcondizioni

/**

* Returns a BigInteger whose value is (this-1 mod m).

* @param m the modulus.

* @return this-1 mod m.

* @throws ArithmeticException m <= 0, or this BigInteger

* has no multiplicative inverse mod m (that is, this

* BigInteger is not relatively prime to m).

*/

public BigInteger modInverse(BigInteger m) { if (m.signum <= 0)

throw new ArithmeticException("Modulus not positive: " + m);

... // Do the computation

// You can test postcondition with assertions // in both public and nonpublic methods

assert this.multiply(result).mod(m).equals(ONE) : this;

return result;

}

(58)

AOT AOT

LAB LAB Memorizzare lo stato iniziale

void foo(final int[] array) {

// Inner class to save state and perform final consistency check class DataCopy {

private int[] arrayCopy;

DataCopy() {

arrayCopy = (int[]) array.clone();

}

boolean isConsistent() {

return Arrays.equals(array, arrayCopy);

} }

DataCopy copy = null;

// Always succeeds; has side effect of saving a copy of array assert ((copy = new DataCopy()) != null);

... // Manipulate array

// Ensure array has same values as before manipulation.

assert copy.isConsistent();

(59)

59

AOT AOT

LAB LAB Invariante di classe

Tipo di invariante interna che vale per ogni istanza, eccetto che durante le transizioni tra stati consistenti

Può specificare relazioni tra più attributi

Dovrebbe essere vera prima e dopo ogni metodo pubblico

Es. Imporre che un albero sia sempre bilanciato e ordinato

Singolo metodo privato chiamato da asserzioni

Asserzione all’uscita di ogni metodo e costruttore pubblico

Se stato incapsulato, non necessaria asserzione all’inizio

// Class invariant: returns true if this tree is properly balanced private boolean balanced() {

. . . }

public someMethod() { . . .

assert balanced();

}

(60)

AOT AOT

LAB LAB Abilitare le asserzioni

Asserzioni disabilitate per default a runtime

Per abilitarle, switch -enableassertions, o -ea,

Per disabilitarle, switch -disableassertions, o –da

Si può specificare una granularità, indicando una classe o un package

Es. Lanciare un programma, BatTutor, con asserzioni abilitate solo nel package com.wombat.fruitbat (e nei sottopackage):

 java -ea:com.wombat.fruitbat... BatTutor

(61)

61

AOT AOT

LAB LAB Design-by-contract - Perché no?

Perchè non fornire funzionalità di tipo design-by-contract complete, come in Eiffel?

Ipotesi considerata

Ma grossi cambi al linguaggio e alle librerie

Gravi inconsistenze tra vecchie e nuove librerie

Non preservata la semplicità caratteristica di Java

 Semplice meccanismo delle asserzioni

Forma limitata di design-by-contract

Appropriata per precondizioni non pubbliche, postcondizioni e invarianti di classe

Precondizioni pubbliche con eccezioni documentate, come

IllegalArgumentException e IllegalStateException

figura

Updating...

Riferimenti

Updating...

Argomenti correlati :