Skip to content

2. De basis van de programmeertaal Java

2.1. Inleiding

We behandelen Java in eerste instantie als een klassieke programmeertaal. We zullen later ingaan op objecten.

In een programma komen twee soorten elementen voor

  • gegevens
  • de instructies die deze gegevens bewerken

Meestal proberen we de gegevens en de instructies van elkaar te scheiden:

Image

2.2. De gegevens in Java

Java maakt gebruik van de volgende gegevenstypen:

  • gehele getallen
  • reële getallen
  • tekens en tekenreeksen
  • booleaanse waarden
  • objecten

2.2.1. Vooraf gedefinieerde gegevenstypen

Type
Codering
Domein
char
2 bytes
Unicode-teken
int
4 bytes
[-231, 231-1]
long
8 bytes
[-263, 263 -1]
byte
1 byte
[-27 , 27 -1]
short
2 bytes
[-215, 215-1]
float
4 bytes
[3.4 10-38, 3.4 10+38] in absolute waarde
double
8 bytes
[1.7 10-308 , 1.7 10+308] in absolute waarde
boolean
1 bit
true, false
String
objectreferentie
tekenreeks
Date
objectreferentie
datum
Character
objectreferentie
teken
Integer
objectreferentie
int
Long
objectreferentie
long
Byte
objectreferentie
byte
Float
objectreferentie
float
Double
objectreferentie
double
Boolean
objectreferentie
boolean

2.2.2. Notatie van letterlijke gegevens

entier
145, -7, 0xFF (hexadecimaal)
dubbel reëel
134,789, -45E-18 (-45 × 10⁻¹⁸)
reëel float
134.789F, -45E-18F (-45 × 10⁻¹⁸)
caractère
'A', 'b'
tekenreeks
"vandaag"
booléen
waar, onwaar
date
new Date(13,10,1954) (dag, maand, jaar)

2.2.3. Gegevensrapportage

2.2.3.1. De rol van declaraties

Een programma verwerkt gegevens die worden gekenmerkt door een naam en een type. Deze gegevens worden in het geheugen opgeslagen. Bij het compileren van het programma wijst de compiler aan elk gegeven een geheugenlocatie toe die wordt gekenmerkt door een adres en een grootte. Hierbij maakt de compiler gebruik van de declaraties die door de programmeur zijn gemaakt.

Bovendien stellen deze de compiler in staat om programmeerfouten op te sporen. Zo is de bewerking

x=x*2;

als foutief worden aangemerkt als x bijvoorbeeld een tekenreeks is.

2.2.3.2. Verklaring van constanten

De syntaxis voor het declareren van een constante is als volgt:

final type naam=waarde; //definieert constante naam=waarde

bijv.: final float PI=3.141592F;

Opmerking

Waarom constanten declareren?

  • Het programma is gemakkelijker te lezen als de constante een betekenisvolle naam krijgt:

bijv.: final float taux_tva = 0.186F;

  • Het aanpassen van het programma zal eenvoudiger zijn als de „constante” verandert. Zo zal in het voorgaande geval, als het btw-tarief stijgt naar 33%, de enige aanpassing die moet worden gedaan, bestaan uit het wijzigen van de instructie die de waarde ervan definieert:

final float taux_tva=0.33F;

Als we 0,186 expliciet in het programma hadden gebruikt, zouden er talrijke instructies moeten worden aangepast.

2.2.3.3. Variabelen declareren

Een variabele wordt aangeduid met een naam en verwijst naar een gegevenstype. De naam van een Java-variabele bestaat uit n tekens, waarvan het eerste een letter is en de overige letters of cijfers. Java maakt onderscheid tussen hoofdletters en kleine letters. De variabelen FIN en fin zijn dus verschillend.

Variabelen kunnen bij hun declaratie worden geïnitialiseerd. De syntaxis voor het declareren van één of meerdere variabelen is:

identificateur_de_type variable1,variable2,...,variablen;

waarbij identificateur_de_type een vooraf gedefinieerd type is of een door de programmeur gedefinieerd objecttype.

2.2.4. Conversies tussen getallen en tekenreeksen

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

Hier volgt een programma dat de belangrijkste conversietechnieken tussen getallen en tekenreeksen laat zien. De conversie van een tekenreeks naar een getal kan mislukken als de tekenreeks geen geldig getal vertegenwoordigt. Er wordt dan een fatale fout gegenereerd, in Java een 'exception' genoemd. Deze fout kan worden afgehandeld met de volgende clausule try/catch:

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

Als de functie geen uitzondering genereert, gaan we door naar de volgende instructie; anders gaan we naar de hoofdtekst van de clausule catch en vervolgens naar de volgende instructie. We zullen later terugkomen op het beheer van uitzonderingen.


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;

    // getal --> tekenreeks
    S=""+i;
    affiche(S);
    S=""+l;
    affiche(S);
    S=""+f;
    affiche(S);
    S=""+d;
    affiche(S);

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

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

    // tekenreeks --> long
    long l1;
    l1=Long.parseLong("100");
    affiche(""+l1);
    try{
      l1=Long.parseLong("10.675");
      affiche(""+l1);
    } catch (Exception e){
      affiche("Erreur "+e);
    }
    
    // tekenreeks --> 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);
    }

    // tekenreeks --> 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);
    }

}// einde main

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

