Skip to content

2. Nozioni di base sul linguaggio Java

2.1. Introduzione

Tratteremo Java innanzitutto come un linguaggio di programmazione classico. Affronteremo il tema degli oggetti in un secondo momento.

In un programma si trovano due elementi

  • i dati
  • le istruzioni che li manipolano

In genere si cerca di separare i dati dalle istruzioni:

Image

2.2. I dati in Java

Java utilizza i seguenti tipi di dati:

  • i numeri interi
  • i numeri reali
  • i caratteri e le stringhe
  • i valori booleani
  • gli oggetti

2.2.1. I tipi di dati predefiniti

Tipo
Codifica
Dominio
char
2 byte
carattere Unicode
int
4 byte
[-231, 231-1]
long
8 byte
[-263, 263 -1]
byte
1 byte
[-27 , 27 -1]
short
2 byte
[-215, 215-1]
float
4 byte
[3.4 10-38, 3.4 10+38] in valore assoluto
double
8 byte
[1.7 10-308 , 1.7 10+308] in valore assoluto
boolean
1 bit
vero, falso
String
riferimento all'oggetto
stringa di caratteri
Date
riferimento all'oggetto
data
Character
riferimento oggetto
carattere
Integer
riferimento oggetto
int
Long
riferimento all'oggetto
long
Byte
riferimento oggetto
byte
Float
riferimento all'oggetto
float
Double
riferimento all'oggetto
double
Boolean
riferimento all'oggetto
booleano

2.2.2. Notazione dei dati letterali

entier
145, -7, 0xFF (esadecimale)
reale doppio
134,789, -45E-18 (-45 × 10⁻¹⁸)
reale float
134.789F, -45E-18F (-45 × 10⁻¹⁸)
caractère
'A', 'b'
stringa di caratteri
"oggi"
booléen
vero, falso
date
new Date(13,10,1954) (giorno, mese, anno)

2.2.3. Dichiarazione dei dati

2.2.3.1. Ruolo delle dichiarazioni

Un programma gestisce dati caratterizzati da un nome e da un tipo. Questi dati vengono memorizzati in memoria. Al momento della compilazione del programma, il compilatore assegna a ciascun dato una posizione in memoria caratterizzata da un indirizzo e da una dimensione. Lo fa avvalendosi delle dichiarazioni effettuate dal programmatore.

Inoltre, queste consentono al compilatore di individuare eventuali errori di programmazione. Ad esempio, l’operazione

x=x*2;

sarà segnalata come errata se, ad esempio, x è una stringa di caratteri.

2.2.3.2. Dichiarazione delle costanti

La sintassi per dichiarare una costante è la seguente:

final tipo nome=valore; //definisce la costante nome=valore

es.: final float PI=3.141592F;

Nota

Perché dichiarare le costanti?

  • La lettura del programma risulterà più agevole se alla costante viene assegnato un nome significativo:

es.: final float taux_tva = 0.186F;

  • La modifica del programma risulterà più semplice qualora la «costante» dovesse cambiare. Pertanto, nel caso precedente, se l’aliquota IVA dovesse passare al 33%, l’unica modifica da apportare sarà quella di modificare l’istruzione che ne definisce il valore:

final float taux_tva=0.33F;

Se nel programma fosse stato utilizzato esplicitamente il valore 0,186, sarebbe stato necessario modificare numerose istruzioni.

2.2.3.3. Dichiarazione delle variabili

Una variabile è identificata da un nome e si riferisce a un tipo di dati. Il nome di una variabile Java è composto da n caratteri: il primo deve essere una lettera, mentre gli altri possono essere lettere o cifre. Java distingue tra maiuscole e minuscole. Pertanto, le variabili FIN e fin sono diverse.

Le variabili possono essere inizializzate al momento della loro dichiarazione. La sintassi per dichiarare una o più variabili è:

identificateur_de_type variable1,variable2,...,variablen;

dove identificateur_de_type è un tipo predefinito oppure un tipo oggetto definito dal programmatore.

2.2.4. Le conversioni tra numeri e stringhe di caratteri

numero -> stringa
"" + numero
stringa -> int
Integer.parseInt(stringa)
stringa -> long
Long.parseLong(stringa)
stringa -> double
Double.valueOf(stringa).doubleValue()
stringa -> float
Float.valueOf(stringa).floatValue()

Ecco un programma che illustra le principali tecniche di conversione tra numeri e stringhe di caratteri. La conversione di una stringa in un numero può fallire se la stringa non rappresenta un numero valido. In tal caso viene generato un errore fatale, denominato “eccezione” in Java. Questo errore può essere gestito tramite la clausola try/catch seguente:

try{
    appel de la fonction susceptible de générer l'exception
} catch (Exception e){
    traiter l'exception e
}
instruction suivante

Se la funzione non genera un'eccezione, si passa all'istruzione successiva; in caso contrario, si passa al corpo della clausola catch e poi all'istruzione successiva. Torneremo in seguito sulla gestione delle eccezioni.


import java.io.*;

public class conv1{

  public static void main(String arg[]){
    String S;
    final int i=10;
    final long l=100000;
    final float f=(float)45.78;
    double d=-14.98;

    // numero --> stringa
    S=""+i;
    affiche(S);
    S=""+l;
    affiche(S);
    S=""+f;
    affiche(S);
    S=""+d;
    affiche(S);

    //booleano --> stringa
    final boolean b=false;
    S=""+new Boolean(b);
    affiche(S);

    // stringa --> int
    int i1;
    i1=Integer.parseInt("10");
    affiche(""+i1);
    try{
      i1=Integer.parseInt("10.67");
      affiche(""+i1);
    } catch (Exception e){
      affiche("Erreur "+e);
    }

    // stringa --> long
    long l1;
    l1=Long.parseLong("100");
    affiche(""+l1);
    try{
      l1=Long.parseLong("10.675");
      affiche(""+l1);
    } catch (Exception e){
      affiche("Erreur "+e);
    }
    
    // stringa --> double
    double d1;
    d1=Double.valueOf("100.87").doubleValue();
    affiche(""+d1);
    try{
      d1=Double.valueOf("abcd").doubleValue();
      affiche(""+d1);
    } catch (Exception e){
      affiche("Erreur "+e);
    }

    // stringa --> float
    float f1;
    f1=Float.valueOf("100.87").floatValue();
    affiche(""+f1);
    try{
      d1=Float.valueOf("abcd").floatValue();
      affiche(""+f1);
    } catch (Exception e){
      affiche("Erreur "+e);
    }

}// fine main

