Libro 1 – Java – Capitolo 3

Argomenti

Lo switch case in Java

Lo switch case è la condizione multipla che in java ha la seguente sintassi:

switch (variabile)
{
case valore1: { istruzioni; break;}
case valore 2: { istruzioni; break;}
case valore 3: { istruzioni, break;}
….
case valore n: { istruzioni; break;}
defaul: {istruzioni; break;}
}

Il break interrompe l’esecuzione e fa saltare direttamente alla fine del blocco per eseguire il resto del programma.
Come esercizio di esempio progettiamo in UML e poi in Java una classe di nome Calcolatrice che riceve due numeri reali, in seguito l’utente sceglie fra le quattro operazioni aritmetiche fondamentali e viene eseguita l’operazione e stampato il risultato sullo schermo. Tutto questo viene fatto con un’applicazione Console.
La nostra classe in UML è:

Digramma UML della classe

Il diagramma UML merita una spiegazione: sono stati definiti quattro attributi tre di input e uno di output, il costruttore che riceve in modo parametrico le scelte dell’utente e nel main è svolto il costrutto switch case per decidere quali operazione svolgere”. In particolare nell’invocazione del metodo “rapporto” occorre tenere conto che non è possibile eseguire la divisione per zero e quindi occorre gestire un’eccezione. La stessa cosa dovrà essere fatta quando andremo a leggere i dati di input nel main mediante l’uso della classe Scanner che consente l’input dei dati da tastiera. La classe Scanner già per altro trattata nel capitolo precedente fa parte del package java.util per maggiori informazioni riferirsi alla documentazione ufficiale a questo link,
Il codice Java della nostra classe è:

1  import java.util.Scanner;
2  public class Calcolatrice {
3     private float n1;
4     private float n2;
5     private float r;
6     private char operazione;
7     public Calcolatrice(float x,float y, char op)
8     {
9         this.n1=x;
10        this.n2=y;
11       this.operazione=op;
12    }
13    public float somma()
14    {
15        r=n1+n2;
16        return r;
17    }
18    public float differenza()
19    {
20        r=n1-n2;
21        return r;
22    }
23    public float prodotto()
24    {
25        r=n1*n2;
26        return r;
27    }
28    public float rapporto()
29    {
30        try 
31        {
32            r=n1/n2;
33        }
34        catch (ArithmeticException e)
35        {
36            System.out.println("Errore divisione zero;");
37        }
38    }
39    public String stampa()
40    {
41      String temp="Risultato dell'operazione di:";
42        switch (operazione)
43        {
44            case '+':{ temp=temp+"somma:";
45            break;}
46            case '-': {temp=temp+"differenza:";
47            break;}
48            case '*': {temp=temp+"prodotto:";
49            break;}
50            case '/': {temp=temp+"divisione:";
51            break;}
52        }
53            temp=temp+r;
54          return temp;
55    }
56    public static void main(String[] args) {
57        Scanner sc=new Scanner(System.in);
58        float a=0,b=0;
59        float ris=0;
60        String tmp="";
61        char op;
62        System.out.println("Insersici due nueeri reali e il tipo di operazione:");
63        System.out.println("Somma +:");
64        System.out.println("Differenza -:");
65        System.out.println("Prodotto *:");
66        System.out.println("Rapporto /:");
67        try
68        {
69            System.out.println("Numero 1:");
70            a=sc.nextFloat();
71            System.out.println("Numero 2:");
72            b=sc.nextFloat();
73            System.out.println("Operazione:");
74            tmp=sc.next();
75        }
76        catch (Exception e)
77        {
78            System.out.println("Errore nell'inserimento dati:");
79        }
80        op=tmp.charAt(0);
81        Calcolatrice calc = new Calcolatrice(a,b,op);
82        switch (op)
83        {
84            case '+':
85            {
86                ris=calc.somma();
87                break;
88            }
89            case '-':
90            {
91                ris=calc.differenza();
92                break;
93            }
94            case '*':
95            {
96                ris=calc.prodotto();
97                break;
98            }
99            case '/':
100            {
101                ris=calc.somma();
102                break;
103            }
104        }
105        System.out.println("Risultato:"+ris);
106        System.out.println("Stesso risultato con metodo della classe:");
107        tmp=calc.stampa();
109        System.out.println(tmp);
109        }
110 }
Per continuare a leggere questo articolo devi sottoscrivere un abbonamento
Puoi abbonarti al link al menù principale o cliccando sul link Abbonati Ora!