De verkregen resultaten zijn als volgt:

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. Gegevenstabellen

Een Java-array is een object waarmee gegevens van hetzelfde type onder één identificatie kunnen worden gebundeld. De declaratie ervan is als volgt:

Type Array[] = new Type[n] of Type[] Array = new Type[n]

Beide syntaxisvormen zijn geldig. n is het aantal gegevens dat de array kan bevatten. De syntaxis Array[i] verwijst naar het gegeven met nummer i, waarbij i tot het interval [0,n-1] behoort. Elke verwijzing naar het gegevenselement Tableau[i] waarbij i niet tot het interval [0,n-1] behoort, zal een uitzondering veroorzaken.

Een tweedimensionale array kan als volgt worden gedeclareerd:

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

De syntaxis Tableau[i] verwijst naar het gegeven nr. i van Tableau, waarbij i tot het interval [0,n-1] behoort. Tabel[i] is zelf een tabel: Tabel[i][j] verwijst naar gegevensnummer j van Tabel[i], waarbij j tot het interval [0,p-1] behoort. Elke verwijzing naar een gegeven van Tableau met onjuiste indexen leidt tot een fatale fout.

Hier volgt een voorbeeld:


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]);
  }
}

en de resultaten van de uitvoering:

2
0.33

Een array is een object met het attribuut length: dit is de grootte van de array.

2.3. De basisinstructies van Java

Er wordt onderscheid gemaakt tussen

  • de basisinstructies die door de computer worden uitgevoerd.
  • de instructies die de uitvoering van het programma sturen.

De basisinstructies worden duidelijk wanneer men de structuur van een microcomputer en zijn randapparatuur bekijkt.

Image

  1. het uitlezen van informatie van het toetsenbord

  2. verwerking van informatie

  3. informatie op het scherm weergeven

  4. informatie uit een schijfbestand lezen

  5. informatie naar een bestand op de harde schijf schrijven

2.3.1. Schrijven naar het scherm

De syntaxis van de instructie om naar het scherm te schrijven is als volgt:

System.out.println(uitdrukking) of System.err.println(uitdrukking)

waarbij expression elk gegevenstype is dat kan worden omgezet in een tekenreeks om op het scherm te worden weergegeven. In het vorige voorbeeld hebben we twee schrijfinstructies gezien:

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

System.out schrijft naar een tekstbestand, dat standaard het scherm is. Hetzelfde geldt voor System.err. Deze bestanden hebben respectievelijk nummer 1 en 2 (of descripteur). De invoerstroom van het toetsenbord (System.in) wordt eveneens beschouwd als een tekstbestand, met descriptor 0. Zowel DOS als Unix ondersteunen het doorpijpen (piping) van commando’s:

    commande1 | commande2

Alles wat commande1 schrijft met System.out wordt doorgestuurd naar de invoer System.in van commande2. Met andere woorden: commande2 leest via System.in de gegevens die door commande2 via System.out zijn gegenereerd en die dus niet meer op het scherm worden weergegeven. Dit systeem wordt veel gebruikt onder Unix. In deze pijpconstructie wordt de stroom System.err echter niet omgeleid: deze schrijft naar het scherm. Daarom wordt deze gebruikt om foutmeldingen weer te geven (vandaar de naam err): zo is men er zeker van dat bij het doorpijpen van commando’s de foutmeldingen nog steeds op het scherm worden weergegeven. Men zal er dus een gewoonte van maken om foutmeldingen op het scherm weer te geven met de stream System.err in plaats van met de stream System.out.

2.3.2. Lezen van gegevens die via het toetsenbord zijn ingevoerd

De gegevensstroom afkomstig van het toetsenbord wordt aangeduid door het object System.in van het type InputStream. Met dit type objecten kunnen gegevens teken voor teken worden gelezen. Het is vervolgens aan de programmeur om in deze tekenstroom de informatie te vinden die voor hem van belang is. Met het type InputStream is het niet mogelijk om in één keer een tekstregel te lezen. Het type BufferedReader maakt dit wel mogelijk met de methode readLine.

Om tekstregels te kunnen lezen die via het toetsenbord zijn ingevoerd, maken we op basis van de invoerstroom System.in van het type InputStream een andere invoerstroom aan, ditmaal van het type BufferedReader:

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

We zullen hier niet ingaan op de details van deze instructie, waarbij het concept van objectconstructies een rol speelt. We gebruiken deze instructie gewoon zoals ze is.

Het aanmaken van een stream kan mislukken: er wordt dan een fatale fout, in Java een ‘exception’ genoemd, gegenereerd. Telkens wanneer een methode een exception kan genereren, eist de Java-compiler dat deze door de programmeur wordt afgehandeld. Om de vorige invoerstream aan te maken, moet dus in werkelijkheid het volgende worden geschreven:


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

Ook hier zullen we niet ingaan op de afhandeling van uitzonderingen. Zodra de voorgaande stroom IN is opgebouwd, kan een tekstregel worden gelezen met de instructie:

    String ligne;
    ligne=IN.readLine();