  public static void affiche(String S){
    System.out.println("S="+S);
  }
}// fine classe

I risultati ottenuti sono i seguenti:

S=10
S=100000
S=45.78
S=-14.98
S=false
S=10
S=Erreur java.lang.NumberFormatException: 10.67
S=100
S=Erreur java.lang.NumberFormatException: 10.675
S=100.87
S=Erreur java.lang.NumberFormatException: abcd
S=100.87
S=Erreur java.lang.NumberFormatException: abcd

2.2.5. Gli array di dati

Un array Java è un oggetto che consente di raggruppare dati dello stesso tipo sotto un unico identificatore. La sua dichiarazione è la seguente:

Tipo Array[] = new Tipo[n] oppure Tipo[] Array = new Tipo[n]

Entrambe le sintassi sono valide. n è il numero di elementi che l'array può contenere. La sintassi Array[i] indica l'elemento n° i, dove i appartiene all'intervallo [0,n-1]. Qualsiasi riferimento al dato Tableau[i] in cui i non appartiene all'intervallo [0,n-1] provocherà un'eccezione.

Un array bidimensionale può essere dichiarato come segue:

Type Tableau[][] = new Type[n][p] oppure Type[][] Tableau = new Type[n][p]

La sintassi Tableau[i] indica il dato n. i di Tableau, dove i appartiene all'intervallo [0,n-1]. Tableau[i] è a sua volta una tabella: Tableau[i][j] indica il dato n. j della tabella [i], dove j appartiene all'intervallo [0,p-1]. Qualsiasi riferimento a un dato di Tableau con indici errati genera un errore irreversibile.

Ecco un esempio:


public class test1{

  public static void main(String arg[]){
    float[][] taux=new float[2][2];
    taux[1][0]=0.24F;
    taux[1][1]=0.33F;
    System.out.println(taux[1].length);
    System.out.println(taux[1][1]);
  }
}

e i risultati dell'esecuzione:

2
0.33

Un array è un oggetto che possiede l'attributo length: si tratta della dimensione dell'array.

2.3. Le istruzioni elementari di Java

Si distingue tra

  • le istruzioni elementari eseguite dal computer
  • le istruzioni di controllo dello svolgimento del programma.

Le istruzioni elementari risultano evidenti se si considera la struttura di un microcomputer e delle sue periferiche.

Image

  1. lettura delle informazioni provenienti dalla tastiera

  2. elaborazione delle informazioni

  3. visualizzazione di informazioni sullo schermo

  4. lettura di informazioni da un file su disco

  5. scrittura di informazioni in un file su disco

2.3.1. Scrittura sullo schermo

La sintassi dell'istruzione di scrittura sullo schermo è la seguente:

System.out.println(espressione) oppure System.err.println(espressione)

dove expression è un tipo di dato qualsiasi che possa essere convertito in una stringa di caratteri da visualizzare sullo schermo. Nell’esempio precedente abbiamo visto due istruzioni di scrittura:

System.out.println(taux[1].length);
System.out.println(taux[1][1]);

System.out scrive in un file di testo che, per impostazione predefinita, è lo schermo. Lo stesso vale per System.err. Questi file recano un numero (ad esempio descripteur) rispettivamente pari a 1 e 2. Anche il flusso di input dalla tastiera (System.in) è considerato un file di testo, con descrittore 0. Sia DOS che Unix supportano il piping dei comandi:

    commande1 | commande2

Tutto ciò che commande1 scrive con System.out viene reindirizzato (tramite pipe) verso l'ingresso System.in di commande2. In altre parole, commande2 legge tramite System.in i dati generati da commande2 tramite System.out, che quindi non vengono più visualizzati sullo schermo. Questo sistema è molto diffuso in ambiente Unix. In questa concatenazione, il flusso System.err non viene invece reindirizzato: scrive sullo schermo. Ecco perché viene utilizzato per scrivere i messaggi di errore (da cui il suo nome err): si ha la certezza che, durante un reindirizzamento dei comandi, i messaggi di errore continueranno a essere visualizzati sullo schermo. Si prenderà quindi l’abitudine di scrivere i messaggi di errore sullo schermo con il flusso System.err piuttosto che con il flusso System.out.

2.3.2. Lettura dei dati digitati dalla tastiera

Il flusso di dati proveniente dalla tastiera è indicato dall’oggetto System.in di tipo InputStream. Questo tipo di oggetti consente di leggere i dati carattere per carattere. Spetta poi al programmatore individuare in questo flusso di caratteri le informazioni che gli interessano. Il tipo InputStream non consente di leggere un’intera riga di testo in un’unica operazione. Il tipo BufferedReader lo consente tramite il metodo readLine.

Per poter leggere le righe di testo digitate dalla tastiera, si crea, a partire dal flusso di input System.in di tipo InputStream, un altro flusso di input, questa volta di tipo BufferedReader:

BufferedReader IN=new BufferedReader(new InputStreamReader(System.in));

Non spiegheremo qui i dettagli di questa istruzione, che coinvolge il concetto di costruzione di oggetti. La useremo così com’è.

La creazione di un flusso può fallire: in tal caso viene generato un errore fatale, chiamato eccezione in Java. Ogni volta che un metodo è suscettibile di generare un’eccezione, il compilatore Java richiede che essa venga gestita dal programmatore. Pertanto, per creare il flusso di input precedente, sarà necessario in realtà scrivere:


BufferedReader IN=null;
try{
IN=new BufferedReader(new InputStreamReader(System.in));
} catch (Exception e){
        System.err.println("Erreur " +e);
        System.exit(1);
}

Anche in questo caso, non ci soffermeremo qui a spiegare la gestione delle eccezioni. Una volta creato il flusso IN di cui sopra, è possibile leggere una riga di testo tramite l'istruzione:

    String ligne;
    ligne=IN.readLine();

La riga digitata sulla tastiera viene memorizzata nella variabile ligne e può quindi essere utilizzata dal programma.

2.3.3. Esempio di operazioni di input-output

Ecco un programma che illustra le operazioni di input-output da tastiera/schermo:


import java.io.*;        // necessario per l'utilizzo dei flussi di I/O

