Skip to content

2. Le basi del linguaggio Java

2.1. Introduzione

Inizialmente tratteremo Java come un linguaggio di programmazione tradizionale. Tratteremo gli oggetti in seguito.

In un programma, ci sono due cose

  • i dati
  • le istruzioni che li manipolano

In genere ci sforziamo di separare i dati dalle istruzioni:

Image

2.2. Dati Java

Java utilizza i seguenti tipi di dati:

  • interi
  • numeri in virgola mobile
  • caratteri e stringhe
  • Booleani
  • oggetti

2.2.1. Tipi di dati predefiniti

Tipo
Codifica
Intervallo
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
[-2(15), 2(15),-1]
float
4 byte
[3,410⁻³⁸, 3,410³⁸] in valore assoluto
doppio
8 byte
[1,7 × 10⁻³⁰⁸, 1,7 × 10³⁰⁸] in valore assoluto
booleano
1 bit
vero, falso
Stringa
riferimento a un oggetto
stringa
Data
riferimento a un oggetto
data
Carattere
riferimento all'oggetto
carattere
Intero
riferimento a un oggetto
int
Long
riferimento a un oggetto
long
Byte
riferimento a oggetto
byte
Float
riferimento a oggetto
float
doppio
riferimento a un oggetto
double
Booleano
riferimento a un oggetto
Booleano

2.2.2. Notazione dei dati letterali

intero
145, -7, 0xFF (esadecimale)
doppio
134,789, -45E-18 (-45 × 10⁻¹⁸)
float
134,789F, -45E-18F (-45 × 10⁻¹⁸)
carattere
'A', 'b'
stringa
"oggi"
booleano
vero, falso
data
new Date(13,10,1954) (giorno, mese, anno)

2.2.3. Dichiarazione dei dati

2.2.3.1. Ruolo delle dichiarazioni

Un programma manipola dati caratterizzati da un nome e da un tipo. Questi dati vengono memorizzati nella memoria. Quando il programma viene compilato, il compilatore assegna a ciascun dato una posizione di memoria caratterizzata da un indirizzo e da una dimensione. Lo fa utilizzando le dichiarazioni effettuate dal programmatore.

Inoltre, queste dichiarazioni consentono al compilatore di rilevare errori di programmazione. Pertanto, l'operazione

x=x*2;

sarà dichiarata errata se x è una stringa, ad esempio.

2.2.3.2. Dichiarazione delle costanti

La sintassi per dichiarare una costante è la seguente:

<mark style="background-color: #ffff00">tipo</mark>**<mark style="background-color: #ffff00"> finale </mark>**<mark style="background-color: #ffff00">nome=valore; </mark>          //definisce una costante nome=valore

es.: final float PI=3.141592F;

Nota

Perché dichiarare le costanti?

  • Il programma sarà più facile da leggere se alla costante viene assegnato un nome significativo:
es.: *final float VAT\_rate=0.186F*;
  • Modificare il programma sarà più semplice se la "costante" deve essere cambiata. Pertanto, nel caso precedente, se l'aliquota IVA cambia al 33%, l'unica modifica necessaria sarà quella di cambiare l'istruzione che ne definisce il valore:
*final float aliquota\_fiscale=0.33F*;

Se avessimo utilizzato esplicitamente 0,186 nel programma, avremmo dovuto modificare numerose istruzioni.

2.2.3.3. Dichiarazione delle variabili

Una variabile è identificata da un nome e fa riferimento a un tipo di dati. Un nome di variabile Java è composto da n caratteri, il primo dei quali deve essere una lettera, mentre gli altri possono essere lettere o numeri. Java distingue tra lettere 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 identificatore_di_tipo è un tipo predefinito o un tipo di oggetto definito dal programmatore.

2.2.4. 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(string).floatValue()