De via het toetsenbord ingevoerde regel wordt opgeslagen in de variabele ligne en kan vervolgens door het programma worden verwerkt.

2.3.3. Voorbeeld van invoer en uitvoer

Hier volgt een programma ter illustratie van invoer- en uitvoerbewerkingen via toetsenbord en scherm:


import java.io.*;        // vereist voor het gebruik van I/O-streams

public class io1{
  
  
  public static void main (String[] arg){
    
    // schrijven naar de stream System.out
    Object obj=new Object();
    System.out.println(""+obj);
    System.out.println(obj.getClass().getName());
    
    // schrijven naar de stream System.err
    int i=10;
    System.err.println("i="+i);
    
    // een via het toetsenbord ingevoerde regel lezen
    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);
    }
  }//einde handmatige invoer

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

}//einde klasse

en de resultaten van de uitvoering:

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à

De instructies

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

zijn bedoeld om aan te tonen dat elk object kan worden weergegeven. We zullen hier niet ingaan op de betekenis van wat er wordt weergegeven. We hebben ook de weergave van de waarde van een object in het blok:

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

De variabele e is een object van het type Exception dat hier wordt weergegeven met de aanroep affiche(e). We waren deze weergave van de waarde van een uitzondering al tegengekomen in het hierboven besproken conversieprogramma, zonder er verder op in te gaan.

2.3.4. De waarde van een uitdrukking toewijzen aan een variabele

We richten ons hier op de bewerking variable=expression;

De uitdrukking kan van het volgende type zijn: rekenkundig, relationeel, booleaans, tekenreeks

2.3.4.1. Interpretatie van de toewijzingsbewerking

De bewerking variable=expression; is zelf een uitdrukking waarvan de evaluatie als volgt verloopt:

  • De rechterkant van de toewijzing wordt geëvalueerd: het resultaat is een waarde V.
  • De waarde V wordt toegewezen aan de variabele
  • de waarde V is tevens de waarde van de toewijzing, ditmaal beschouwd als een uitdrukking.

Zo is de bewerking V1=V2=uitdrukking geldig is. Vanwege de prioriteit wordt de operator = die het verst rechts staat, als eerste geëvalueerd. We krijgen dus V1=(V2=uitdrukking). De uitdrukking V2=uitdrukking wordt berekend en heeft als waarde V. De evaluatie van deze uitdrukking heeft ertoe geleid dat V is toegewezen aan V2. De volgende =-operator wordt vervolgens geëvalueerd in de vorm V1=V. De waarde van deze uitdrukking is nog steeds V. De evaluatie ervan leidt tot de toewijzing van V aan V1. De bewerking V1=V2=uitdrukking is een uitdrukking waarvan de evaluatie

1: ervoor zorgt dat de waarde van expression wordt toegewezen aan de variabelen V1 en V2

2: de waarde van expression als resultaat oplevert.

Dit kan worden veralgemeend naar een uitdrukking van het type: V1=V2=....=Vn=uitdrukking

2.3.4.2. Rekenkundige uitdrukking

De operatoren van rekenuitdrukkingen zijn de volgende:

+: optelling

  • : aftrekking

*: vermenigvuldiging

/ : deling: het resultaat is het exacte quotiënt als ten minste één van de operanden een reëel getal is. Als beide operanden gehele getallen zijn, is het resultaat het gehele quotiënt. Dus 5/2 -> 2 en 5,0/2 -> 2,5.

% : deling: het resultaat is de rest, ongeacht de aard van de operanden, waarbij het quotiënt een geheel getal is. Dit is dus de modulo-bewerking.

Er bestaan diverse wiskundige functies:

double sqrt(double x)
vierkantswortel
double cos(double x)
Cosinus
double sin(double x)
Sinus
double tan(double x)
Tangens
double pow(double x, double y)
x tot de macht y (x > 0)
double exp(double x)
Exponentieel
double log(double x)
Natuurlogaritme
double abs(double x)
absolute waarde

enz...

Al deze functies zijn gedefinieerd in een Java-klasse genaamd Math. Wanneer je ze gebruikt, moet je ze vooraf laten gaan door de naam van de klasse waarin ze zijn gedefinieerd. Je schrijft dus:

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

De definitie van de klasse Math is als volgt:


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

        // Methoden
    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. Prioriteiten bij het evalueren van rekenkundige uitdrukkingen

De prioriteit van de operatoren bij het evalueren van een rekenuitdrukking is als volgt (van hoogste naar laagste prioriteit):

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

Rekenkundige operatoren binnen hetzelfde blok [ ] hebben dezelfde prioriteit.

2.3.4.4. Relationele uitdrukkingen

De operatoren zijn: <, <=, ==, !=, >, >=

prioriteitsvolgorde

>, >=, <, <=

==, !=

Het resultaat van een relationele uitdrukking is de booleaanse waarde false als de uitdrukking onwaar is, true anders.

Voorbeeld:

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

Vergelijking van twee tekens

Stel dat we twee tekens hebben: C1 en C2. Deze kunnen worden vergeleken met de operatoren

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

Dan worden hun codes ASCII, die getallen zijn, met elkaar vergeleken. We herinneren eraan dat volgens de volgorde ASCII de volgende relaties gelden:

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

