Lezione in Laboratorio 1

Venerdì, 24 Novembre 2006

OBIETTIVI DELLA LEZIONE

In questa lezione in laboratorio vedremo alcuni dettagli di Java che non avevamo ancora affrontato. Inoltre completeremo e discuteremo eventuali esercizi rimasti irrisolti dalle scorse esercitazioni.

Debug di un programma Java

Leggere il valore che le variabili assumono run-time

Spesso un programma contiene errori "run-time" (cioè, vi ricordo, il codice viene compilato correttamente ma poi in esecuzione non fa quello che avremmo voluto) e non è detto sia facile individuarli. Una tecnica utilizzata per localizzare errori si chiama Debug (togliere i bugs, cioè gli errori). Fare il debug di un file consiste nell'eseguire passo per passo le istruzioni del nostro codice ed ad ogni istante poter rilevare cosa contengono le variabili che stiamo manipolando.

Vediamo quali sono i passi che servono per debuggare un file con Eclipse.

Per prima cosa lanciamo JBuilder e creiamo un progetto che contenga il file Java Lune.java che avevevamo già visto durante la lezione 2.

import java.io.*;

class Lune {
  public static void main(String[] args) throws IOException {
    InputStreamReader flussoTesto = new InputStreamReader(System.in);
    BufferedReader bufferTastiera = new BufferedReader(flussoTesto);
    String lineaLetta;

    System.out.print("Quanti anni hai? ");
    lineaLetta = bufferTastiera.readLine();
    int anni = Integer.parseInt(lineaLetta);

    System.out.print("In che mese sei nato (numero)? ");
    lineaLetta = bufferTastiera.readLine();
    short mesi = Short.parseShort(lineaLetta);

    short numeroLune = (short)(12*anni + mesi);
    System.out.println("Durante la tua vita, hai visto " + numeroLune + " lune.");
  }
}