Ecco un programma che illustra le principali tecniche di conversione tra numeri e stringhe. La conversione di una stringa in un numero potrebbe non riuscire se la stringa non rappresenta un numero valido. Ciò provoca un errore irreversibile, noto come eccezione in Java. Questo errore può essere gestito utilizzando il seguente blocco try/catch:

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, il programma procede all'istruzione successiva; altrimenti, entra nel corpo della clausola catch e poi procede all'istruzione successiva. Torneremo più avanti alla 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;
 
    // number --> string
    S=""+i;
    affiche(S);
    S=""+l;
    affiche(S);
    S=""+f;
    affiche(S);
    S=""+d;
    affiche(S);
 
    //boolean --> string
    final boolean b=false;
    S=""+new Boolean(b);
    affiche(S);
 
    // string --> int
    int i1;
    i1=Integer.parseInt("10");
    affiche(""+i1);
    try{
      i1=Integer.parseInt("10.67");
      affiche(""+i1);
    } catch (Exception e){
      affiche("Erreur "+e);
    }
 
    // string --> long
    long l1;
    l1=Long.parseLong("100");
    affiche(""+l1);
    try{
      l1=Long.parseLong("10.675");
      affiche(""+l1);
    } catch (Exception e){
      affiche("Erreur "+e);
    }
    
    // chain --> 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);
    }
 
    // string --> 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 hand
 
  public static void affiche(String S){
    System.out.println("S="+S);
  }
}// end of class

I risultati 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. Matrici di dati

Un array Java è un oggetto che consente di raggruppare dati dello stesso tipo sotto un unico identificatore. Viene dichiarato come segue:

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] si riferisce all'elemento all'indice i, dove i è compreso nell'intervallo [0,n-1]. Qualsiasi riferimento all'elemento Array[i] dove i non è compreso nell'intervallo [0,n-1] causerà un'eccezione.

Un array bidimensionale può essere dichiarato come segue:

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

La sintassi Array[i] si riferisce all'elemento i di Array, dove i appartiene all'intervallo [0,n-1]. Array[i] è esso stesso un array: Array[i][j] si riferisce al j-esimo elemento di Array[i], dove j appartiene all'intervallo [0,p-1]. Qualsiasi riferimento a un elemento di Array con indici errati genera un errore fatale.

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 dotato di un attributo "length": si tratta della dimensione dell'array.

2.3. Comandi Java di base

Distinguiamo

  • le istruzioni di base eseguite dal computer.
  • istruzioni che controllano il flusso del programma.

Le istruzioni di base diventano chiare se si considera la struttura di un microcomputer e delle sue periferiche.

Image

  1. Lettura delle informazioni dalla tastiera

  2. Elaborazione delle informazioni

  3. Scrittura delle informazioni sullo schermo

  4. Lettura delle informazioni da un file su disco

  5. Scrivere informazioni su un file su disco

2.3.1. Scrivere sullo schermo

La sintassi dell'istruzione di output su schermo è la seguente:

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

dove espressione è un tipo di dati qualsiasi che può essere convertito in una stringa da visualizzare sullo schermo. Nell'esempio precedente abbiamo visto due istruzioni di stampa:

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

System.out scrive su un file di testo, che per impostazione predefinita è lo schermo. Lo stesso vale per System.err. A questi file sono assegnati rispettivamente i numeri (o descrittori) 1 e 2. Anche il flusso di input della tastiera (System.in) viene trattato come un file di testo, con descrittore 0. Sia DOS che Unix supportano il piping dei comandi:

    commande1 | commande2

Tutto ciò che command1 scrive su System.out viene convogliato (reindirizzato) all'ingresso System.in di command2. In altre parole, command2 legge da System.in i dati prodotti da command2 tramite System.out, che quindi non vengono più visualizzati sullo schermo. Questo sistema è ampiamente utilizzato in Unix. In questo piping, il flusso System.err non viene reindirizzato: scrive sullo schermo. Questo è il motivo per cui viene utilizzato per scrivere messaggi di errore (da cui il nome err): possiamo essere certi che quando i comandi vengono sottoposti a piping, i messaggi di errore continueranno ad apparire sullo schermo. Dovremmo quindi prendere l'abitudine di scrivere i messaggi di errore sullo schermo utilizzando il flusso System.err piuttosto che il flusso System.out.

2.3.2. Lettura dei dati digitati sulla tastiera

Il flusso di dati proveniente dalla tastiera è rappresentato dall'oggetto System.in di tipo InputStream. Questo tipo di oggetto consente di leggere i dati carattere per carattere. Spetta poi al programmatore estrarre le informazioni rilevanti da questo flusso di caratteri. Il tipo InputStream non consente di leggere un'intera riga di testo in una sola volta. Il tipo BufferedReader lo consente tramite il metodo readLine.