Vergelijking van twee tekenreeksen

Ze worden teken voor teken vergeleken. De eerste ongelijkheid die tussen twee tekens wordt aangetroffen, leidt tot een ongelijkheid in dezelfde richting voor de tekenreeksen.

Voorbeelden:

Stel dat we de tekenreeksen "Kat" en "Hond" willen vergelijken

Op basis van deze laatste ongelijkheid kunnen we stellen dat "Kat" < "Hond".

Image

Stel dat we de tekenreeksen "Kat" en "Kitten" vergelijken. Er is telkens gelijkheid totdat de tekenreeks "Kat" is uitgeput. In dit geval wordt de uitgeputte tekenreeks als de "kleinste" aangemerkt. We hebben dus de relatie

"Kat" < "Kitten".

Vergelijkingsfuncties voor twee tekenreeksen

De relationele operatoren <, <=, ==, !=, >, >= kunnen hier niet worden gebruikt. Er moet gebruik worden gemaakt van methoden uit de klasse String:

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

Hierboven krijgt de variabele i de waarde:

0: als beide tekenreeksen gelijk zijn

1: als tekenreeks nr. 1 > tekenreeks nr. 2

-1: als tekenreeks nr. 1 kleiner is dan tekenreeks nr. 2

De variabele egal krijgt de waarde true als beide tekenreeksen gelijk zijn.

2.3.4.5. Booleaanse uitdrukkingen

De operatoren zijn & (and) ||(or) en ! (not). Het resultaat van een booleaanse uitdrukking is een booleaanse waarde.

prioriteitsvolgorde ! , &&, ||

voorbeeld:

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

Relationele operatoren hebben voorrang op de operatoren && en ||.

2.3.4.6. Bitverwerking

De operatoren

Stel dat i en j twee gehele getallen zijn.

i<<n
verschuift i n bits naar links. De nieuwe bits zijn nullen.
i>>n
verschuift i n bits naar rechts. Als i een getal met teken is (signed char, int, long), blijft het tekenbit behouden.
i & j
voert de bit-voor-bit logische OR-bewerking uit tussen i en j.
i | j
voert de bit-voor-bit logische OR-bewerking uit tussen i en j.
~i
maakt i complementair tot 1
i^j
voert de OU EXCLUSIF uit op i en j

Ofwel

    int i=0x123F, k=0xF123;
    unsigned j=0xF123;
bewerking
waarde
i<<4
0x23F0
i>>4
0x0123 het tekenbit blijft behouden.
k>>4
0xFF12 het tekenbit blijft behouden.
i&j
0x1023
i|j
0xF33F
~i
0xEDC0

2.3.4.7. Combinatie van operatoren

a=a+b kan worden geschreven als a+=b

a=a-b kan worden geschreven als a-=b

Hetzelfde geldt voor de operatoren /, %, *, <<, >>, &, |, ^

Zo kan a=a+2; worden geschreven als a+=2;

2.3.4.8. Incrementatie- en decrementie-operatoren

De notatie variable++ betekent variable=variable+1 of ook variable+=1

De notatie variable-- betekent variable=variable-1 of ook variable-=1.

2.3.4.9. De operator ?

De uitdrukking expr_cond ? expr1:expr2 wordt als volgt geëvalueerd:

1: de uitdrukking expr_cond wordt geëvalueerd. Dit is een voorwaardelijke uitdrukking met de waarde waar of onwaar

2: Als deze waar is, is de waarde van de uitdrukking die van expr1. expr2 wordt niet geëvalueerd.

3: Als deze onwaar is, gebeurt het tegenovergestelde: de waarde van de uitdrukking is die van expr2. expr1 wordt niet berekend.

Voorbeeld

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

wijst aan de variabele i toe:

j+1 als j>4, anders j-1

Dit is hetzelfde als if(j>4) i=j+1; else i=j-1; schrijven, maar het is beknopter.

2.3.4.10. Algemene prioriteit van operatoren

() [] functie
gd
! ~ ++ --
dg
new (type) cast-operatoren
dg
* / %
gd
+ -
gd
<< >>
gd
< <= > >= instanceof
gd
== !=
gd
&
gd
^
gd
|
gd
&&
gd
||
gd
? :
dg
= += -= enz. .
dg

gd: geeft aan dat bij gelijke prioriteit de volgorde van links naar rechts wordt gevolgd. Dit betekent dat wanneer er in een uitdrukking operatoren met dezelfde prioriteit voorkomen, de operator die zich het meest links in de uitdrukking bevindt, als eerste wordt geëvalueerd. dg duidt op een volgorde van rechts naar links.

2.3.4.11. Typeomzettingen

Het is mogelijk om in een uitdrukking de codering van een waarde tijdelijk te wijzigen. Dit wordt het wijzigen van het type van een waarde genoemd, of in het Engels ‘type casting’. De syntaxis voor het wijzigen van het type van een waarde in een uitdrukking is als volgt: (type) waarde. De waarde krijgt dan het aangegeven type. Dit leidt tot een wijziging in de codering van de waarde.

Voorbeeld:

int i, j;
float isurj;
isurj= (float)i/j;   // prioriteit van () boven /