public class io1{
  
  
  public static void main (String[] arg){
    
    // scrittura sul flusso System.out
    Object obj=new Object();
    System.out.println(""+obj);
    System.out.println(obj.getClass().getName());
    
    // scrittura sul flusso System.err
    int i=10;
    System.err.println("i="+i);
    
    // lettura di una riga immessa dalla tastiera
    String ligne;
    BufferedReader IN=null;
    try{
      IN=new BufferedReader(new InputStreamReader(System.in));
    } catch (Exception e){
      affiche(e);
      System.exit(1);
    }
    System.out.print("Tapez une ligne : ");
    try{
      ligne=IN.readLine();
      System.out.println("ligne="+ligne);
    } catch (Exception e){
      affiche(e);
      System.exit(2);
    }
  }//fine mano

  public static void affiche(Exception e){
    System.err.println("Erreur : "+e);
  }

}//fine classe

e i risultati dell'esecuzione:

C:\Serge\java\bases\iostream>java io1
java.lang.Object@1ee78b
java.lang.Object
i=10
Tapez une ligne : je suis là
ligne=je suis là

Le istruzioni

Object obj=new Object();
System.out.println(""+obj);
System.out.println(obj.getClass().getName());

hanno lo scopo di dimostrare che qualsiasi oggetto può essere visualizzato. In questa sede non cercheremo di spiegare il significato di ciò che viene visualizzato. Nel blocco è presente anche la visualizzazione del valore di un oggetto:

try{
      IN=new BufferedReader(new InputStreamReader(System.in));
    } catch (Exception e){
      affiche(e);
      System.exit(1);
    }

La variabile e è un oggetto di tipo Exception che viene visualizzato qui con la chiamata affiche(e). Avevamo già incontrato, senza però menzionarlo, questa visualizzazione del valore di un'eccezione nel programma di conversione visto in precedenza.

2.3.4. Assegnazione del valore di un’espressione a una variabile

Ci interessiamo qui all’operazione variable=expression;

L'espressione può essere di tipo: aritmetico, relazionale, booleano, stringa

2.3.4.1. Interpretazione dell'operazione di assegnazione

L'operazione variable=expression; è essa stessa un'espressione la cui valutazione avviene nel modo seguente:

  • Viene valutata la parte destra dell'assegnazione: il risultato è un valore V.
  • il valore V viene assegnato alla variabile
  • il valore V è anche il valore dell'assegnazione, considerata questa volta come espressione.

È così che l’operazione V1=V2=espressione è valida. A causa della priorità, verrà valutato l'operatore = più a destra. Si ottiene quindi V1=(V2=espressione). L'espressione V2=espressione viene valutata e ha come valore V. La valutazione di questa espressione ha provocato l'assegnazione di V a V2. L'operatore = successivo viene quindi valutato nella forma V1=V. Il valore di questa espressione è ancora V. La sua valutazione provoca l’assegnazione di V a V1. Pertanto, l’operazione V1=V2=espressione è un'espressione la cui valutazione

1: provoca l'assegnazione del valore di expression alle variabili V1 e V2

2: restituisce come risultato il valore di expression.

È possibile generalizzare a un’espressione del tipo: V1=V2=....=Vn=espressione

2.3.4.2. Espressione aritmetica

Gli operatori delle espressioni aritmetiche sono i seguenti:

+: addizione

  • : sottrazione

*: moltiplicazione

/ : divisione: il risultato è il quoziente esatto se almeno uno degli operandi è un numero reale. Se entrambi gli operandi sono interi, il risultato è il quoziente intero. Quindi 5/2 -> 2 e 5,0/2 -> 2,5.

% : divisione: il risultato è il resto indipendentemente dalla natura degli operandi, mentre il quoziente è intero. Si tratta quindi dell'operazione modulo.

Esistono diverse funzioni matematiche:

double sqrt(double x)
radice quadrata
double cos(double x)
Coseno
double sin(double x)
Sen
double tan(double x)
Tangente
double pow(double x, double y)
x elevato a y (x>0)
double exp(double x)
Esponenziale
double log(double x)
Logaritmo naturale
double abs(double x)
valore assoluto

ecc...

Tutte queste funzioni sono definite in una classe Java chiamata Math. Quando le si utilizza, è necessario anteporre il nome della classe in cui sono definite. Quindi si scriverà:

double x, y=4;
x=Math.sqrt(y);

La definizione della classe Math è la seguente:


public  final  class  java.lang.Math
    extends  java.lang.Object  (I-§1.12)
{
        // Campi
    public final static double E;    §1.10.1
    public final static double PI;    §1.10.2

        // Metodi
    public static double abs(double  a);    §1.10.3
    public static float abs(float  a);    §1.10.4
    public static int abs(int  a);    §1.10.5
    public static long abs(long  a);    §1.10.6
    public static double acos(double  a);    §1.10.7
    public static double asin(double  a);    §1.10.8
    public static double atan(double  a);    §1.10.9
    public static double atan2(double  a, double  b);    §1.10.10
    public static double ceil(double  a);    §1.10.11
    public static double cos(double  a);    §1.10.12
    public static double exp(double  a);    §1.10.13
    public static double floor(double  a);    §1.10.14
    public static double                        §1.10.15
        IEEEremainder(double  f1, double  f2);
    public static double log(double  a);    §1.10.16
    public static double max(double  a, double  b);    §1.10.17
    public static float max(float  a, float  b);    §1.10.18
    public static int max(int  a, int  b);    §1.10.19
    public static long max(long  a, long  b);    §1.10.20
    public static double min(double  a, double  b);     §1.10.21
    public static float min(float  a, float  b);    §1.10.22
    public static int min(int  a, int  b);    §1.10.23
    public static long min(long  a, long  b);    §1.10.24
    public static double pow(double  a, double  b);    §1.10.25
    public static double random();    §1.10.26
    public static double rint(double  a);    §1.10.27
    public static long round(double  a);    §1.10.28
    public static int round(float  a);    §1.10.29
    public static double sin(double  a);    §1.10.30
    public static double sqrt(double  a);    §1.10.31
    public static double tan(double  a);    §1.10.32
}

2.3.4.3. Priorità nella valutazione delle espressioni aritmetiche

La priorità degli operatori nella valutazione di un'espressione aritmetica è la seguente (dal più prioritario al meno prioritario):

[fonctions], [ ( )], [ *, /, %], [+, -]

Gli operatori appartenenti allo stesso blocco [ ] hanno la stessa priorità.

2.3.4.4. Espressioni relazionali

Gli operatori sono i seguenti: <, <=, ==, !=, >, >=

ordine di priorità

>, >=, <, <=

==, !=

Il risultato di un'espressione relazionale è il valore booleano false se l'espressione è falsa, true altrimenti.