Per leggere le righe di testo immesse tramite la tastiera, creiamo un nuovo flusso di input di tipo BufferedReader a partire dal flusso di input System.in* di tipo InputStream*:

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

Non spiegheremo qui i dettagli di questa istruzione, poiché riguarda il concetto di costruzione di oggetti. La useremo così com'è.

La creazione di uno stream 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 questa venga gestita dal programmatore. Pertanto, per creare lo stream di input precedente, dobbiamo effettivamente 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 entreremo nei dettagli della gestione delle eccezioni. Una volta creato il flusso IN precedente, possiamo leggere una riga di testo utilizzando 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 input/output

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


import java.io.*;        // required to use I/O streams
 
public class io1{
  
  
  public static void main (String[] arg){
    
    // write to System.out stream
    Object obj=new Object();
    System.out.println(""+obj);
    System.out.println(obj.getClass().getName());
    
    // write to System.err stream
    int i=10;
    System.err.println("i="+i);
    
    // reading a line entered on the keyboard
    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 hand
 
  public static void affiche(Exception e){
    System.err.println("Erreur : "+e);
  }
 
}//end of class

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 mostrare che qualsiasi oggetto può essere visualizzato. Non tenteremo qui di spiegare il significato di ciò che viene visualizzato. Nel blocco abbiamo 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 Exception che viene visualizzato qui utilizzando la chiamata display(e). Abbiamo incontrato questa visualizzazione del valore di un'eccezione nel programma di conversione visto in precedenza, anche se all'epoca non ne abbiamo discusso.

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

In questo caso ci interessa l'operazione variabile=espressione;

L'espressione può essere dei seguenti tipi: aritmetica, relazionale, booleana, stringa

2.3.4.1. Interpretazione dell'operazione di assegnazione

L'operazione variabile=espressione; è essa stessa un'espressione la cui valutazione procede come segue:

  • Viene valutato il lato destro dell'assegnazione: il risultato è un valore V.
  • Il valore V viene assegnato alla variabile
  • Il valore V è anche il valore dell'assegnazione, ora considerata come un'espressione.

Ecco perché l’espressione V1=V2=espressione è valida. A causa della precedenza, verrà valutato l'operatore = più a destra. Abbiamo quindi V1=(V2=espressione). L'espressione V2=espressione viene valutata e ha il valore V. La valutazione di questa espressione ha causato l'assegnazione di V a V2. L'operatore = successivo viene quindi valutato come V1=V. Il valore di questa espressione è ancora V. La sua valutazione fa sì che V venga assegnato a V1. Pertanto, l'operazione V1=V2=espressione è un'espressione la cui valutazione

1: fa sì che il valore di espressione venga assegnato alle variabili V1 e V2

2: restituisce il valore di espressione come risultato.

Possiamo generalizzare questo concetto in un'espressione della forma: V1=V2=....=Vn=espressione

2.3.4.2. Espressione aritmetica

Gli operatori per le espressioni aritmetiche sono i seguenti:

+: addizione