Il nostro obbiettivo è quello di sapere che cosa contenga la variabile numeroLune prima che venga eseguita la riga di codice numero 18 (System.out.println("Durante la tua vita, hai visto " + ...). Vorremmo in sostanza interrompere l'esecuzione del codice ad un certo punto o poterlo eseguire "riga per riga".

Per farlo dobbiamo:

  1. preparare un progetto con Eclipse e copiare il testo del programma (avevamo visto come farlo durante la lezione 2;
  2. andare alla linea 18 (il numero della linea corrente è indicato nella barra di stato di Eclipse). Quindi dobbiamo cliccare due volte sulla barra azzurra che appare di fianco alla linea. Dovrebbe comparire un pallino azzurro che indica che abbiamo stabilito un "breakpoint" (punto di interruzione) a quella riga.
  3. selezionare la “Debug perspective” dal menù “Window” -> “Open perspective” -> “Debug”
  4. lanciare il debug del progetto: dal menù "Run" scegliamo "Debug As" e “Java Application”. L'esecuzione continua normalmente fino a linea 17 compresa (dovete ovviamente fornire al programma gli input richiesti). Quindi si interrompe e la linea 18 (quella con il breakpoint) viene evidenziata in verde chiaro. Notate che nella finestra “Variables” compaiono i valori delle variabili utilizzate nel programma.
  5. Il valore assunto a questo punto dell’esecuzione dalla variabile numeroLune è riportato nella finestra variables.

Vi suggerisco di esplorare il valore delle variabili, in particolare per gli oggetti come lineaLetta. È molto utile perché vi aiuta a comprendere la struttura degli oggetti Java.

Per proseguire l'esecuzione "riga per riga" basta selezionare "Step Over" (o premere F6) o "Step Into" (o premere F5) dal menù "Run". Il secondo a differenza del primo, permette di seguire l'evoluzione del codice anche quando vengono chiamati dei metodi. Se invece siamo soddisfatti con il debug, possiamo continuare l'esecuzione normalmente con "Resume " sempre dal menù "Run" (o premere F8).

Input da console

Notate che nel programma Lune.java per poter utilizzare la console per ottenere l'input dall'utente abbiamo:

  1. istanziato un oggetto della classe InputStreamReader (sottoclasse di java.io.Reader, input modalità testo) a partire dall'oggetto System.in (un oggetto di classe java.io.InputStream, input modalità binaria) che rappresenta lo standard input ed è normalmente associato alla tastiera.
    InputStreamReader flussoTesto = new InputStreamReader(System.in);
    
  2. incartato ("wrapped") lo stream in un oggetto che ci fornisca metodi di input più efficaci come readLine();
    BufferedReader bufferTastiera = new BufferedReader(flussoTesto);
    
  3. letto l'input da tastiera utilizzando il metodo readLine();
    lineaLetta = bufferTastiera.readLine();
    
  4. gestito le eventuali eccezioni di I/O (in questo caso semplicemente con un throws).
    public static void main(String[] args) throws IOException {
    

La classe Scanner

Notate che le operazioni svolte per ottenere l'input da tastiera sono molto simili a quanto fatto nel caso di lettura (e scrittura) di un file. Che fatica rispetto a scanf() del C! Esiste un modo più semplice? A partire da Java 1.5, sì. Vediamolo con un esempio.

import java.util.*;

class LuneScanner {
  public static void main(String[] args) {
    Scanner tastiera = new Scanner(System.in);
    
    System.out.print("Quanti anni hai? ");
    int anni = tastiera.nextInt();

    System.out.print("In che mese sei nato (numero)? ");
    short mesi = tastiera.nextShort();

    short numeroLune = (short)(12*anni + mesi);
    System.out.println("Durante la tua vita, hai visto " + numeroLune + " lune.");
  }
}

Rivediamo i passi seguiti:

  1. Abbiamo istanziato un oggetto di classe java.util.Scanner attorno allo stream dello standard input.
        Scanner tastiera = new Scanner(System.in);
    
  2. quindi abbiamo semplicemente utilizzato i metodi nextInt() e nextShort() per ottenere il parsing dei valori immessi dall'utente:
        int anni = tastiera.nextInt();
    
        short mesi = tastiera.nextShort();
    

La classe Scanner contiene anche altri metodi utili che vi invito a verificare con il manuale. Ad esempio: nextDouble(), nextLine() o next() che restituiscono il successivo/a double, linea e parola rispettivamente.

Formattazione di numeri

Nei vari programma che abbiamo sviluppato durante il corso ci siamo spesso imbattuti nella necessità di stampare a monitor dei double. Di certo non è stato piacevole vedere stampate tutte le cifre decimali. La formattazione dei numeri è sempre stata possibile in Java, ma è divenuta ancora più semplice a partire da Java 1.5.

J2SE 5.0 ha aggiunto il metodo printf(), identico all'equivalente C, alla classe PrintStream. È quindi possibile applicare il metodo all'oggetto System.out. Vediamo un esempio:

double raggio=2.0;
// Calcolo l'area del cerchio
double areaCerchio = Math.pow(raggio,2)*Math.PI;
// stampo l'area del cerchio
System.out.println(areaCerchio);
// 12.566370614359172 ... troppi decimali!
// utilizzo invece printf
System.out.printf("%7.2f\n", areaCerchio);
// 12.57 ... molto meglio!

Il metodo funziona in modo molto simile alla funzione C. Vi ricordo che si utilizza fornendo una stringa che indica la formattazione che si desidera ("format string"). Nell'esempio abbiamo indicato che la variabile fornita deve essere stampata come un numero in virgola mobile (%f) e deve occupare a monitor l'equivalente di 7 caratteri di cui 2 dopo la virgola (7.2). Inoltre abbiamo utilizzato una sequenza di escape (\n) per andare a capo. Vi invito a consultare il manuale per maggiori informazioni sui singoli tag.

E per formattare l'output quando si utilizzano metodi della classe JOptionPane? È possibile utilizzare il metodo static String.format() che funziona in modo molto simile alla funzione C sprintf(). Ad esempio:

double raggio=2.0;
// Calcolo l'area del cerchio
double areaCerchio = Math.pow(raggio,2)*Math.PI;
// stampo l'area del cerchio
JOptionPane.showMessageDialog(null, "L'area del cerchio è" + String.format("%7.2f\n", areaCerchio) );
System.exit(0);

Lab

Esercizio 1 [Soluzione]

Costruire la classe CercaNumeriPrimi che elenchi i numeri primi minori di un dato numero fornito dall’utente.

Suggerimento: utilizzate un oggetto di tipo Vector in cui inserire di volta in volta i numeri primi trovati.

Vi ricordo che 1 non è un numero primo e che un numero è primo se è divisibile solo per 1 e per se stesso. Commentate opportunamente il codice con commenti Javadoc.

Esercizi per gli studenti del corso di Laboratorio di Programmazione ad Oggetti

Un file HTML è solo un file di testo ed in Java possiamo creare e modificare dei file di testo. Perché non scrivere un programma che crei automaticamente delle pagine HTML? E' utilissimo sopratutto per strutture ripetitive come le tabelle. Una breve guida ai TAG HTML la trovate all’indirizzo: http://werbach.com/barebones/barebones.html.

Provate a svolgere gli esercizi 3 e 4 della lezione 14 e l'esercizio 3 della lezione 16. Ne vedremo le correzioni nella prossima esercitazione comune. Potete comunque inviarmi i dubbi o le vostre soluzioni per email o fissare un appuntamente per parlarne a ricevimento.

©2006 Roberto Sassi