Esempio:

      boolean fin;
      int x;
      fin=x>4;

Confronto tra due caratteri

Siano dati due caratteri C1 e C2. È possibile confrontarli utilizzando gli operatori

<, <=, ==, !=, >, >=

Vengono quindi confrontati i loro codici ASCII, che sono numeri. Si ricorda che, secondo l'ordine ASCII, si hanno le seguenti relazioni:

spazio < .. < '0' < '1' < .. < '9' < .. < 'A' < 'B' < .. < 'Z' < .. < 'a' < 'b' < .. < 'z'

Confronto tra due stringhe di caratteri

Vengono confrontate carattere per carattere. La prima disuguaglianza riscontrata tra due caratteri determina una disuguaglianza dello stesso segno tra le stringhe.

Esempi:

Si considerino le stringhe "Gatto" e "Cane"

Quest'ultima disuguaglianza permette di affermare che "Gatto" < "Cane".

Image

Supponiamo di confrontare le stringhe "Gatto" e "Gattino". C'è uguaglianza per tutto il tempo fino all'esaurimento della stringa "Gatto". In questo caso, la stringa esaurita viene dichiarata la più "piccola". Si ha quindi la relazione

"Gatto" < "Gattino".

Funzioni di confronto tra due stringhe

Qui non è possibile utilizzare gli operatori relazionali <, <=, ==, !=, >, >=. È necessario utilizzare i metodi della classe String:

String chaine1, chaine2;
chaine1=…;
chaine2=…;
int i=chaine1.compareTo(chaine2);
boolean egal=chaine1.equals(chaine2)

Nell'esempio sopra riportato, la variabile i avrà il valore:

0: se le due stringhe sono uguali

1: se la stringa n. 1 è maggiore della stringa n. 2

-1: se la stringa n. 1 è minore della stringa n. 2

La variabile egal assumerà il valore true se le due stringhe sono uguali.

2.3.4.5. Espressioni booleane

Gli operatori sono & (and) ||(or) e ! (not). Il risultato di un'espressione booleana è un valore booleano.

Ordine di priorità ! , &&, ||

esempio:

int fin;
int x;
fin= x>2 && x<4;

Gli operatori relazionali hanno la precedenza sugli operatori && e ||.

2.3.4.6. Operazioni bit a bit

Gli operatori

Siano i e j due numeri interi.

i<<n
sposta i di n bit a sinistra. I bit di riempimento sono zeri.
i>>n
sposta i di n bit a destra. Se i è un numero intero con segno (signed char, int, long), il bit di segno viene mantenuto.
i & j
effettua l'OR logico bit per bit tra i e j.
i | j
effettua la OU logica di i e j bit per bit.
~i
completa i a 1
i^j
esegue l'operazione OU EXCLUSIF su i e j

Sia

    int i=0x123F, k=0xF123;
    unsigned j=0xF123;
operazione
valore
i<<4
0x23F0
i>>4
0x0123 il bit di segno viene mantenuto.
k>>4
0xFF12 il bit di segno viene mantenuto.
i&j
0x1023
i|j
0xF33F
~i
0xEDC0

2.3.4.7. Combinazione di operatori

a=a+b può essere scritto come a+=b

a=a-b può essere scritto come a-=b

Lo stesso vale per gli operatori /, %, *, <<, >>, &, |, ^

Pertanto, a=a+2; può essere scritto come a+=2;

2.3.4.8. Operatori di incremento e decremento

La notazione variable++ significa variable=variable+1 oppure variable+=1

La notazione variable-- indica variable=variable-1 oppure variable-=1.

2.3.4.9. L'operatore?

L'espressione expr_cond ? expr1:expr2 viene valutata nel modo seguente:

1: viene valutata l'espressione expr_cond. Si tratta di un'espressione condizionale con valore vero o falso

2: se è vera, il valore dell’espressione è quello di expr1. expr2 non viene valutata.

3: se è falsa, avviene il contrario: il valore dell’espressione è quello di expr2. expr1 non viene valutata.

Esempio

i=(j>4 ? j+1:j-1);

assegnerà alla variabile i:

j+1 se j>4, altrimenti j-1

È come scrivere if(j>4) i=j+1; else i=j-1; ma è più conciso.

2.3.4.10. Priorità generale degli operatori

() [] funzione
gd
! ~ ++ --
dg
new (tipo) operatori di conversione
dg
* / %
gd
+ -
gd
<< >>
gd
< <= > >= instanceof
gd
== !=
gd
&
gd
^
gd
|
gd
&&
gd
||
gd
? :
dg
= += -= ecc. .
dg

gd: indica che, a parità di priorità, viene osservata la priorità da sinistra a destra. Ciò significa che quando in un'espressione sono presenti operatori con la stessa priorità, viene valutato per primo l'operatore più a sinistra nell'espressione. dg indica una priorità da destra a sinistra.

2.3.4.11. I cambiamenti di tipo

In un'espressione è possibile modificare temporaneamente la codifica di un valore. Questo processo è noto come "cambio di tipo" o, in inglese, "type casting". La sintassi per il cambio di tipo di un valore in un'espressione è la seguente: (tipo) valore. Il valore assume quindi il tipo indicato. Ciò comporta una modifica della codifica del valore.

Esempio:

int i, j;
float isurj;
isurj= (float)i/j;   // priorità di () su /

In questo caso è necessario modificare il tipo di i o j in reale, altrimenti la divisione restituirà un quoziente intero e non reale.

i è un valore codificato in modo esatto su 2 byte

(float) i è lo stesso valore codificato in modo approssimativo come numero reale su 4 byte

Si verifica quindi una transcodifica del valore di i. Questa transcodifica avviene solo per la durata di un calcolo, mentre la variabile i mantiene sempre il proprio tipo int.

2.4. Le istruzioni di controllo dello svolgimento del programma

2.4.1. Arresto

Il metodo exit definito nella classe System consente di interrompere l’esecuzione di un programma.

Sintassi : void exit(int status)

Azione: interrompe il processo in corso e restituisce il valore status al processo padre

exit provoca la fine del processo in corso e restituisce il controllo al processo chiamante. Il valore di status può essere utilizzato da quest'ultimo. In DOS, questa variabile status viene restituita a DOS nella variabile di sistema ERRORLEVEL, il cui valore può essere verificato in un file batch. In Unix, è la variabile $? che recupera il valore di status se l'interprete di comandi è la Bourne Shell (/bin/sh).

Esempio:

    System.exit(0);

per terminare il programma con un valore di stato pari a 0.