  • : sottrazione

*: moltiplicazione

/ : divisione: il risultato è il quoziente esatto se almeno uno degli operandi è 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, con il quoziente che è un numero intero. Si tratta quindi dell'operazione modulo.

Esistono varie funzioni matematiche:

double sqrt(double x)
radice quadrata
double cos(double x)
coseno
doppio sin(doppio x)
Seno
tangente
Tangente
double pow(double x, double y)
x elevato a y (x > 0)
doppio exp(doppio x)
Esponenziale
log(x)
logaritmo naturale
doppio abs(doppio x)
valore assoluto

ecc...

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

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)
{
        // Fields
    public final static double E;    §1.10.1
    public final static double PI;    §1.10.2
 
        // Methods
    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. Operatori nella valutazione delle espressioni aritmetiche

La precedenza degli operatori nella valutazione di un'espressione aritmetica è la seguente (dalla più alta alla più bassa):

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

Gli operatori all'interno dello stesso blocco [ ] hanno la stessa precedenza.

2.3.4.4. Operatori relazionali

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

Ordine di precedenza

       &gt;, &gt;=, &lt;, &lt;=

       ==, !=

Il risultato di un'espressione relazionale è il valore booleano false se l'espressione è falsa; in caso contrario, è true.

Esempio:

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

Confronto tra due caratteri

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

&lt;, &lt;=, ==, !=, &gt;, &gt;=

In questo caso, vengono confrontati i loro codici ASCII, che sono numeri. Ricordiamo che, secondo l'ordine ASCII, valgono 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 nella stessa direzione per le stringhe.

Esempi:

Si consideri il confronto tra le stringhe "Cat" e "Dog"

Quest'ultima disuguaglianza ci permette di concludere che "Cat" < "Dog".

Image

Consideriamo il confronto tra le stringhe "Cat" e "Kitten". Sono uguali per tutta la lunghezza fino a quando la stringa "Cat" non è esaurita. In questo caso, la stringa esaurita viene dichiarata quella "più piccola". Abbiamo quindi la relazione

&quot;Cat&quot; &lt; &quot;Kitten&quot;.

Funzioni per il confronto tra due stringhe

Qui non possiamo usare gli operatori relazionali <, <=, ==, !=, >, >=. Dobbiamo usare i metodi della classe String:

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

Nel codice sopra riportato, la variabile i avrà il valore:

    0: se le due stringhe sono uguali

    1: se stringa 1 &gt; stringa 2

    -1: se stringa 1 &lt; stringa 2

La variabile equal avrà il valore true se le due stringhe sono uguali.

2.3.4.5. Espressioni booleane

Gli operatori sono & (e), || (o) e ! (non). Il risultato di un'espressione booleana è un valore booleano.

Ordine di precedenza ! , &&, ||

esempio:

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

Gli operatori relazionali hanno 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 in entrata 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
Esegue l'operazione logica AND tra i e j bit per bit.
i | j
esegue l'OR logico di i e j bit per bit.
~i
completa i a 1
i^j
esegue l'operazione XOR tra 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-- significa variable=variable-1 oppure variable-=1.

2.3.4.9. L'operatore ?

L'espressione expr_cond ? expr1:expr2 viene valutata come segue:

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 è falso, si verifica il contrario: il valore dell'espressione è quello di expr2. expr1 non viene valutato.

Esempio

*i = (j &gt; 4 ? j + 1 : j - 1);*

assegnerà alla variabile i:

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

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

2.3.4.10. Ordine di precedenza generale degli operatori

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

gd: indica che, per gli operatori di pari precedenza, viene osservata la precedenza da sinistra a destra. Ciò significa che quando un'espressione contiene operatori della stessa precedenza, viene valutato per primo l'operatore più a sinistra nell'espressione. dg indica la precedenza da destra a sinistra.

2.3.4.11. Conversione di tipo

È possibile, all'interno di un'espressione, modificare temporaneamente la rappresentazione di un valore. Questo processo è chiamato conversione di tipo. La sintassi per modificare il tipo di un valore in un'espressione è (tipo) valore. Il valore assume quindi il tipo specificato. Ciò comporta una modifica nella rappresentazione del valore.

Esempio:

int i, j;
float isurj;
isurj= (float)i/j;   // priorité de () sur /

Qui è necessario convertire i o j in un tipo a virgola mobile; altrimenti, la divisione restituirà un quoziente intero anziché un valore a virgola mobile.

     *i* è un valore codificato esattamente in 2 byte

     *(float) i* è lo stesso valore, codificato approssimativamente come un numero in virgola mobile su 4 byte

Si ha quindi una conversione di tipo del valore di i. Questa conversione avviene solo per la durata di un calcolo; la variabile i conserva sempre il suo tipo int.

2.4. Istruzioni di controllo del flusso del programma

2.4.1. Basta

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

Sintassi : void exit(int status)

Azione  : interrompe il processo corrente e restituisce il valore di stato al processo padre

exit termina il processo corrente e restituisce il controllo al processo chiamante. Il valore di stato può essere utilizzato dal processo chiamante. In DOS, questa variabile di stato viene restituita a DOS nella variabile di sistema ERRORLEVEL, il cui valore può essere verificato in un file batch. In Unix, la variabile $? recupera il valore di stato 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 condizionale 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'è "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 nidificare le strutture decisionali:

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

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 istruzione if si riferisce l'else? La regola è che un else si riferisce sempre all'istruzione *if più vicina: if(n&gt;6)* in questo 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 from if(n>6): nothing to do 
   else System.out.println("<=1");    // else du if(n>1) 
}

Qui volevamo inserire un else nell'istruzione if(n>1) e nessun else nell'istruzione if(n>6). A causa della nota precedente, siamo costretti a inserire un else nell'istruzione if(n>6), nella quale non c'è alcuna istruzione.