Hier is het noodzakelijk om het type van i of j te wijzigen in ‘reëel’, anders levert de deling een geheel getal op in plaats van een reëel getal.

i is een exact gecodeerde waarde van 2 bytes

(float) i is dezelfde waarde, bij benadering gecodeerd als een reëel getal over 4 bytes

Er vindt dus een transcodering plaats van de waarde van i. Deze transcodering vindt alleen plaats tijdens de berekening; de variabele i behoudt altijd het type int.

2.4. Instructies voor het toezicht op het verloop van het programma

2.4.1. Stoppen

Met de methode exit, gedefinieerd in de klasse System, kunt u de uitvoering van een programma stoppen.

syntaxis : void exit(int status)

actie: beëindigt het lopende proces en geeft de waarde status terug aan het bovenliggende proces

exit zorgt ervoor dat het lopende proces wordt beëindigd en geeft de controle terug aan het aanroepende proces. De waarde van status kan door dit proces worden gebruikt. Onder DOS wordt deze variabele status teruggegeven aan DOS in de systeemvariabele ERRORLEVEL, waarvan de waarde in een batchbestand kan worden gecontroleerd. Onder Unix is het de variabele $? die de waarde van status ophaalt als de command-interpreter de Bourne Shell (/bin/sh) is.

Voorbeeld:

    System.exit(0);

om het programma te beëindigen met een statuswaarde van 0.

2.4.2. Eenvoudige keuzestructuur


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

opmerkingen:

  • de voorwaarde staat tussen haakjes.
  • Elke actie wordt afgesloten met een puntkomma.
  • De accolades worden niet afgesloten met een puntkomma.
  • accolades zijn alleen nodig als er meer dan één actie is.
  • De else-clausule mag ontbreken.
  • Er is geen 'then'.

Het algoritmische equivalent van deze structuur is de if-then-else-structuur:

si condition
  alors actions_condition_vraie
  sinon actions_conditions_fausse
finsi

voorbeeld


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

Keuzestructuren kunnen in elkaar worden genest:

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

Soms doet zich het volgende probleem voor:


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

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

In het vorige voorbeeld: op welke if verwijst de else? De regel is dat een else altijd verwijst naar de dichtstbijzijnde if: in dit voorbeeld is dat if(n>6). Laten we nog een voorbeeld bekijken:


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

   if(n>1)
     if(n>6)   System.out.println(">6");
     else;            // else van if(n>6): niets te doen 
   else System.out.println("<=1");    // else van if(n>1) 
}

Hier wilden we een else aan if(n>1) toevoegen en geen else aan if(n>6). Vanwege de vorige opmerking zijn we genoodzaakt een ‘else’ toe te voegen voor if(n>6), waarin geen instructie staat.

2.4.3. Case-structuur

De syntaxis is als volgt:

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

opmerkingen

  • De waarde van de controle-uitdrukking mag alleen een geheel getal of een teken zijn.
  • De controle-uitdrukking staat tussen haakjes.
  • De clausule default mag ontbreken.
  • De waarden vi zijn mogelijke waarden van de uitdrukking. Als de uitdrukking de waarde vi heeft, worden de acties achter de case-clausule vi uitgevoerd.
  • De instructie break verlaat de case-structuur. Als deze ontbreekt aan het einde van het instructieblok met de waarde vi, wordt de uitvoering voortgezet met de instructies van de waarde vi+1.

Voorbeeld

In algoritmiek

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. Herhalingsstructuur

2.4.4.1. Aantal herhalingen bekend

Syntaxis


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

Opmerkingen

  • De 3 argumenten van for staan tussen haakjes.
  • De 3 argumenten van for worden gescheiden door puntkomma's.
  • Elke actie van for wordt afgesloten met een puntkomma.
  • De accolades zijn alleen nodig als er meer dan één actie is.
  • De accolades worden niet gevolgd door een puntkomma.

Het algoritmische equivalent is de structuur pour:

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

wat kan worden vertaald naar een structuur tantque:

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

2.4.4.2. Aantal herhalingen onbekend

Er bestaan in Java talrijke structuren voor dit geval.

While-structuur


    while(condition){
          actions;
        } 

De lus wordt herhaald zolang aan de voorwaarde wordt voldaan. Het kan zijn dat de lus nooit wordt uitgevoerd.

opmerkingen:

  • de voorwaarde staat tussen haakjes.
  • Elke actie wordt afgesloten met een puntkomma.
  • De accolades zijn alleen nodig als er meer dan één actie is.
  • De accolades worden niet gevolgd door een puntkomma.

De bijbehorende algoritmische structuur is de 'zolang'-structuur:

tantque condition
        actions
fintantque

Herhaalstructuur (do while)

De syntaxis is als volgt:


    do{
       instructions;
    }while(condition); 

De lus wordt herhaald totdat de voorwaarde onwaar wordt of zolang de voorwaarde waar is. Hier wordt de lus minstens één keer doorlopen.

opmerkingen

  • De voorwaarde staat tussen haakjes.
  • Elke actie wordt afgesloten met een puntkomma.
  • De accolades zijn alleen nodig als er meer dan één actie is.
  • De accolades worden niet gevolgd door een puntkomma.