2.4.2. Struttura di selezione semplice


 syntaxe :  if (condition) {actions_condition_vraie;} else {actions_condition_fausse;}

Note:

  • la condizione è racchiusa tra parentesi.
  • Ogni azione è terminata da un punto e virgola.
  • le parentesi graffe non sono seguite da un punto e virgola.
  • le parentesi graffe sono necessarie solo se c'è più di un'azione.
  • La clausola else può essere omessa.
  • Non c'è il «then».

L'equivalente algoritmico di questa struttura è la struttura if ... then ... else:

si condition
  alors actions_condition_vraie
  sinon actions_conditions_fausse
finsi

esempio


    if (x>0)  { nx=nx+1;sx=sx+x;} else dx=dx-x;

È possibile annidare le strutture di selezione:

if(condition1)
if (condition2)
        {......}
      else         //condizione2
         {......}
else         //condizione1
     {.......}

A volte si presenta il seguente problema:


public static void main(void){
      int n=5;

   if(n>1)
     if(n>6)
             System.out.println(">6");
     else System.out.println("<=6");
}

Nell'esempio precedente, a quale if si riferisce il else? La regola prevede che un codice else si riferisca sempre al codice if più vicino: if(n>6) nell'esempio. Consideriamo un altro esempio:


public static void main(void)
{  int n=0;

   if(n>1)
     if(n>6)   System.out.println(">6");
     else;            // else dell'if(n>6): niente da fare 
   else System.out.println("<=1");    // else dell'if(n>1) 
}

Qui volevamo inserire un else al posto di if(n>1) e non un else al posto di if(n>6). A causa dell'osservazione precedente, siamo costretti a inserire un "else" per il codice if(n>6), nel quale non è presente alcuna istruzione.

2.4.3. Struttura dei casi

La sintassi è la seguente:

switch(expression) {
    case v1:     
            actions1;
            break;
    case v2:     
            actions2;
            break;
         . .. .. .. .. ..
    default:     actions_sinon;
}

note

  • Il valore dell'espressione di controllo può essere solo un numero intero o un carattere.
  • L'espressione di controllo è racchiusa tra parentesi.
  • La clausola default può essere assente.
  • I valori vi sono valori possibili dell'espressione. Se l'espressione ha come valore vi, vengono eseguite le azioni successive alla clausola case vi.
  • L'istruzione break fa uscire dalla struttura case. Se è assente alla fine del blocco di istruzioni con valore vi, l'esecuzione prosegue con le istruzioni del valore vi+1.

Esempio

In algoritmica

selon la valeur de choix
cas 0
          arrêt
      cas 1
    exécuter module M1
  cas 2
    exécuter module M2
  sinon
    erreur<--vrai
findescas

In Java


    int choix, erreur;
    switch(choix){   
        case 0: System.exit(0);
      case 1: M1();break;
      case 2: M2();break;
      default: erreur=1;
     }

2.4.4. Struttura di ripetizione

2.4.4.1. Numero di ripetizioni noto

Sintassi


    for (i=id;i<=if;i=i+ip){ 
       actions; 
      } 

Note

  • I 3 argomenti di for sono racchiusi tra parentesi.
  • I 3 argomenti di for sono separati da punti e virgola.
  • Ogni azione di for termina con un punto e virgola.
  • La parentesi graffa è necessaria solo se vi è più di un'azione.
  • La parentesi graffa non è seguita da un punto e virgola.

L'equivalente algoritmico è la struttura pour:

pour i variant de id à if avec un pas de ip
        actions
finpour

che può essere tradotta in una struttura tantque:

    i  id
    tantque i<=if
        actions
        i i+ip
    fintantque

2.4.4.2. Numero di ripetizioni sconosciuto

In Java esistono numerose strutture per questo caso.

Struttura «while»


    while(condition){
          actions;
        } 

Il ciclo continua finché la condizione è vera. Il ciclo potrebbe non essere mai eseguito.

Note:

  • la condizione è racchiusa tra parentesi.
  • Ogni azione è seguita da un punto e virgola.
  • la parentesi graffa è necessaria solo se c'è più di un'azione.
  • la parentesi graffa non è seguita da un punto e virgola.

La struttura algoritmica corrispondente è la struttura «finché»:

tantque condition
        actions
fintantque

Struttura «ripeti fino a» (do while)

La sintassi è la seguente:


    do{
       instructions;
    }while(condition); 

Il ciclo continua finché la condizione non diventa falsa o finché la condizione rimane vera. In questo caso il ciclo viene eseguito almeno una volta.

Note

  • la condizione è racchiusa tra parentesi.
  • Ogni azione è seguita da un punto e virgola.
  • la parentesi graffa è necessaria solo se c'è più di un'azione.
  • La parentesi graffa non è seguita da un punto e virgola.

La struttura algoritmica corrispondente è la struttura «ripeti … fino a»:

répéter
    actions
jusqu'à condition

Struttura «for» (for)

La sintassi è la seguente:


for(instructions_départ;condition;instructions_fin_boucle){
    instructions; 
}

Il ciclo continua finché la condizione è vera (valutata prima di ogni iterazione). Le istruzioni Instructions_départ vengono eseguite prima di entrare nel ciclo per la prima volta. Le istruzioni Instructions_fin_boucle vengono eseguite dopo ogni iterazione.

note

  • I 3 argomenti di for sono racchiusi tra parentesi.
  • I 3 argomenti di for sono separati da punti e virgola.
  • Ogni azione del ciclo «for» termina con un punto e virgola.
  • La parentesi graffa è necessaria solo se vi è più di un'azione.
  • La parentesi graffa non è seguita da un punto e virgola.
  • Le diverse istruzioni nei file instructions_depart e instructions_fin_boucle sono separate da virgole.

La struttura algoritmica corrispondente è la seguente:

instructions_départ
tantque condition
        actions
        instructions_fin_boucle
fintantque

Esempi

I seguenti programmi calcolano tutti la somma dei primi n numeri interi.


1  for(i=1, somme=0;i<=n;i=i+1)
        somme=somme+a[i];

2     for (i=1, somme=0;i<=n;somme=somme+a[i], i=i+1);

3    i=1;somme=0;
    while(i<=n)
       { somme+=i; i++; }

4    i=1; somme=0;
    do somme+=i++;
         while (i<=n);

Istruzioni per la gestione dei cicli

break
esce dal ciclo for, while, do ... while.
continue
passa all'iterazione successiva nei cicli for, while, do ... while