2.4.3. Struttura case

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 predefinita può essere omessa.
  • I valori vi sono valori possibili dell'espressione. Se l'espressione restituisce il valore vi, vengono eseguite le azioni che seguono la clausola case vi.
  • L'istruzione break esce dalla struttura case. Se è assente alla fine del blocco di istruzioni per il valore vi, l'esecuzione prosegue con le istruzioni per il valore vi+1.

esempio

Negli algoritmi

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 del ciclo

2.4.4.1. Numero noto di ripetizioni

Sintassi


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

Note

  • I tre argomenti del ciclo for sono racchiusi tra parentesi.
  • I tre argomenti del ciclo for sono separati da punti e virgola.
  • Ogni azione nel ciclo for è terminata 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.

L'equivalente algoritmico è la struttura for:

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

che può essere tradotto in una struttura while:

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

2.4.4.2. Numero di ripetizioni sconosciuto

In Java esistono molte strutture di controllo per questo caso.

Ciclo 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 è terminata da un punto e virgola.
  • Le parentesi graffe sono necessarie solo se c'è più di un'azione.
  • La parentesi graffa non è seguita da un punto e virgola.

La struttura algoritmica corrispondente è la struttura while:

tantque condition
        actions
fintantque

Struttura 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 è terminata da un punto e virgola.
  • Le parentesi graffe sono necessarie solo se c'è più di un'azione.
  • La parentesi graffa non è seguita da un punto e virgola.

La struttura algoritmica corrispondente è la struttura "repeat ... until":

répéter
    actions
jusqu'à condition