De bijbehorende algoritmische structuur is de structuur ‘herhaal … tot’:

répéter
    actions
jusqu'à condition

Structuur voor 'for'

De syntaxis is als volgt:


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

De lus wordt herhaald zolang de voorwaarde waar is (deze wordt voor elke lusronde geëvalueerd). Instructions_départ worden uitgevoerd voordat de lus voor de eerste keer wordt gestart. Instructions_fin_boucle worden na elke lusronde uitgevoerd.

opmerkingen

  • De 3 argumenten van for staan tussen haakjes.
  • De 3 argumenten van for worden gescheiden door puntkomma's.
  • Elke actie in de for-lus wordt afgesloten met een puntkomma.
  • De accolades zijn alleen nodig als er meer dan één actie is.
  • De accolades worden niet gevolgd door een puntkomma.
  • De verschillende instructies in instructions_depart en instructions_fin_boucle worden gescheiden door komma's.

De bijbehorende algoritmische structuur is als volgt:

instructions_départ
tantque condition
        actions
        instructions_fin_boucle
fintantque

Voorbeelden

De volgende programma's berekenen allemaal de som van de eerste n gehele getallen.


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);

Instructies voor het beheer van de lus

break
verlaat de for-, while- of do...while-lus.
continue
gaat door naar de volgende iteratie van de for-, while- en do ... while-lussen

2.5. De structuur van een Java-programma

Een Java-programma dat geen door de gebruiker gedefinieerde klassen of andere functies dan de hoofdfunctie main gebruikt, kan de volgende structuur hebben:


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