2.5. La struttura di un programma Java

Un programma Java che non utilizza classi definite dall'utente né funzioni diverse dalla funzione principale main potrà avere la seguente struttura:


public class test1{
    public static void main(String arg[]){
        … code du programme
    }// main
}// class

La funzione main, detta anche metodo, viene eseguita per prima durante l'esecuzione di un programma Java. Deve obbligatoriamente avere la seguente firma:


    public static void main(String arg[]){

oppure


    public static void main(String[] arg){

Il nome dell'argomento arg può essere qualsiasi. Si tratta di un array di stringhe che rappresenta gli argomenti della riga di comando. Ne riparleremo più avanti.

Se si utilizzano funzioni che potrebbero generare eccezioni che non si desidera gestire in modo dettagliato, è possibile racchiudere il codice del programma in una clausola try/catch:


public class test1{
    public static void main(String arg[]){
        try{
        … code du programme
        } catch (Exception e){
            // gestione degli errori
        }// try
    }// main
}// classe

All'inizio del codice sorgente e prima della definizione della classe, è comune trovare istruzioni di importazione delle classi. Ad esempio:


import java.io.*;
public class test1{
    public static void main(String arg[]){
        … code du programme
    }// main
}// classe

Facciamo un esempio. Consideriamo la seguente istruzione di scrittura:

System.out.println("java");

che scrive java sullo schermo. In questa semplice istruzione ci sono molte cose:

  • System è una classe il cui nome completo è java.lang.System
  • out è una proprietà di questa classe di tipo java.io.PrintStream, un’altra classe
  • println è un metodo della classe java.io.PrintStream.

Non complicheremo inutilmente questa spiegazione, che arriva troppo presto poiché richiede la comprensione del concetto di classe, non ancora trattato. Si può considerare una classe come una risorsa. In questo caso, il compilatore dovrà avere accesso alle due classi java.lang.System e java.io.PrintStream. Le centinaia di classi di Java sono suddivise in archivi chiamati anche pacchetti (package). Le istruzioni import inserite all’inizio del programma servono a indicare al compilatore di quali classi esterne ha bisogno il programma (quelle utilizzate ma non definite nel file sorgente che verrà compilato). Pertanto, nel nostro esempio, il nostro programma necessita delle classi java.lang.System e java.io.PrintStream. Lo si indica con l’istruzione import. All’inizio del programma si potrebbe scrivere:

import java.lang.System;
import java.io.PrintStream;

Poiché un programma Java utilizza comunemente diverse decine di classi esterne, sarebbe complicato scrivere tutte le funzioni import necessarie. Le classi sono state raggruppate in pacchetti ed è quindi possibile importare l’intero pacchetto. Pertanto, per importare i pacchetti java.lang e java.io, si scriverà:

import java.lang.*;
import java.io.*;

Il pacchetto java.lang contiene tutte le classi di base di Java e viene importato automaticamente dal compilatore. Pertanto, alla fine si scriverà semplicemente:

import java.io.*;

2.6. Gestione delle eccezioni

Numerose funzioni Java possono generare eccezioni, ovvero errori. Abbiamo già incontrato una funzione di questo tipo, la funzione readLine:


String ligne=null;
try{
      ligne=IN.readLine();
      System.out.println("ligne="+ligne);
    } catch (Exception e){
      affiche(e);
      System.exit(2);
}// try

Quando una funzione può generare un'eccezione, il compilatore Java impone al programmatore di gestirla al fine di ottenere programmi più resistenti agli errori: occorre sempre evitare il "crash" incontrollato di un'applicazione. In questo caso, la funzione readLine genera un'eccezione se non c'è nulla da leggere, ad esempio perché il flusso di input è stato chiuso. La gestione di un'eccezione avviene secondo lo schema seguente:

try{
    appel de la fonction susceptible de générer l'exception
} catch (Exception e){
    traiter l'exception e
}
instruction suivante

Se la funzione non genera un'eccezione, si passa all'istruzione successiva; in caso contrario, si passa al corpo della clausola catch e poi all'istruzione successiva. Si notino i seguenti punti:

  • e è un oggetto derivato dal tipo Exception. È possibile essere più precisi utilizzando tipi quali IOException, SecurityException, ArithmeticException, ecc.: esistono una ventina di tipi di eccezioni. Scrivendo catch (Exception e), si indica che si desidera gestire tutti i tipi di eccezioni. Se il codice della clausola try è suscettibile di generare diversi tipi di eccezioni, si può voler essere più precisi gestendo l’eccezione con più clausole catch:

try{
    appel de la fonction susceptible de générer l'exception
} catch (IOException e){
    traiter l'exception e
}
} catch (ArrayIndexOutOfBoundsException e){
    traiter l'exception e
}
} catch (RunTimeException e){
    traiter l'exception e
}
instruction suivante
  • È possibile aggiungere alle clausole try/catch una clausola finally:
try{
    appel de la fonction susceptible de générer l'exception
} catch (Exception e){
    traiter l'exception e
}
finally{
    code exécuté après try ou catch
}
instruction suivante

In questo caso, indipendentemente dal fatto che si verifichi o meno un'eccezione, il codice della clausola finally verrà sempre eseguito.

  • La classe Exception dispone di un metodo getMessage() che restituisce un messaggio con i dettagli dell’errore verificatosi. Pertanto, se si desidera visualizzarlo, si scriverà:
catch (Exception ex){
    System.err.println("L'erreur suivante s'est produite : "+ex.getMessage());
    ...
}//catch
  • La classe Exception dispone di un metodo toString() che restituisce una stringa di caratteri indicante il tipo dell'eccezione e il valore della proprietà Message. Si potrà quindi scrivere:
catch (Exception ex){
    System.err.println ("L'erreur suivante s'est produite : "+ex.toString());
    ...
}//catch

Si può scrivere anche:

catch (Exception ex){
    System.err.println ("L'erreur suivante s'est produite : "+ex);
    ...
}//catch

In questo caso abbiamo un'operazione string + Exception che verrà automaticamente trasformata dal compilatore in string + Exception.toString() per concatenare due stringhe di caratteri.

L'esempio seguente mostra un'eccezione generata dall'utilizzo di un elemento di array inesistente:

// quadri

// importazioni
import java.io.*;