Il commento al codice è molto semplice: è stato riporto in Java l’insieme dei membri previsti nel diagramma UML. Il metodo stampa prepara mediante l’uso di uno switch da riga 39 a 55, il formato di stampa scegliendo l’opportuno messaggio da stampare che cambia in funzione del tipo di operazione svolta. Nel metodo main (riga da 56 a 109) è inizializzato l’oggetto sc di tipo Scanner per l’inserimento dei dati mediante il costrutto try .. catch, è gestito mediante un istanziamento l’oggetto “calc” di tipo “Calcolatrice” a riga 81, poi mediante uno switch viene scelto quale operazione (metodo invocare per il calcolo (da riga 82 a 104). Un’attenzione alla riga 80 ove la stringa viene convertita in carattere mediante la funzione “charAt(indice della stringa)” che trasforma un elemento della stringa in un char. In Java tutto ciò che viene letto da tastiera è considerato come stringa, mentre un singolo carattere è anche possibile considerarlo come char. In Java conviene utilizzar sempre le stringhe per flussi di dati di più caratteri, in quanto un aggregato di char è un array ed è più articolato gestire le funzionalità. Ad esempio il confronto fra stringhe nel senso di ordinamento alfabetico può avvenire con gli operatori di relazione “<“, “>”, “==”, “!=” (gli ultimi due sono diverso e uguale).

La quarta classe Calcolatrice scientifica

Come esempio ulteriore ampliamo l’esempio precedente e predisponiamo la classe Calcolatrice in modo che possa eseguire l’elevamento a potenza, la radice quadrata di un numero.
La classe avrà un nome diverso e sarà i”CalcolatotriceScientifica”. IL diagramma UML precedente diventa:

Diagramma UML della classe

La classe Math in Java

In Java la classe Math permette di svolgere operazioni matematiche con funzioni scientifiche quali trascendenti, e trigonometriche.
La classe fa parte del package java.lang e possiede molti metodi statici. In questo modo ogni volta che occorre utilizzare una funzione matematica non è necessario istanziare un oggetto di tipo Math ma basta richiamare la funzione avendo cura di aver incluso la classe stessa nel progetto della nostra classe.
Le funzioni sono quindi rappresentate da metodi che in particolare sono pow per l’elevamento a potenza e sqIl diagramma UML merita una spiegazione: sono stati definiti quattro attributi tre di input e uno di output, il costruttore che riceve in modo parametrico le scelte dell’utente e nel main è svolto il costrutto switch case per decidere quali operazione svolgere”. In particolare nell’invocazione del metodo “rapporto” occorre tenere conto che non è possibile eseguire la divisione per zero e quindi occorre gestire un’eccezione. La stessa cosa dovrà essere fatta quando andremo a leggere i dati di input nel main mediante l’uso della classe Scanner che consente l’input dei dati da tastiera. La classe Scanner già per altro trattata nel capitolo precedente fa parte del package java.util per maggiori informazioni riferirsi alla documentazione ufficiale a questo link,
Il codice Java della nostra classe è:

rt per la radice quadrata di un numero. Entrambi i metodi prevedono un valore di ritorno di tipo double ovvero un numero reale in precisione doppia.
Il codice di questa nuova classe è:

1  import java.util.Scanner;
2  import java.lang.Math;
3  public class CalcolatriceScientifica {
4      private float n1;
5      private float n2;
6      private float r;
7      private double r1=0;
8      private char operazione;
9      public CalcolatriceScientifica(float x,float y, char op)
10     {
11        this.n1=x;
12        this.n2=y;
13        this.operazione=op;
14    }
15    public float somma()
16    {
17        r=n1+n2;
18        return r;
19    }
20    public float differenza()
21    {
22        r=n1-n2;
23        return r;
24    }
25    public float prodotto()
26    {
27        r=n1*n2;
28        return r;
29    }
30    public float rapporto()
31    {
32        try 
33        {
34            r=n1/n2;
35        }
36        catch (ArithmeticException e)
37        {
38            System.out.println("Errore divisione zero;");
39        }
40    }
41    public double potenza()
42    {
43        r1=Math.pow(n1,n2);
44        return r1;
45    }
46    public double radice()
47    {
48        r1=Math.sqrt(n1);
49        return r1;
50    }
51    public String stampa()
52    {
53      String temp="Risultato dell'operazione di:";
54        switch (operazione)
55        {
56            case '+':{ temp=temp+"somma:";
57            break;}
58            case '-': {temp=temp+"differenza:";
59            break;}
60            case '*': {temp=temp+"prodotto:";
61            break;}
62            case '/': {temp=temp+"divisione:";
63            break;}
64            case 'p': {temp=temp+"Potenza di:"+n1+" elevato alla "+n2;
65            break;}
66            case 'r': {temp=temp+"Radice quadrata di:"+n1;
67            break;}
68        }
69        if (r1!=0)
70            temp=temp+","+r1;
71        else
72            temp=temp+","+r;
73           return temp;
74    }
75   public static void main(String[] args) {
76        Scanner sc=new Scanner(System.in);
77        float a=0,b=0;
78        float ris=0;
79        String tmp="";
80        char op;
81        System.out.println("Insersici due nueeri reali e il tipo di operazione:");
82        System.out.println("Somma +:");
83        System.out.println("Differenza -:");
84        System.out.println("Prodotto *:");
85        System.out.println("Rapporto /:");
86        System.out.println("Potenza p:");
87        System.out.println("Rapice quadrata r:");
88        try
89        {
90            System.out.println("Numero 1:");
91            a=sc.nextFloat();
92            System.out.println("Numero 2:");
93            b=sc.nextFloat();
94            System.out.println("Operazione:");
95            tmp=sc.next();
96        }
97        catch (Exception e)
98        {
99            System.out.println("Errore nell'inserimento dati:");
100            //codice di gestione eccezione ! //
101        }
102        op=tmp.charAt(0);
103        CalcolatriceScientifica calc = new CalcolatriceScientifica(a,b,op);
104       switch (op)
105        {
106            case '+':
107            {
108                ris=calc.somma();
109                break;
110            }
111            case '-':
112            {
113                ris=calc.differenza();
114                break;
115            }
116            case '*':
117            {
118                ris=calc.prodotto();
119                break;
120            }
121            case '/':
122            {
123                ris=calc.somma();
124                break;
125            }
126            case 'p':
127            {
128                ris=(float)calc.potenza();
129                break;
130            }
131            case 'r':
132            {
133                ris=(float)calc.radice();
134                break;
135            }
136        }
137        System.out.println("Risultato:"+ris);
138        System.out.println("Stesso risultato con metodo della classe:");
139        tmp=calc.stampa();
140       System.out.println(tmp);
141        }
142 }

In questo codice Java è stata apmpiata la classe precedente con l’aggiunta delle operazioni di elevamento a potenza e radice quadrata. E’ stato introdotto un attributo privato di tipo double r1 in quanto i metodi per il calcolo della potenza e della radice quadrata. Inoltre per utilizzar ei metodi pow e sqrt occorre includere anche la classe Math nell’invocazione di tali metodi poiché non prevedono l’istanziamento di un oggetto di tipo Math obbligatoriamente. L’invocazione dei metodi “pow” e “sqrt” sono a riga 43 e 48. Rimane da gestire l’eccezione nelle righe fra la riga 88 e 101.
Infatti nel momento in cui l’utente digita un valore non corretto l’errore si verifica successivamente nei metodi che calcolano l’espressione numerica. Infatti se l’utente fornisce una stringa al posto di un numero un’operazione anche aritmetica non può essere svolta e quindi viene sollevata un’eccezione che non è gestita, in quanto occorre verificare prima se i valori inseriti sono validi.
In questo caso i tre input ovvero i due numeri e il tipo di operaizone sono gestiti da una sola e eccezione e occorre o separare le eccezioni per ogni input oppure uscire dal programma con un errore che riporti che non è possibile andare avanti. Esiste una terza possibilità e cioè nel blocco catch che ha generato l’eccezione richiedere l’inserimento del valore errato.
Per ora possiamo solo inserire a riga 100 l’istruzione return che termina il metodo main e non porta avanti l’esecuzione del programma. La classe sarà migliorata con la risoluzione della convalida dopo che avremo esaminato le strutture cicliche.

Le strutture cicliche in Java

Le strutture cicliche consentono di ripetere blocchi di istruzioni più volte, il numero delle ripetizioni può essere prefissato o indefinito. Nell’ultimo caso il numero delle ripetizione viene determinato da una condizione.
Le strutture indefinite possono essere con condizione iniziale e quindi è utilizzata la struttura ciclica while, o con condizione finale e allora è utilizzata la struttura do .. while.
In dettaglio la struttura generale di un ciclo while è:

while (condizione)
{blocco istruzioni 1;}
blocco istruzioni 2;

La struttura con condizione finale è:

do { blocco istruzioni 1;}
while (condizione);
blocco istruzioni 2;

In entrambi i casi il ciclo è ripetuto quando la condizione è verificata, in caso contrario avviene l’uscita dal ciclo. Una differenza ulteriore fra le due strutture cicliche è legata anche alla possibilità che la condizione sia falsa in partenza. Nel ciclo while se la condizione è falsa in partenza il ciclo non viene ripetuto, nel ciclo do .. while la ripetizione è eseguita almeno una volta anche se la condizione è falsa.
Un terzo tipo di struttura ciclica è il ciclo a ripetizione definita ciclo “for”. In questo caso il blocco di istruzioni da ripetere “corpo del ciclo” sono ripetute un numero prefissato di volte.
Occorre definire sempre una variabile supplementare che è appunto l’indice del ciclo che può essere un tipo numerico, o enumerativo (ad esempio l’insieme dei colori sarà discusso quando si parlerà delle strutture dati).
La struttura generale di un ciclo for è:
for (contatore=inizio;condizione(contatore); contatore=contatore+passo)
{ istruzioni; ..}
La variabile contatore può assumere vari intervalli ed è utilizzata per un conteggio del numero delle ripetizioni.
Alcuni esempi

for (k=0;k<10;k++) è un ciclo che ripete dieci volte;
for (k=-10;k<=10;k=k+2) è un ciclo che esegue un numero di ripetizioni pari a (10–10+1)/2; infatti nel numero delle ripetizioni l’estremo superiore è incluso così come il valore zero, e il passo ovvero il modo in cui deve conteggiare è pari a due.

La ricerca di valori minimi e massimi in sequenze numeriche

Come esempio di applicazione di una struttura ciclica immaginiamo di avere una sequenza numerica del tipo -3, 10, 21, -11, 32, 1, 7, 20, 35 e di voler determinare il valore massimo e minimo. I numeri della sequenza sono puramente indicativi, infatti tali valori saranno digitati in input da tastiera.
La classe Java chiamata test per semplicità sarà costituita solo dal metodo main che sarà suddiviso in cinque parti:
1- Dichiarazione di dati;
2- Inserimento dati;
3- Determinazione del massimo;
4- Determinazione del minimo
5- Stampa risultati

Il punto 4) sarà eseguito con un ciclo while, e il punto 5) con un ciclo for. Il vero problema di questo esercizio e che i dati non sono memorizzati in nessun area di memoria a meno di ricorrere ad una struttura dati organizzata come una array che sarà introdotto in questo esempio, che però sarà ripreso in modo più esteso nel capitolo successivo. In alternativa per poter svolgere questo compito senza l’uso dell’array occorre che il punto 2,3,4 siano svolti insieme. In questo secondo caso non è possibile utilizzare due cicli separati a meno di non eseguire l’inserimento due volte (che è una pratica non consigliabile). Pertanto la soluzione che viene presentata prevede una prima versione con il ciclo for dove sono noti il numero degli elementi e una seconda versione dove è l’utente che determina l’uscita dal ciclo mediante la pressione di un tasto.
Il codice Java è:

1  import java.util.Scanner;
2  public class CicloFor {
3     public static void main(String[] args) {
4          int num, n,k, max, min;
5          System.out.println("Quanti numeri!");
6          Scanner sc =new Scanner(System.in);
7          n=sc.nextInt();
0          System.out.println("Digita un numero");
9          num=sc.nextInt();
10         max=num;
11         min=num;
12         for (k=1;k<n;k++)
13         {
14             System.out.println("Digita un altro numero");
15             num=sc.nextInt();
16             if (num<min)
17                 min=num;
18             if (num>max)
19                 max=num;
20        }
21         System.out.println("Il massimo e il minimo sono:");
22         System.out.println(max+","+min+"\n");
23     }
24 }

La classe contiene un ciclo for che chiede di inserire dei numeri e valuta ogni volta se il numero e maggiore del massimo o minore del minimo in caso affermativo il nuovo massimo e minimo sono assegnati (12-20). Il ciclo for parte con k=1 in quanto il primo numero lo richiediamo all’esterno del ciclo e lo assegniamo al massimo e al minimo come primo riferimento di confronto (righe 8-11). In questo programma Java non sono gestite le eccezioni e quindi necessario migliorare la classe per la gestione delle eccezioni. Un utile esercizio è trasformare il listato sopra in un programma che utilizza il ciclo do .. while o while. In questo caso in entrambi i casi il ciclo dovrà contenere una variabile contatore che conti materialmente il numero di ripetizioni. Il codice è presto fatto:

1  import java.util.Scanner;
2  public class CicloFor {
3     public static void main(String[] args) {
4          int num, n,k=0, max, min;
5          System.out.println("Quanti numeri!");
6          Scanner sc =new Scanner(System.in);
7          n=sc.nextInt();
0          System.out.println("Digita un numero");
9          num=sc.nextInt();
10         max=num;
11         min=num;
12         while (k<n)
13         {
14             System.out.println("Digita un altro numero");
15             num=sc.nextInt();
16             if (num<min)
17                 min=num;
18             if (num>max)
19                 max=num;
20             k++;}
21         System.out.println("Il massimo e il minimo sono:");
22         System.out.println(max+","+min+"\n");
23     }
24 }

Il ciclo while verifica che il contatore k non sia maggiore o uguale al valore n, in quanto il nostro ciclo parte da zero. E’ buona abitudine iniziare da zero, sopratutto perché in tutti i linguaggi di programmazione il valore zero rappresenta il valore id partenza in cui sono memorizzati i dati nella memoria centrale del calcolatore. Viene fatta l’assunzione che ogni struttura dati composta da più elementi viene memorizzata a partire dalla cella di indirizzo relativo zero.
I cicli condizionali sono maggiormente utilizzati nelle ripetizioni ove è l’utente a decidere quando interrompere il ciclo. Tale ciclo è detto a “rottuera di codice” in quanto l’utente digitando un valore prestabilito rompe l’esecuzione del ciclo. Come esempio immaginiamo di volere sommare una sequenza arbitraria di numeri e di interrompere il ciclo quando l’utente digita il valore zero. In questo caso l’utente condiziona la prosecuzione del ciclo sulla base dell’inserimento di un numero diverso o uguale a zero. L’esercizio è così strutturato:

1  import java.util.Scanner;
2  public class CicloFor {
3     public static void main(String[] args) {
4          int num, s=0; 
5          do
6          {
7              System.out.println("Digita un altro numero");
8              num=sc.nextInt();
9              s+=num;
10              }
11         while (num ! =0);
11         System.out.println("La somma è:"+s);
12     }
13 }

L’esercizio è molto semplice, il ciclo è ripetuto fin quando il numero inserito è diverso da zero positivo e negativo esso è sempre condierato ai fini della somma.

La quinta classe usare le strutture dati in Java

Per concludere questo capitolo iniziamo a introdurre le strutture dati in Java in particolare le strutture dati di tipo array o vettore molto importanti in molteplici ambiti della programmazione. La sesta classe basa il suo funzionamento principale sulle operazioni sui vettori. Partiamo col dire subito che un vettore è un aggregato di dati omogenei e identificato da un nume collettivo e i cui elementi sono individuati da un indice che ha un intervallo di variazione da 0 aal numero di elementi meno 1.
L’array è allocato dal punto vista del calcolatore e della memoria RAM in un’area contigua nelle quale ogni cella occupa un numero di byte pari alla dimensione del singolo componente dell’array o item.
Ad esempio in Java possiamo definire un array di interi di 10 elementi con la seguente dichiarazione:
int[] x= new int[10];
tale dichiarazione nell’ipotesi che un numero intero occupi 4 byte per ogni elemento tale array alloca 40 byte contigui.
Ogni elemento dell’array è costituito da un numero intero.
La dichiarazione dell’array vista sopra non prevede l’inizializzazione di valori dentro l’array ma solo la predisposizione di una variabile strutturata atta a ospitare 10 numeri inteir.
Una variante possibile è dichiarare un array e inserire i dati all’intero come riprotato in questo esempio:
int x[] ={1,2,3,4,5,7,8,9,10};
in questo caso è dichiarato un array di 10 interi con valori all’intero da 1 a 10 per semplicità; il primo valore ha posizione zero e l’ultimo 9.
In pratica:
x[0])1; x[1]=2; ……;x[4]=5; ……. x[9]=10;
In questo caso i valori sono definiti all’interno della classe e non vi è necessità di inseirere ulteriori dati al suo intero.
Come esempio molto semplice scriviamo un programma che inserisca i nomi di N alunni in un array di stringhe da tastiera e i voti riportati alla fine dell’anno e permetta di stampare per ogni alunno il giudizio secondo la sequente tabella;