Struttura per "in generale" (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_di_inizio vengono eseguite prima di entrare nel ciclo per la prima volta. Le istruzioni_di_fine_ciclo vengono eseguite dopo ogni iterazione.

Note

  • I tre argomenti del ciclo for sono racchiusi tra parentesi.
  • I tre argomenti del ciclo for sono separati da punti e virgola.
  • Ogni istruzione for termina con 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.
  • Le varie istruzioni in start_statements e end_loop_statements 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 di controllo del ciclo

break
Esce dal ciclo for, while o do...while.
continue
passa all'iterazione successiva dei cicli for, while e do...while

2.5. La struttura di un programma Java

Un programma Java che non utilizza classi o funzioni definite dall'utente diverse dalla funzione main può avere la seguente struttura:


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

La funzione main, nota anche come metodo, è la prima ad essere eseguita all'avvio di un programma Java. Deve 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 cosa. Si tratta di un array di stringhe che rappresenta gli argomenti della riga di comando. Torneremo su questo punto più avanti.

Se si utilizzano funzioni che potrebbero generare eccezioni che non si desidera gestire esplicitamente, è possibile racchiudere il codice del programma in un blocco try/catch:


public class test1{
    public static void main(String arg[]){
        try{
        … code du programme
        } catch (Exception e){
            // error handling
        }// try
    }// hand
}// class

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


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

Facciamo un esempio. Consideriamo la seguente istruzione di scrittura:

System.out.println("java");

che stampa "java" sullo schermo. C'è molto da scoprire in questa semplice istruzione:

  • 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 che non è stato ancora trattato. Una classe può essere considerata come una risorsa. In questo caso, il compilatore avrà bisogno di accedere sia alla classe java.lang.System che a quella java.io.PrintStream. Le centinaia di classi Java sono organizzate in archivi noti anche come pacchetti. Le istruzioni import poste all'inizio del programma servono a indicare al compilatore di quali classi esterne il programma ha bisogno (quelle utilizzate ma non definite nel file sorgente da compilare). Pertanto, nel nostro esempio, il nostro programma necessita delle classi java.lang.System e java.io.PrintStream. Lo specifichiamo con l'istruzione import. Potremmo scrivere all'inizio del programma:

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

Poiché un programma Java utilizza comunemente decine di classi esterne, sarebbe noioso scrivere tutte le istruzioni di importazione necessarie. Le classi sono state raggruppate in pacchetti e possiamo importare l'intero pacchetto. Pertanto, per importare i pacchetti java.lang e java.io, scriviamo:

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

Il pacchetto java.lang contiene tutte le classi di base di Java e viene importato automaticamente dal compilatore. Quindi, in definitiva, scriveremo semplicemente:

import java.io.*;

2.6. Gestione delle eccezioni

Molte funzioni Java sono in grado di 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 rischia di generare un'eccezione, il compilatore Java richiede al programmatore di gestirla al fine di produrre programmi più resistenti agli errori: è necessario evitare sempre che un'applicazione si "blocchi" in modo imprevisto. 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 delle eccezioni segue questo schema:

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, il programma passa all'istruzione successiva; in caso contrario, entra nel corpo della clausola catch e poi passa all'istruzione successiva. Si notino i seguenti punti:

  • e è un oggetto derivato dal tipo Exception. Possiamo essere più specifici utilizzando tipi come IOException, SecurityException, ArithmeticException, ecc.: esistono circa venti tipi di eccezioni. Scrivendo catch (Exception e), indichiamo che vogliamo gestire tutti i tipi di eccezioni. Se il codice nel blocco try è suscettibile di generare più tipi di eccezioni, potremmo voler essere più specifici gestendo l'eccezione con più blocchi 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 una clausola finally ai blocchi try/catch:
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 nella clausola finally verrà sempre eseguito.

  • La classe Exception dispone di un metodo getMessage() che restituisce un messaggio che descrive in dettaglio l'errore verificatosi. Quindi, se vogliamo visualizzare questo messaggio, scriviamo:
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 indicante il tipo di eccezione e il valore della proprietà Message. Possiamo quindi scrivere:
catch (Exception ex){
    System.err.println ("L'erreur suivante s'est produite : "+ex.toString());
    ...
}//catch

Possiamo anche scrivere:

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

Qui abbiamo un'operazione stringa + Exception che verrà automaticamente convertita in stringa + Exception.toString() dal compilatore al fine di concatenare due stringhe.

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

// tables

// imports
import java.io.*;

public class tab1{
  public static void main(String[] args){
    // declaring & initializing an array
    int[] tab=new int[] {0,1,2,3};
    int i;
     // table display with for
    for (i=0; i<tab.length; i++)
      System.out.println("tab[" + i + "]=" + tab[i]);
    // generating an exception
      try{
      tab[100]=6;
    }catch (Exception e){
      System.err.println("L'erreur suivante s'est produite : " + e);
    }//try-catch
  }//hand
}//class

L'esecuzione del programma produce 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 gestiamo l'eccezione causata dall'assegnazione di una stringa a un numero quando la stringa non rappresenta un numero:

// imports
import java.io.*;

public class console1{
  public static void main(String[] args){
      // creation of an input stream
    BufferedReader IN=null;
    try{
        IN=new BufferedReader(new InputStreamReader(System.in));
    }catch(Exception ex){}
     // We ask for the name
    System.out.print("Nom : ");
     // reading response
    String nom=null;
    try{
        nom=IN.readLine();
    }catch(Exception ex){}      
     // age requested
    int age=0;
    boolean ageOK=false;
    while ( ! ageOK){
       // question
      System.out.print("âge : ");
       // read-verify answer
      try{
        age=Integer.parseInt(IN.readLine());
        ageOK=true;
      }catch(Exception ex) {
        System.err.println("Age incorrect, recommencez...");
      }//try-catch
    }//while
     // final display
    System.out.println("Vous vous appelez " + nom + " et vous avez " + age + " ans");
  }//Main
}//class

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:

// importing classes
import java.io.*;

// test class
public class coucou{
    // hand function
  public static void main(String args[]){
      // screen display
    System.out.println("coucou");
  }//hand
}//class

Il file sorgente contenente la classe coucou precedente deve essere denominato 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 del 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 produrrà un file .class compilato. Questo file non è immediatamente eseguibile dal processore. Richiede un interprete Java (java.exe), noto come macchina virtuale o JVM (Java Virtual Machine). Dal codice intermedio nel file .class, la macchina virtuale genera istruzioni specifiche per il processore della macchina su cui è in esecuzione. Esistono macchine virtuali Java per diversi tipi di sistemi operativi (Windows, Unix, Mac OS, ecc.). Un file .class può 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 nel comando di esecuzione sopra riportato non abbiamo specificato il suffisso .class per il file coucou.class da eseguire. È implicito. Se la directory bin del JDK si trova nel PATH del computer DOS, non è necessario fornire il percorso completo degli eseguibili javac.exe e java.exe. È sufficiente scrivere

javac coucou.java
java coucou

2.8. Argomenti principali del programma

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

        java P arg0 arg1 … argn

e se la funzione principale è dichiarata come segue:

public static void main(String[] arg);

avremo 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 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 mostravano solo programmi Java con una singola funzione, la funzione main. L'esempio seguente illustra come utilizzare le funzioni e come avviene lo scambio di informazioni tra di esse. I parametri delle funzioni 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 "papà" e 20 sono stati copiati nei parametri formali S e a. Questi sono stati poi modificati. I parametri effettivi sono rimasti invariati. Si noti qui il tipo dei parametri effettivi:

  • S è un riferimento a un oggetto, ovvero l'indirizzo di un oggetto in memoria
  • age è un numero intero

2.10. Un esempio di calcolo delle imposte

Concluderemo questo capitolo con un esempio che riprenderemo più volte nel presente documento. Proponiamo di scrivere un programma per calcolare l'imposta di un contribuente. Consideriamo il caso semplificato di un contribuente che deve dichiarare solo il proprio stipendio:

  • calcoliamo il numero di scaglioni fiscali per il dipendente come nbParts = nbEnfants / 2 + 1 se è celibe, e nbEnfants / 2 + 2 se è coniugato, dove nbEnfants è il numero di figli.
  • Se ha almeno tre figli, riceve una quota aggiuntiva pari a metà.
  • Calcoliamo il reddito imponibile R = 0,72 × S, dove S è lo stipendio annuo
  • Calcoliamo il coefficiente familiare QF = R / nbParts
  • Calcoliamo la tua imposta I. Considera la seguente tabella:
12.620,0
0
0
13.190
0,05
631
15.640
0,1
1.290,5
24.740
0,15
2.072,5
31.810
0,2
3.309,5
39.970
0,25
4.900
48.360
0,3
6.898,5
55.790
0,35
9.316,5
92.970
0,4
12.106
127.860
0,45
16.754,5
151.250
0,50
23.147,5
172.040
0,55
30.710
195.000
0,60
39.312
0
0,65
49.062

Ogni riga ha 3 campi. Per calcolare l'imposta I, cerchiamo la prima riga in cui QF <= campo1. Ad esempio, se QF = 23.000, troveremo la riga

    24740        0.15        2072.5

L'imposta I è quindi pari a 0,15*R - 2072,5*nbParts. Se QF è tale che la condizione QF<=field1 non è mai soddisfatta, vengono utilizzati i coefficienti dell'ultima riga. Qui:

    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{
 
    // ------------ hand
    public static void main(String arg[]){
 
        // data
 
        // tax bracket limits
        double Limites[]={12620, 13190, 15640, 24740, 31810, 39970, 48360,55790, 92970, 127860, 151250, 172040, 195000, 0};    
        // coefficient applied to the number of shares
        double Coeffn[]={0, 631, 1290.5, 2072.5, 3309.5, 4900, 6898.5, 9316.5,12106, 16754.5, 23147.5, 30710, 39312, 49062};
 
        // the program
 
        // keyboard input stream creation
        BufferedReader IN=null;
        try{
            IN=new BufferedReader(new InputStreamReader(System.in));
        }
        catch(Exception e){
            erreur("Création du flux d'entrée", e, 1);
        }
 
            // we recover marital status
        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");
 
            // number of children
        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
 
        // salary
        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
 
            // calculating the number of shares
        double NbParts;
        if(Marie) NbParts=(double)NbEnfants/2+2;
            else NbParts=(double)NbEnfants/2+1;
        if (NbEnfants>=3) NbParts+=0.5;
 
            // taxable income
        double Revenu;
        Revenu=0.72*Salaire;
 
            // family quotient
        double QF;
        QF=Revenu/NbParts;
 
            // search for tax bracket corresponding to QF
        int i;
        int NbTranches=Limites.length;
        Limites[NbTranches-1]=QF;
        i=0;
        while(QF>Limites[i]) i++;
            // tax
        long impots=(long)(i*0.05*Revenu-Coeffn[i]*NbParts);
 
        // the result is displayed
        System.out.println("Impôt à payer : " + impots);
    }// hand
 
    // ------------ error
    private static void erreur(String msg, Exception e, int exitCode){
        System.err.println(msg+"("+e+")");
        System.exit(exitCode);
    }// error
 
}// class

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