public class tab1{
  public static void main(String[] args){
    // dichiarazione e inizializzazione di un array
    int[] tab=new int[] {0,1,2,3};
    int i;
     // visualizzazione di un array con un ciclo for
    for (i=0; i<tab.length; i++)
      System.out.println("tab[" + i + "]=" + tab[i]);
    // generazione di un'eccezione
      try{
      tab[100]=6;
    }catch (Exception e){
      System.err.println("L'erreur suivante s'est produite : " + e);
    }//try-catch
  }//main
}//classe

L'esecuzione del programma fornisce i seguenti risultati:

tab[0]=0
tab[1]=1
tab[2]=2
tab[3]=3
L'erreur suivante s'est produite : java.lang.ArrayIndexOutOfBoundsException

Ecco un altro esempio in cui si gestisce l'eccezione causata dall'assegnazione di una stringa di caratteri a un numero quando la stringa non rappresenta un numero:

// importazioni
import java.io.*;

public class console1{
  public static void main(String[] args){
      // creazione di un flusso di input
    BufferedReader IN=null;
    try{
        IN=new BufferedReader(new InputStreamReader(System.in));
    }catch(Exception ex){}
     // Richiesta del nome
    System.out.print("Nom : ");
     // lettura della risposta
    String nom=null;
    try{
        nom=IN.readLine();
    }catch(Exception ex){}      
     // viene richiesta l'età
    int age=0;
    boolean ageOK=false;
    while ( ! ageOK){
       // domanda
      System.out.print("âge : ");
       // Lettura e verifica della risposta
      try{
        age=Integer.parseInt(IN.readLine());
        ageOK=true;
      }catch(Exception ex) {
        System.err.println("Age incorrect, recommencez...");
      }//try-catch
    }//while
     // visualizzazione finale
    System.out.println("Vous vous appelez " + nom + " et vous avez " + age + " ans");
  }//Main
}//classe

Alcuni risultati dell'esecuzione:

dos>java console1
Nom : dupont
âge : 23
Vous vous appelez dupont et vous avez 23 ans
E:\data\serge\MSNET\c#\bases\1>console1
Nom : dupont
âge : xx
Age incorrect, recommencez...
âge : 12
Vous vous appelez dupont et vous avez 12 ans

2.7. Compilazione ed esecuzione di un programma Java

Compilare ed eseguire il seguente programma:

// importazione delle classi
import java.io.*;

// classe di test
public class coucou{
    // funzione main
  public static void main(String args[]){
      // visualizzazione sullo schermo
    System.out.println("coucou");
  }//main
}//classe

Il file sorgente contenente la classe coucou precedente deve necessariamente chiamarsi coucou.java:

E:\data\serge\JAVA\ESSAIS\intro1>dir
10/06/2002  08:42                  228 coucou.java

La compilazione e l'esecuzione di un programma Java avvengono in una finestra DOS. I file eseguibili javac.exe (compilatore) e java.exe (interprete) si trovano nella directory bin della directory di installazione di JDK:

E:\data\serge\JAVA\classes\paquetages\personne>dir "e:\program files\jdk14\bin\java?.exe"
07/02/2002  12:52               24 649 java.exe
07/02/2002  12:52               28 766 javac.exe

Il compilatore javac.exe analizzerà il file sorgente .java e genererà un file compilato .class. Quest'ultimo non è immediatamente eseguibile dal processore. Richiede un interprete Java (java.exe), denominato macchina virtuale o JVM (Java Virtual Machine). A partire dal codice intermedio presente nel file .class, la macchina virtuale genererà istruzioni specifiche per il processore del computer su cui viene eseguita. Esistono macchine virtuali Java per diversi tipi di sistemi operativi (Windows, Unix, Mac OS, ecc.). Un file .class potrà essere eseguito da una qualsiasi di queste macchine virtuali e quindi su qualsiasi sistema operativo. Questa portabilità tra sistemi è uno dei principali punti di forza di Java.

Compiliamo il programma precedente:

E:\data\serge\JAVA\ESSAIS\intro1>"e:\program files\jdk14\bin\javac" coucou.java

E:\data\serge\JAVA\ESSAIS\intro1>dir
10/06/2002  08:42                  228 coucou.java
10/06/2002  08:48                  403 coucou.class

Eseguiamo il file .class generato:

E:\data\serge\JAVA\ESSAIS\intro1>"e:\program files\jdk14\bin\java" coucou
coucou

Si noti che nella richiesta di esecuzione sopra riportata non è stato specificato il suffisso .class del file coucou.class da eseguire. È implicito. Se la directory bin del file JDK si trova all’interno del file PATH della macchina DOS, non sarà necessario specificare il percorso completo dei file eseguibili javac.exe e java.exe. Basterà quindi scrivere semplicemente

javac coucou.java
java coucou

2.8. Argomenti del programma principale

La funzione principale main accetta come parametro un array di stringhe: String[]. Questo array contiene gli argomenti della riga di comando utilizzata per avviare l'applicazione. Pertanto, se si avvia il programma P con il comando:

        java P arg0 arg1 … argn

e se la funzione main è dichiarata come segue:

public static void main(String[] arg);

si avrà arg[0]="arg0", arg[1]="arg1" … Ecco un esempio:


import java.io.*;

public class param1{
  public static void main(String[] arg){
    int i;
    System.out.println("Nombre d'arguments="+arg.length);
    for (i=0;i<arg.length;i++)
      System.out.println("arg["+i+"]="+arg[i]);
  }
}

I risultati ottenuti sono i seguenti:

dos>java param1 a b c
Nombre d'arguments=3
arg[0]=a
arg[1]=b
arg[2]=c

2.9. Passaggio di parametri a una funzione

Gli esempi precedenti hanno mostrato solo programmi Java con una sola funzione, ovvero la funzione principale main. L'esempio seguente illustra come utilizzare le funzioni e come avviene lo scambio di informazioni tra di esse. I parametri di una funzione vengono sempre passati per valore: ciò significa che il valore del parametro effettivo viene copiato nel parametro formale corrispondente.


import java.io.*;

public class param2{
  public static void main(String[] arg){
    String S="papa";
    changeString(S);
    System.out.println("Paramètre effectif S="+S);
    int age=20;
    changeInt(age);
    System.out.println("Paramètre effectif age="+age);
  }
  private static void changeString(String S){
    S="maman";
    System.out.println("Paramètre formel S="+S);
  }
  private static void changeInt(int a){
    a=30;
    System.out.println("Paramètre formel a="+a);
  }
}

I risultati ottenuti sono i seguenti:

Paramètre formel S=maman
Paramètre effectif S=papa
Paramètre formel a=30
Paramètre effectif age=20