De functie main, ook wel methode genoemd, wordt als eerste uitgevoerd bij het uitvoeren van een Java-programma. Deze moet verplicht de volgende handtekening hebben:


    public static void main(String arg[]){

of


    public static void main(String[] arg){

De naam van het argument arg kan willekeurig zijn. Het is een array van tekenreeksen die de argumenten van de opdrachtregel vertegenwoordigen. We komen hier later op terug.

Als we functies gebruiken die uitzonderingen kunnen genereren die we niet gedetailleerd willen afhandelen, kunnen we de programmacode omringen met een try/catch-clausule:


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

Aan het begin van de broncode en vóór de definitie van de klasse staan doorgaans instructies voor het importeren van klassen. Bijvoorbeeld:


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

Laten we een voorbeeld nemen. Stel dat we de volgende schrijfinstructie hebben:

System.out.println("java");

die java op het scherm schrijft. Deze eenvoudige instructie bevat veel informatie:

  • System is een klasse met de volledige naam java.lang.System
  • out is een eigenschap van deze klasse van het type java.io.PrintStream, een andere klasse
  • println is een methode van de klasse java.io.PrintStream.

We zullen deze uitleg niet onnodig ingewikkeld maken, aangezien ze te vroeg komt en kennis vereist van het begrip ‘klasse’, dat nog niet aan bod is gekomen. Een klasse kan worden vergeleken met een hulpbron. In dit geval heeft de compiler toegang nodig tot de twee klassen java.lang.System en java.io.PrintStream. De honderden klassen van Java zijn verdeeld over archieven die ook wel pakketten (packages) worden genoemd. De instructies import aan het begin van het programma dienen om de compiler aan te geven welke externe klassen het programma nodig heeft (de klassen die worden gebruikt maar niet zijn gedefinieerd in het bronbestand dat zal worden gecompileerd). In ons voorbeeld heeft ons programma dus de klassen java.lang.System en java.io.PrintStream nodig. Dit geven we aan met de instructie import. We zouden aan het begin van het programma het volgende kunnen schrijven:

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

Aangezien een Java-programma doorgaans tientallen externe klassen gebruikt, zou het lastig zijn om alle benodigde import-functies te schrijven. De klassen zijn gegroepeerd in pakketten en men kan dan het volledige pakket importeren. Om de pakketten java.lang en java.io te importeren, schrijft men dus:

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

Het pakket java.lang bevat alle basisklassen van Java en wordt automatisch door de compiler geïmporteerd. Uiteindelijk schrijf je dus alleen:

import java.io.*;

2.6. Uitzonderingsafhandeling

Veel Java-functies kunnen uitzonderingen, oftewel fouten, genereren. We zijn al eens zo’n functie tegengekomen, namelijk de functie readLine:


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

Wanneer een functie een uitzondering kan genereren, verplicht de Java-compiler de programmeur om deze af te vangen, met als doel foutbestendigere programma's te verkrijgen: het oncontroleerbaar "crashen" van een applicatie moet altijd worden vermeden. Hier genereert de functie readLine een uitzondering als er niets te lezen is, bijvoorbeeld omdat de invoerstroom is gesloten. Het afhandelen van een uitzondering verloopt volgens het volgende schema:

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

Als de functie geen uitzondering genereert, gaat men door naar de volgende instructie; anders gaat men naar de hoofdtekst van de clausule catch en vervolgens naar de volgende instructie. Let op de volgende punten:

  • e is een object afgeleid van het type Exception. We kunnen specifieker zijn door typen te gebruiken zoals IOException, SecurityException, ArithmeticException, enzovoort: er zijn ongeveer twintig soorten uitzonderingen. Door catch (Exception e) te schrijven, geef je aan dat je alle soorten uitzonderingen wilt afhandelen. Als de code van de clausule try meerdere soorten uitzonderingen kan genereren, wil je misschien specifieker zijn door de uitzondering af te handelen met meerdere clausules 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
  • Aan de clausules try/catch kan een finally-clausule worden toegevoegd:
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

Hier wordt de code van de clausule finally altijd uitgevoerd, ongeacht of er een uitzondering optreedt of niet.

  • De klasse Exception heeft een methode getMessage() die een bericht retourneert met details over de opgetreden fout. Als we dit bericht willen weergeven, schrijven we dus:
catch (Exception ex){
    System.err.println("L'erreur suivante s'est produite : "+ex.getMessage());
    ...
}//catch
  • De klasse Exception heeft een methode toString() die een tekenreeks retourneert waarin het type van de uitzondering en de waarde van de eigenschap Message worden aangegeven. We kunnen dan het volgende schrijven:
catch (Exception ex){
    System.err.println ("L'erreur suivante s'est produite : "+ex.toString());
    ...
}//catch

Men kan ook schrijven:

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

We hebben hier te maken met een bewerking van het type string + Exception, die door de compiler automatisch wordt omgezet in string + Exception.toString() om twee tekenreeksen aan elkaar te koppelen.

Het volgende voorbeeld toont een uitzondering die wordt gegenereerd door het gebruik van een niet-bestaand array-element:

// tabellen

// imports
import java.io.*;

public class tab1{
  public static void main(String[] args){
    // definitie en initialisatie van een array
    int[] tab=new int[] {0,1,2,3};
    int i;
     // weergave van een array met een for-lus
    for (i=0; i<tab.length; i++)
      System.out.println("tab[" + i + "]=" + tab[i]);
    // een uitzondering genereren
      try{
      tab[100]=6;
    }catch (Exception e){
      System.err.println("L'erreur suivante s'est produite : " + e);
    }//try-catch
  }//main
}//klasse

De uitvoering van het programma levert de volgende resultaten op:

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

Hier is nog een voorbeeld waarin de uitzondering wordt afgehandeld die wordt veroorzaakt door het toewijzen van een tekenreeks aan een getal wanneer de tekenreeks geen getal vertegenwoordigt:

// imports
import java.io.*;

public class console1{
  public static void main(String[] args){
      // aanmaken van een invoerstroom
    BufferedReader IN=null;
    try{
        IN=new BufferedReader(new InputStreamReader(System.in));
    }catch(Exception ex){}
     // De naam wordt gevraagd
    System.out.print("Nom : ");
     // antwoord lezen
    String nom=null;
    try{
        nom=IN.readLine();
    }catch(Exception ex){}      
     // leeftijd wordt gevraagd
    int age=0;
    boolean ageOK=false;
    while ( ! ageOK){
       // vraag
      System.out.print("âge : ");
       // antwoord lezen en controleren
      try{
        age=Integer.parseInt(IN.readLine());
        ageOK=true;
      }catch(Exception ex) {
        System.err.println("Age incorrect, recommencez...");
      }//try-catch
    }//while
     // eindweergave
    System.out.println("Vous vous appelez " + nom + " et vous avez " + age + " ans");
  }//Main
}//klasse

Enkele uitvoerresultaten:

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. Een Java-programma compileren en uitvoeren

Compileer en voer vervolgens het volgende programma uit:

// klassen importeren
import java.io.*;

// testklasse
public class coucou{
    // main-functie
  public static void main(String args[]){
      // schermweergave
    System.out.println("coucou");
  }//main
}//klasse

Het bronbestand met de vorige klasse coucou moet verplicht de naam coucou.java hebben:

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

Het compileren en uitvoeren van een Java-programma gebeurt in een venster met de naam DOS. De uitvoerbare bestanden javac.exe (compiler) en java.exe (interpreter) bevinden zich in de map bin van de installatiemap van 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

De compiler javac.exe analyseert het .java-bronbestand en genereert een gecompileerd .class-bestand. Dit bestand kan niet direct door de processor worden uitgevoerd. Hiervoor is een Java-interpreter (java.exe) nodig, die een virtuele machine of JVM (Java Virtual Machine) wordt genoemd. Op basis van de tussencode in het .class-bestand genereert de virtuele machine instructies die specifiek zijn voor de processor van de machine waarop deze wordt uitgevoerd. Er bestaan Java-virtuele machines voor verschillende soorten besturingssystemen (Windows, Unix, Mac OS, ...). Een .class-bestand kan door elk van deze virtuele machines worden uitgevoerd, dus op elk besturingssysteem. Deze systeemoverschrijdende draagbaarheid is een van de belangrijkste troeven van Java.

Laten we het vorige programma compileren:

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

Laten we het gegenereerde bestand .class uitvoeren:

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

Merk op dat in de bovenstaande uitvoeropdracht het achtervoegsel .class van het uit te voeren bestand coucou.class niet is gespecificeerd. Dit is impliciet. Als de map bin van het bestand JDK zich bevindt in de map PATH op de machine DOS, hoeft het volledige pad naar de uitvoerbare bestanden javac.exe en java.exe niet te worden opgegeven. Men schrijft dan gewoon

javac coucou.java
java coucou

2.8. Argumenten van het hoofdprogramma

De hoofdfunctie main accepteert als parameters een array van tekenreeksen: String[]. Deze array bevat de argumenten van de opdrachtregel die wordt gebruikt om de toepassing te starten. Als we het programma P dus starten met de opdracht:

        java P arg0 arg1 … argn

en de functie main als volgt is gedeclareerd:

public static void main(String[] arg);

dan is arg[0]="arg0", arg[1]="arg1" … Hier volgt een voorbeeld:


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]);
  }
}