VotoGiudizio
voto<4Gravemente insufficiente
4<= voto < 5Lievemnte insufficiente
5<=votoMediocre
6<=voto <7Sufficiente
voto > =7Più che sufficiente

Per risolvere questo problema definiamo una classe strutturata secondo il diagramma UML sotto riportato:

Come si può osservare sono definiti il numero degli studenti da inserire da tastiera e tre array due di input e uno di oputput l’array di nome “elenco” conterrò i nomi degli studenti, mentre l’array “voti” i voti degli studenti e l’array “esiti” i giudizi elabroati. Sono definiti un costruttore per l’inserimento solo del numero degli studenti e i metodi “Inserimento” e “StampaGiudizi” che risolvono il nostro problema, il main istanzia solo un oggetto della classe e poi richiama il metodo “inserimento” e il metodo “StampaGiudizi” per completare l’elaborazione.
La classe in Java progettata ha il codice sotto riportato.

1  import java.util.Scanner;
2  public class Giudizio
3  {
4    private int n;
5    private String[] elenco;
6    private float[] voti;
7    private String[] esiti;
8    public Giudizio()
9    {
10        Scanner sc=new Scanner (System.in);
11        System.out.println("Quanti studenti ?");
12        n=sc.nextInt();
13        elenco = new String[n];
14        voti = new float[n];
15        esiti= new String[n];
16    }
17    public void Inserimento()
18    {
19        int k;
20        Scanner sc = new Scanner (System.in);
21        for (k=0;k<n;k++)
22        {
23            System.out.println("Inserisci nome studente:");
24            elenco[k]= sc.nextLine();
25            System.out.print("Inserisci voto dello studente riportato a fine anno:");
26            voti[k]=sc.nextFloat();
27            sc.nextLine();
28        }
29        System.out.println("Inserimento completato con successo");
30    }
31    public void StampaGiudizi()
32    {
33        int k;
34        for (k=0;k<n;k++)
35        {
36         if (voti[k]<4)
37             esiti[k]="Gravemtne insufficiente";
38        else
39            if ((voti[k]>=4)&&(voti[k]<5))
40                esiti[k]="Lievemente insufficiente";
41            else
42                if ((voti[k]>=5)&&(voti[k]<6))
43                    esiti[k]="Mediocre";
44                else
45                    if (voti[k]>6)
46                        esiti[k]="Sufficiente";
47                    else
48                        if (voti[k]>=7)
49                            esiti[k]="Più che sufficiente";
50        }
51        System.out.println("Prospetto Giudizi:");
52        for (k=0;k<n;k++)
53            {
54                System.out.println("Alunno numero:"+(k+1)+"-->");
55                System.out.println("Nominativo:"+elenco[k]);
56                System.out.println("Giudizio:"+esiti[k]);
57            }
58    }
59    public static void main(String[] args)
60    {
61        Giudizio g=new Giudizio();
62        g.Inserimento();
63        g.StampaGiudizi();
64    }
65 }

L’esempio proposto utilizza tra array e l’elaborazione dei giudizi avviene con una serie di if nelle righe fra la 34 e la 50 nel ciclo for sono controllati i voti e viene riempito l’array “esiti” con i giudizi corrispondente. I giudizi elaborati sono inseriti nell’array “esiti” e nelle righe fra la 52 e la 57 sono stampati i giudizi. Nelle righe fra la 59 e la 64 il metodo main istanzia un oggetto della classe “Giudizioo” e invoca il metodo “Inserimento” e il metodo “StampaGiudizi” per l’elaborazione dei giudizi e la relativa stampa.
L’uso degli array in Java è molto importante, finora abbiamo considerato solo array costituiti da tipi di dati non strutturati come numeri interi, numeri reali. Già per le stringhe non si parla più di tipi di dati non strutturati anche se la flessibilità di utilizzo induce lo sviluppatore a utilizzarli come se lo fossero.
In realtà una stringa in Java è un oggetto di una classe String, a cui sarà dedicata attenzione nel prossimo capitolo.
Un array può essere anche composto da oggetti di una classe, in senso più generale ogni elemento dell’array sempre indetificato mediante un indice è un oggetto di una classe. Per comprendere meglio, immaginiamo di avere una classe ContoCorrente ove sono inseriti i dati di un singolo conto corrente quali: intestatario del conto, codice conto, saldo del conto, data saldo e elenco dei movimenti in un periodo. Ora possiamo definire a partire da questa classe una nuova classe di nome “AgenziaBancaria” all’interno della quale sono gestititi l’insieme dei conti correnti di quella specifica agenzia bancaria. La classe “AgenziaBancaria” conterrà un array di oggetit di tpo “Conto Corrente” che rappresenatono l’insieme di tutti ic onti correnti presenti nella specifica agenzia bancaria. Una relazione di questo tipo fra due classi è detta “Aggregazione”; in particoalre la classe “AgenziaBancaria” possiede N oggetti della classe “Conto Corrente” e peranto possiede un’associazione 1 a N si legge “uno a molti”; overo ad ogni oggetto della classe “AgenziaBancaria” corrispondono più oggetti della classe “Conto Corrente”. La rappresentazione UML è pertnato:

Sesta classe Conto Corrente

L’esempio che segue è molto significativo in quanto mostra come utilizzare un array per memorizzare gli oggetti di una classe. Il problema posto prima è sempre quello della gestione di una serie di conti correnti bancari di clienti affiliati alla stessa agenzia bancaria.
L’idea è quella di progettare una classe di nome “ContoCorrente” che permetta di definire un nuovo oggetto conto corrente ove sono rappresentati i dati del cliente, il saldo, la data dell’ultimo saldo e l’elenco dei movimenti eseguiti da quello specifico cliente. L’esercizio sarà iniziato in questo paragrafo e terminato nel Capitolo successivo ove attraverso l’uso di altre nozioni potremo completare l’esercizio. In particolare la classe “ContoCorrente” possiede un costruttore per la definizione dei dati iniziali del conto corrente, delle proprietà “get and set” per leggere e scrivere gli attributi singoarmente, un metodo toString “modificato” per stampare i dati del conto corrente e un metodo privato “Rosso” che restituisce un valore true se il conto corrente e a rosso.
Soffermiamoci un attimo sulle “get and set”; se in Java definiamo una classe come ad esempio:

class Esempio 
{
 private tipo 1 attributo1;
 private tipo 2 attributo2;
 ..
 private tipo N attributo N;
 public Esempio { /* codice costruttore */}
 public  tipo 1 getAttributo1()
 { return attributo 1;}
 public void setAttributo1(tipo 1 x)
 { attributo 1 =x ;}
 ....
 public  tipo N getAttributoN()
 { return attributo N;}
 public void setAttributo1(tipo N x)
 { attributo N =x ;}
 // altri metodo

In questa classe è definita una classe di esempio, quello che è significativo è il fatto che per ogni attributo da qualunque classe sia possibile prelevare il valore di ogni attributo di una variabile di istanza della claasse (l’oggetto istanziato per intenderci con dei valori pre impostati) e modificare ad uno ad uno con le “set” tali attributi.
Rappresenta in questo modo la possibilità di poter modificare singolarmente ogni attributo o di leggerlo senza andare a richiamare metodi che coinvolgnano necessariamente tutti gli attributi.
Ad esempio nel caso della classe “ContoCorrente” può essere utile modificare e leggere solo l’intestatario del conto o il saldo del conto e così via.
Tornando all’idea progettuale dell’agenzia bancaria è essenziale notare che la classe “AgenziaBancaria” contiene un array di oggetti “ContoCorrente” e quindi è creata un’associazione N a 1 fra l’insieme dei conti correnti e la singolaagenzia bacnaria. Lo stesso poteva avvenire per l’array movimenti che per semplicità abbiamo trattato nella classe “ContoCorrente” in parallelo all’array “tipomovimenti” che indica che tipologia di movimento è stato eseguito sul conto corrente (versamento, bonifico, assegno, ecc.). Inoltre sono introdotte le eccezioni almeno in alcuni casi per iniziare a gestire corretamente l’input dei nostri dati. Il diagramma UML delle classi è:

Il codice Java della classe “ContoCorrrente” è:

1 import java.util.Scanner;
2 import java.util.Date;
3 import java.text.DateFormat;
4 import java.text.SimpleDateFormat;
5 public class ContoCorrente
6 {
7     private String intestatario;
8     private String codiceconto;
9     private Date datasaldo;
10    private float saldo;
11    private float[] movimenti;
12    private String[] tipomovimenti;
13    private int numeromovimenti=0;
14    public ContoCorrente(String _intestatario, String _codiceconto,
15    Date _datasaldo, float _saldo)
16    {
17        this.intestatario=_intestatario;
18        this.codiceconto = _codiceconto;
19        this.datasaldo=_datasaldo;
20        this.saldo =_saldo; 
21    }
22    public String getCodiceConto()
23    {
24        return codiceconto;
25    }
26    public String getIntestatario()
27    {
28        return intestatario;
29    }
30    public Date getDataSaldo()
31    {
32        return datasaldo;
33    }
34    public float getSaldo()
35    {
36        return saldo;
37    }
38    public void setIntestatario(String x)
39    {
40        intestatario=x;
41    }
42    public void setCodiceConto(String x)
43    {
44        codiceconto=x;
45    }
46    public void setDataSaldo(Date x)
47    {
48        datasaldo=x;
49    }
50    public void setSaldo(float x)
51    {
52        saldo=x;
53    }
54    public boolean AggiungiMovimento(int i, float x, String y)
55    {
56        i=numeromovimenti;
57        movimenti[i]=x;
58        tipomovimenti[i]=y;
59        numeromovimenti++;
60        return true;
61    }
62    public String toString()
63    {
64        String tmp;
65        DateFormat df = new SimpleDateFormat("dd-mm-yyyy");
66        tmp="\nIntestatario Conto:"+intestatario;
67        tmp=tmp+"\nCodice Conto:"+codiceconto;
68        tmp=tmp+"\nData Saldo Ultima:"+df.format(datasaldo);
69        tmp=tmp+"\nSaldo in Euro:"+saldo;
70        return tmp;
71    }
72    private boolean Rosso()
73    {
74        if (saldo <=0)
75        return true;
76            else
77        return false;
78    }
79 }

Nelle righe 2,3,4 sono importate delle classi per definire oggetti di tipo Date che possono rappresentare date e orari in qualunque formato, la classe DataFormat che serve per definire il “pattern” della data ovvero in quale formato lo vogliamo trattare; nel nostro caso utilizziamo il formato “gg-mm-aaaa” e la classe SimpleDateFormat che permette di fare conversioni da tipo String a tipo Date e viceversa in quanto in input la data è letta in una stringa temporanea e poi viene eseguita la conversione nel formato Date richiesto (vedasi righe 62-71 nel metodo toString viene convertito un dato in formato Date (che in realtà è un oggetto) in una stringa prima definendo il pattern a riga 65, e poi a riga 68 per eseguire la conversione vera e propria nel pattern richiesto. Significative sono le righe 54 alla 61 ove è definito il metodo “AggiungiMovimento” che provvede ad aggiungere un nuovo movimento all’array dei movimenti e all’array dei “tipo movimenti” in parallelo, e restituisce valore true se tale operazione è andata a buon fine.
Rimane da vedere la classe “AgenziaBancaria” il cui codice è:

1   import java.util.Scanner;
2   import java.util.Date;
3   import java.text.DateFormat;
4   import java.text.SimpleDateFormat;
5   public class AgenziaBancaria
6   {
7      private int numeroclienti;
8      private ContoCorrente[] ContiCorrenti;
9      private int id;
10     public AgenziaBancaria()
11     {   
12         Scanner sc=new Scanner(System.in);
13         System.out.println("Quanti Clienti ?");
14         while (true)
15         {try 
16         {
17             numeroclienti=sc.nextInt();
18         }
19         catch (NumberFormatException e)
20         {
21            System.out.println("Stai inserendo un dato errato riprova !");
22             
23         }
24         finally 
25         {
26            ContiCorrenti=new ContoCorrente[numeroclienti];
27            id=0;
28            break;
29         }
30        }      
31     }
32     public boolean ApriConto()
33     {
34         boolean esito=false;
35         String _intestatario="", _codiceconto="";
36         float _saldo=0;
37         Date _datasaldo=null;
38         String _tmp;
39         Scanner sc=new Scanner(System.in);
40         while (!esito)
41         {
42             try
43             {
44                 System.out.println("Inserisci intestatario conto:");
45                 _intestatario=sc.nextLine();
46                 System.out.println("Inserisci codice conto:");
47                 _codiceconto=sc.nextLine();
48                 System.out.println("Inserisci il saldo del conto:");
49                 _saldo= sc.nextFloat();
50                 System.out.println("Inserisci la data di Saldo gg-mm-aaaa");
51                sc.nextLine();
52                 _tmp=sc.nextLine();
53                 _datasaldo=new SimpleDateFormat("dd-mm-yyyy").parse(_tmp);
54                
55                  }
56             catch (Exception e)
57             {
58                 System.out.println("Errore nell'inserimento dati ! Riprova");
59                 System.out.println(e.getMessage());
60             }
61             finally 
62            {
63                 ContoCorrente c= new ContoCorrente(_intestatario, _codiceconto, _datasaldo, _saldo);
64                 esito=true;
65                 ContiCorrenti[id]=c;
66                 id++;
67             }
68         }
69          return esito;
70     }
71         public ContoCorrente InfoConto(int i)
72         {
73             ContoCorrente c= new ContoCorrente("","",null,0);
74             c=ContiCorrenti[i];
75             return c;
76         }
77     public static void main(String[] args)
78     {
79         int i=0;
80         int p=0;
81         char risp='n';
82         Scanner sc =new Scanner (System.in);
83         AgenziaBancaria ag = new AgenziaBancaria();
84         do
85         {
86             if (ag.ApriConto())
87             {
88              System.out.println("Conto Aperto Correttamente altri conti s/n");
89              risp=sc.next().charAt(0);
90              i++;
91             }
92             else
93             {
94                 System.out.println("Errore di inserimento dati !");
95                 break;
96             }
97                
98         }
99         while (risp!='n');
100     System.out.println("Hai inserito numero clienti:"+i);
101     System.out.println("Quale correntista vuoi visualizzare da 1 a "+(i+1)+":");
102     p=sc.nextInt();
103     ContoCorrente c=new ContoCorrente("","",null,0);
104     c=ag.InfoConto(p-1);
105     System.out.println(c.toString());
106  } 
107  }

In questa classe ci sono tanti elementi di novità che andremo a descrivere anliticamente. Partiamo subito col dire che la lunghezza del codice della classe è dovuto alla presena del metodo main che non è inserito in una classe separata (dal prossimo capitolo sarà così avremo una classe “Test” che contiene solo il main), poi è stata più volte inserita la gestione delle eccezioni (fra un attimo ne parleremo).
A riga 8 è definito un array di oggetti “ContiCorrenti” che poi viene deinitivamente allocato nel costruttore a riga 26 nella clauola “finally” della “try & catch”. L’array di oggetti ha l’incoveniente che almeno una volta deve ssere istanziato e quinidi occorre precisare una dimensione. In taluni casi questo non sempre è possibile anche perché dati possono sempre essere aggiunti in momenti successivi (pensiamo ad un file che contiene prima due righe, poi quattro e man mano aumenta la sua dimensione). Per ovviare a questo è possibile utilizzare in Java i “Generic” che permttono l’uso effeiciente delle strutture dati dinamiche, se ne parlerà nel prossimo capitolo. Il metodo “InfoConto” restituisce un oggetto di tipo “ContoCorrente” che contiene tutte le informazioni di un conto corrente che è individuato in una posizione specifica nell’array di oggetti (vedasi righe 71-76). In questo caso il metodo ritorna il riferimento all’oggetto (un puntatore nella sostana volendo utilizzare uan terminologia alla “C/C++”) ove l’oggetto è allocato mediante l’assegnazione fatta a riga 74, dopo che a riga 73 è stato utilizzato un oggetto c di tipo “ContoCorrente” con valori vuoti.
Il metodo “ApriConto” gestisce tutta la fase dell’input e output da Console che prevede la gestione delle eccezioni per i dati di input (vedasi righe 32-70).

Primi elementi di gestione delle eccezioni

Per continuare a discutere del nostro progetto è opportuno introdurre il concetto di “eccezione”. L’eccezione è una condizione di errore che può verificarsi all’esecuzione del programma o per un errore di programma o perché l’utente l’ha generata incidentalemnte o perché è sollevata dal programma stesso per gestire determinate situazioni che possono verificarsi nel programma.
In qualunque caso quando l’eccezione è sollevata deve essere gestita perna il termine anomalo del progrmama. Le eccezioni possono essere ovviamente dovute a varie e molteplici situazioni in questa prima introduzione limiteremo il nostro discorso ad una discussione più generica e con pochi casi specifici in quanto per gestire le eccezioni in modo completo ed esaustivo occorre introdurre altri concetti in Java fra cui le sotto classi, la gerarchia delle classi ed altro ancora che sarà fatto più avanti nel libro. Possiamo vedre il funzionamento dell’eccezione come il tentativo “try” di esegtuire una porzione di codice, in caso di fallimento “intercettare” con “catch” l’eccezione e prendere decisioni in base a cosa è fallito nella “try” e poi in caso di esito positivo della “try” aggiungere delle azioni conclusive “finally”. Il costrutto generale Java per le eccezioni ha la struttura:
try
{ // codice di test // }
catch (Tipo Eccezione identificatore eccezione)
{ // codice di gestione //}
[finally
{ // codice finale in caso di mancata eccezione test riuscito in try //} ]
Le parentesi quadrate nella clausola finally stanno ad indicare che tale costrutto non è obbligatorio, in quanto se la try riesce l’esecuzione “bypassa” la catch e prosegue al codice successivo.
La nomenclatura “Tipo di Eccezione” deriva dal fatto che occorre conoscere che tipologia di eccezione deve essere intercettata, in caso contrario per iniziar è possibile utilizzare la parola “Exception” per indicare qualunque tipo di eccezione venga sollevata.
Ad esempio se si hanno due variabili a e b e viene tentata nella try la divisione di a e b con b che è zero, viene generata l’eccezione ArithmeticException che indica un problema in un’operaizone aritmetica, oppure se nell’inserimento di dati sono isneriti dati non compatibili con il tipo richiesto InputMismatchExcetion è l’eccezione che intercetta questo errore. E’ bene ricordare che se l’eccezione non viene gestita nel momento in cui si verifica il programma termina in maniera anomala. Questa non è una buona notizia sopratutto in Java dove la sicurezza del codice è uno dei pilastri fondanti della programmazione in questo linguaggio.
Premesso che sarà dedicato ampio spazio alle eccezione nel prossimo capitolo insieme ai “Generic” nel codice della classe “AgenziaBancaria” sono intercettate in modo generico delle eccezioni che possono scaturire da errori di input dei dati (vedasi riga 15-21 ove il programma si aspetta in input un nuermo e quindi un errore di inserimento viene gestito nelle righe 14-30 ove il ciclo while termina con il break nella clausola finllay ). Nelle righe 40-68 sempre nel ciclo while sono gestite insieme le eccezioni derivanti da errori di inserimento dei dati (per essere più accurati ogni input deve prevedere una try e catch autonoma) e dove nel caso di un errore la variabile esito rimane false e il ciclo non temrina.
Le eccezioni possono prevere sia più costrutti try e catch annidati e sia più catch per una sinolga try per gesitre in modo accurato ogni potenziale condizione di errore.
Rimane a conclusione del capitolo la discussione main che istanzia l’oggetto “ag” della classe “AgenziaBancaria” provvede con ciclo “a rottura di codice” all’apertura di un numero arbitrario di conti correnti e finito l’inserimento il main si limita a richiedere sul numero di clienti disponibili quale conto corrente di quale conto corrente si vuole visualizare i dati di apertura.

This content is for members only.