I valori dei parametri effettivi "papa" e 20 sono stati copiati nei parametri formali S e a. Questi ultimi sono stati poi modificati. I parametri effettivi sono rimasti invece invariati. Si noti in particolare il tipo dei parametri effettivi:

  • S è un riferimento all’oggetto c.a.d, ovvero l’indirizzo di un oggetto in memoria
  • age è un valore intero

2.10. L'esempio delle imposte

Concluderemo questo capitolo con un esempio che riprenderemo più volte nel presente documento. Ci proponiamo di scrivere un programma che consenta di calcolare l’imposta di un contribuente. Consideriamo il caso semplificato di un contribuente che abbia da dichiarare solo il proprio stipendio:

  • si calcola il numero di quote del dipendente nbParts=nbEnfants/2 +1 se non è sposato, nbEnfants/2+2 se è sposato, dove nbEnfants è il numero dei suoi figli.
  • se ha almeno tre figli, ha diritto a una mezza quota in più
  • si calcola il suo reddito imponibile R = 0,72 * S, dove S è il suo stipendio annuale
  • si calcola il suo coefficiente familiare QF = R / nbParts
  • si calcola la sua imposta I. Consideriamo la seguente tabella:
12620,0
0
0
13190
0,05
631
15640
0,1
1290,5
24.740
0,15
2072,5
31810
0,2
3309,5
39.970
0,25
4900
48360
0,3
6898,5
55790
0,35
9316,5
92970
0,4
12106
127.860
0,45
16754,5
151250
0,50
23147,5
172.040
0,55
30710
195.000
0,60
39312
0
0,65
49062

Ogni riga ha 3 campi. Per calcolare l'imposta I, si cerca la prima riga in cui QF<=campo1. Ad esempio, se QF=23000, si troverà la riga

    24740        0.15        2072.5

L'imposta I è quindi pari a 0,15*R - 2072,5*nbParts. Se QF è tale che la relazione QF<=campo1 non è mai soddisfatta, allora vengono utilizzati i coefficienti dell’ultima riga. In questo caso:

    0                0.65        49062

il che dà l'imposta I=0,65*R - 49062*nbParts.

Il programma Java corrispondente è il seguente:


import java.io.*;

public class impots{

    // ------------ main
    public static void main(String arg[]){

        // dati

        // scaglioni fiscali
        double Limites[]={12620, 13190, 15640, 24740, 31810, 39970, 48360,55790, 92970, 127860, 151250, 172040, 195000, 0};    
        // coefficiente applicato al numero di quote
        double Coeffn[]={0, 631, 1290.5, 2072.5, 3309.5, 4900, 6898.5, 9316.5,12106, 16754.5, 23147.5, 30710, 39312, 49062};

        // il programma

        // creazione del flusso di input da tastiera
        BufferedReader IN=null;
        try{
            IN=new BufferedReader(new InputStreamReader(System.in));
        }
        catch(Exception e){
            erreur("Création du flux d'entrée", e, 1);
        }

            // si recupera lo stato civile
        boolean OK=false;
        String reponse=null;
        while(! OK){
            try{
                System.out.print("Etes-vous marié(e) (O/N) ? ");
                reponse=IN.readLine();
                reponse=reponse.trim().toLowerCase();
                if (! reponse.equals("o") && !reponse.equals("n"))
                    System.out.println("Réponse incorrecte. Recommencez");
                else OK=true;
            } catch(Exception e){
                erreur("Lecture état marital",e,2);
            }
        }
        boolean Marie = reponse.equals("o");

            // numero di figli
        OK=false;
        int NbEnfants=0; 
        while(! OK){
            try{
                System.out.print("Nombre d'enfants : ");
                reponse=IN.readLine();
                try{
                    NbEnfants=Integer.parseInt(reponse);
                    if(NbEnfants>=0) OK=true; 
                        else System.err.println("Réponse incorrecte. Recommencez");
                } catch(Exception e){
                    System.err.println("Réponse incorrecte. Recommencez");
                }// try
            } catch(Exception e){
                erreur("Lecture état marital",e,2);
            }// try
        }// while

        // stipendio
        OK=false;
        long Salaire=0; 
        while(! OK){
            try{
                System.out.print("Salaire annuel : ");
                reponse=IN.readLine();
                try{
                    Salaire=Long.parseLong(reponse);
                    if(Salaire>=0)  OK=true;
                        else System.err.println("Réponse incorrecte. Recommencez");
                } catch(Exception e){
                    System.err.println("Réponse incorrecte. Recommencez");
                }// try
            } catch(Exception e){
                erreur("Lecture Salaire",e,4);
            }// try
        }// while

            // calcolo del numero di quote
        double NbParts;
        if(Marie) NbParts=(double)NbEnfants/2+2;
            else NbParts=(double)NbEnfants/2+1;
        if (NbEnfants>=3) NbParts+=0.5;
        
            // reddito imponibile
        double Revenu;
        Revenu=0.72*Salaire;

            // quoziente familiare
        double QF;
        QF=Revenu/NbParts;
        
            // ricerca della fascia di imposta corrispondente a QF
        int i;
        int NbTranches=Limites.length;
        Limites[NbTranches-1]=QF;
        i=0;
        while(QF>Limites[i]) i++;
            // l'imposta
        long impots=(long)(i*0.05*Revenu-Coeffn[i]*NbParts);

        // viene visualizzato il risultato
        System.out.println("Impôt à payer : " + impots);
    }// main

    // ------------ errore
    private static void erreur(String msg, Exception e, int exitCode){
        System.err.println(msg+"("+e+")");
        System.exit(exitCode);
    }// errore

}// classe

I risultati ottenuti sono i seguenti:

C:\Serge\java\impots\1>java impots

Etes-vous marié(e) (O/N) ? o
Nombre d'enfants : 3
Salaire annuel : 200000
Impôt à payer : 16400

C:\Serge\java\impots\1>java impots

Etes-vous marié(e) (O/N) ? n
Nombre d'enfants : 2
Salaire annuel : 200000
Impôt à payer : 33388

C:\Serge\java\impots\1>java impots

Etes-vous marié(e) (O/N) ? w
Réponse incorrecte. Recommencez
Etes-vous marié(e) (O/N) ? q
Réponse incorrecte. Recommencez
Etes-vous marié(e) (O/N) ? o
Nombre d'enfants : q
Réponse incorrecte. Recommencez
Nombre d'enfants : 2
Salaire annuel : q
Réponse incorrecte. Recommencez
Salaire annuel : 1
Impôt à payer : 0