De verkregen resultaten zijn als volgt:

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

2.9. Parameters doorgeven aan een functie

In de voorgaande voorbeelden zijn alleen Java-programma's getoond met slechts één functie, namelijk de hoofdfunctie main. Het volgende voorbeeld laat zien hoe functies worden gebruikt en hoe informatie tussen functies wordt uitgewisseld. De parameters van een functie worden altijd per waarde doorgegeven: dat wil zeggen dat de waarde van de werkelijke parameter wordt gekopieerd naar de bijbehorende formele parameter.


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);
  }
}

De verkregen resultaten zijn als volgt:

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

De waarden van de effectieve parameters "papa" en 20 zijn overgenomen in de formele parameters S en a. Deze zijn vervolgens gewijzigd. De effectieve parameters zijn ongewijzigd gebleven. Let hierbij goed op het type van de effectieve parameters:

  • S is een objectreferentie naar c.a.d, het adres van een object in het geheugen
  • age is een gehele waarde

2.10. Het voorbeeld ‘belastingen’

We sluiten dit hoofdstuk af met een voorbeeld dat we in dit document nog verschillende keren zullen terugkomen. We willen een programma schrijven waarmee de belasting van een belastingplichtige kan worden berekend. We gaan uit van het vereenvoudigde geval van een belastingplichtige die alleen zijn salaris hoeft aan te geven:

  • we berekenen het aantal aandelen van de werknemer nbParts=nbEnfants/2 +1 als hij ongehuwd is, nbEnfants/2+2 als hij getrouwd is, waarbij nbEnfants het aantal kinderen is.
  • als hij ten minste drie kinderen heeft, krijgt hij een half extra aandeel
  • zijn belastbaar inkomen wordt berekend als R = 0,72 * S, waarbij S zijn jaarsalaris is
  • we berekenen zijn gezinscoëfficiënt QF = R / nbParts
  • zijn belasting I wordt berekend. Laten we de volgende tabel bekijken:
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
127860
0,45
16754,5
151250
0,50
23147,5
172.040
0,55
30710
195.000
0,60
39312
0
0,65
49062

Elke regel heeft 3 velden. Om belasting I te berekenen, zoeken we de eerste regel waar QF <= veld1. Als QF bijvoorbeeld 23000 is, vinden we de regel

    24740        0.15        2072.5

De belasting I is dan gelijk aan 0,15*R - 2072,5*nbParts. Als QF zodanig is dat de relatie QF<=veld1 nooit geldt, dan worden de coëfficiënten van de laatste regel gebruikt. In dit geval:

    0                0.65        49062

wat de belasting I = 0,65*R - 49062*nbParts oplevert.

Het bijbehorende Java-programma is als volgt:


import java.io.*;

public class impots{

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

        // gegevens

        // grenzen van de belastingschijven
        double Limites[]={12620, 13190, 15640, 24740, 31810, 39970, 48360,55790, 92970, 127860, 151250, 172040, 195000, 0};    
        // coëfficiënt toegepast op het aantal aandelen
        double Coeffn[]={0, 631, 1290.5, 2072.5, 3309.5, 4900, 6898.5, 9316.5,12106, 16754.5, 23147.5, 30710, 39312, 49062};

        // het programma

        // aanmaken van de invoerstroom via het toetsenbord
        BufferedReader IN=null;
        try{
            IN=new BufferedReader(new InputStreamReader(System.in));
        }
        catch(Exception e){
            erreur("Création du flux d'entrée", e, 1);
        }

            // de burgerlijke staat wordt opgehaald
        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");

            // aantal kinderen
        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

        // salaris
        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

            // berekening van het aantal aandelen
        double NbParts;
        if(Marie) NbParts=(double)NbEnfants/2+2;
            else NbParts=(double)NbEnfants/2+1;
        if (NbEnfants>=3) NbParts+=0.5;
        
            // belastbaar inkomen
        double Revenu;
        Revenu=0.72*Salaire;

            // gezinsquotiënt
        double QF;
        QF=Revenu/NbParts;
        
            // opzoeken van de belastingschijf die overeenkomt met QF
        int i;
        int NbTranches=Limites.length;
        Limites[NbTranches-1]=QF;
        i=0;
        while(QF>Limites[i]) i++;
            // de belasting
        long impots=(long)(i*0.05*Revenu-Coeffn[i]*NbParts);

        // het resultaat wordt weergegeven
        System.out.println("Impôt à payer : " + impots);
    }// hoofdscherm

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

}// klasse

De verkregen resultaten zijn als volgt:

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