Inleiding Java: antwoorden op sommige oefeningen

2. Basisconstructies

2.1 Rangschikking van accoladen

Accoladen worden steeds op het einde van een regel geopend. De overeenkomstige accolade om het blok af te sluiten, is het eerste (meestal enige) teken van haar regel en bevindt zich recht onder de eerste letter van de regel waarop de accolade geopend werd.

Alle regels binnen het blok (tussen het paar accoladen) bevinden zich minstens twee plaatsen verder naar rechts.

Bovenstaande regels zijn niet verplicht. Ze worden niet door de Java-compiler afgedwongen. We geven ze slechts mee als een goede raad om je programma's overzichtelijk te houden.

2.2 Resultaat van toekenningen

De uiteindelijke waarde van y is 2 (na de voorlaatste opdracht is temp gelijk aan 6, en y krijgt als waarde 6 - 4).

2.3 Interpretatie van het plusteken

Het bronbestand PlusTest.java kan de volgende programmaregels bevatten:

class PlusTest {
  public static void main(String[] args) {
    System.out.println("Resultaat: " + (3 + 4));
    System.out.println(("Resultaat: " + 3) + 4);
  }
}

Na compilatie met javac PlusTest.java en starten met java PlusTest verschijnt op het scherm

Resultaat: 7
Resultaat: 34

2.4 Deling met rest en deling als breuk

We lezen de twee gegevens (het deeltal en de deler) telkens maar eenmaal. De overeenkomstige tekststrengen worden allebei twee keer vertaald naar getallen: één keer als geheel getal, en één keer als getal met cijfers na de komma.

import java.io.*;

class Deling {
  public static void main(String[] args) throws IOException {
    BufferedReader toetsenbord;
    toetsenbord = new BufferedReader(new InputStreamReader(System.in));

    System.out.println("deeltal ?");
    String deeltalTekst;
    deeltalTekst = toetsenbord.readLine();
    int deeltalGeheel;
    deeltalGeheel = Integer.parseInt(deeltalTekst);
    double deeltalKomma;
    deeltalKomma = Double.parseDouble(deeltalTekst);

    System.out.println("deler ?");
    String delerTekst;
    delerTekst = toetsenbord.readLine();
    int delerGeheel;
    delerGeheel = Integer.parseInt(delerTekst);
    double delerKomma;
    delerKomma = Double.parseDouble(delerTekst);

    int quotient;
    quotient = deeltalGeheel / delerGeheel;
    System.out.println("quotient = " + quotient);

    int rest;
    rest = deeltalGeheel % delerGeheel;
    System.out.println("rest = " + rest);

    double verhouding;
    verhouding = deeltalKomma / delerKomma;
    System.out.println("verhouding = " + verhouding);
  }
}

Hoe reageert het programma als je negatieve getallen invoert ? En als je deelt door nul ?

3. Controlestructuren

3.1 De inhoud van twee veranderlijken verwisselen

De oorspronkelijke inhoud van y gaat verloren bij de eerste opdracht. Stel dat aanvankelijk x en y respectievelijk de getalwaarden 5 en 6 bevatten. Na afloop van de eerste regel bevatten ze allebei 5, en de tweede regel verandert daar niets meer aan.

3.2 Commentaar

Een voorbeeld waarbij de twee stijlen van commentaar gebruikt worden:

/** De volgende drie programmaregels
 *  verwisselen de inhoud van x en y
 *  door gebruik te maken van een
 *  hulpveranderlijke temp.
 */
temp = x;  // bewaar de oude inhoud van x
x = y;     // vervang x door de inhoud van y
y = temp;  // vervang y door de vorige inhoud van x

3.3 Samengestelde voorwaarde

De volgende uitdrukking drukt de gestelde voorwaarde zo letterlijk mogelijk uit:

(a != 3 && a != 4) || b <= a

Aangezien de logische bewerking EN een hogere prioriteit heeft dan de logische bewerking OF, mogen de haakjes eigenlijk wegvallen.

3.4 Effect van een voorwaardelijke opdracht

Het getal a wordt vervangen door zijn absolute waarde.

3.5 Grootste gemene deler

Het volgende programma is de "droge" oplossing. Je kan binnenin de lus natuurlijk een geschikte drukopdracht toevoegen om de stapsgewijze werking van het algoritme in beeld te brengen.

class Euclides {
  /** Berekent de grootste gemene deler
   *   van twee getallen.
   */
  public static void main(String[] args) {
    int a, b;
    a = 1440;
    b = 777;

    /** Indien de getallen in de verkeerde
     *  volgorde staan, verwisselen we ze
     *  van plaats.
     */
    if (a < b) {
      int temp;
      temp = a;
      a = b;
      b = temp;
    }

    /* Nu komt de lusopdracht. Op het einde
     * testen we of b nog niet nul is, want
     * dan bevat a het antwoord.
     */
    do {
      int rest;
      rest = a % b;
      a = b;
      b = rest;
    }
    while (b > 0);

    // Hiep hiep hoera
    System.out.println("De GGD is " + a);
  }
}

Tracht bovenstaand programma nu aan te passen zodat de gebruiker zelf twee willekeurige positieve getallen als gegevens kan invoeren.

3.6 Faculteit

Onze versie van de methode faculteit maakt gebruik van een for-lusopdracht om de factoren van 1 tot en met n te doorlopen.

import java.io.*;

class Faculteit {
  public static int faculteit(int n) {
    int teller;
    int resultaat;
    resultaat = 1;
    for (teller = 1; teller <= n; teller = teller + 1)
      resultaat = resultaat * teller;
    return resultaat;
  }

  public static void main(String[] args) throws IOException {
    BufferedReader toetsenbord;
    toetsenbord = new BufferedReader(new InputStreamReader(System.in));
    System.out.println("Getal n ?");
    String invoertekst;
    invoertekst = toetsenbord.readLine();
    int getal;
    getal = Integer.parseInt(invoertekst);
    System.out.println(getal + "! = " + faculteit(getal));
  }
}

3.7 Faculteit met recursie

Vervang de methode faculteit van de vorige oplossing bijvoorbeeld door

  public static int faculteit(int n) {
    if (n > 0)
      return n * faculteit(n - 1);
    else
      return 1;
  }

3.8 Fibonaccigetallen

public class Fibonacci {
  /** Het grootste geheel getal dat kan worden
      voorgesteld in een primitieve veranderlijke.
  */
  public static final long maxLong = 0x7FFFFFFFFFFFFFFFL;

  public static void main(String[] args) {
    long eersteGetal = 0, tweedeGetal = 1, teller = 1;
    /** Blijf herhalen zolang eersteGetal + tweedeGetal
        niet te groot wordt. De eigenlijke optelling
        moeten we natuurlijk vermijden want onmogelijk
        - gebruik in plaats daarvan een aftrekking.
    */
    while (maxLong - tweedeGetal >= eersteGetal) {
      long tijdelijk;
      System.out.println(teller++ + ": " + tweedeGetal);
      tijdelijk = tweedeGetal;
      tweedeGetal += eersteGetal;
      eersteGetal = tijdelijk;
    }
    System.out.println(teller + ": " + tweedeGetal);
  }
}

Enkele regels output van bovenstaand programma:

1: 1
2: 1
3: 2
4: 3
5: 5
6: 8
7: 13
8: 21
...
80: 23416728348467685
81: 37889062373143906
82: 61305790721611591
83: 99194853094755497
84: 160500643816367088
85: 259695496911122585
86: 420196140727489673
87: 679891637638612258
88: 1100087778366101931
89: 1779979416004714189
90: 2880067194370816120
91: 4660046610375530309
92: 7540113804746346429

4. Objecten en klassen

4.1 Rechthoek

class Rechthoek {
  int links, boven, rechts, onder;
  Rechthoek(int l, int b, int r, int o) {
    links = l;
    boven = b;
    rechts = r;
    onder = o;
  }
  void printRechterBovenhoek() {
    System.out.println("(" + rechts + ", " + boven + ")");
  }
  int opp() {
    return (rechts - links) * (onder - boven);
  }
}

4.2 Intrest op een spaarrekening

class Bankrekening {
  String naam;
  String adres;
  int rekeningnummer;
  double saldo;

  Bankrekening(String nm, String ad, int nr, double sa) {
    naam = nm;
    adres = ad;
    rekeningnummer = nr;
    saldo = sa;
  }

  void stort(double bedrag) {
    saldo = saldo + bedrag;
  }
  void trekTerug(double bedrag) {
    saldo = saldo - bedrag;
  }
  double geefHuidigeStand() {
    return saldo;
  }
  void schrijfOver(double bedrag, Bankrekening begunstigde) {
    trekTerug(bedrag);
    begunstigde.stort(bedrag);
  }
}

class Spaarrekening extends Bankrekening {
  double rentevoet; // in fracties, dus 10 procent is 0.1

  /** Bedrag van de intrest op 31 december, als
   *  geen verdere verrichtingen meer plaatsvinden.
   */
  double voorlopigeIntrest;

  Spaarrekening(String nm, String ad, int nr, double sa,
    double rv) {
    super(nm, ad, nr, sa);
    rentevoet = rv;
    voorlopigeIntrest = saldo * rentevoet;
  }

  /** Nieuwe versie van "stort". Veronderstelt dat er een
   *  (fictieve) veranderlijke "Datum.jaarfractie" bestaat die aangeeft
   *  welk deel van het jaar er nog rest.
   */
  void stort(double bedrag) {
    saldo = saldo + bedrag;
    voorlopigeIntrest = voorlopigeIntrest + bedrag * rentevoet * Datum.jaarfractie;
  }

  /** Nieuwe versie van "stort". Veronderstelt dat er een
   *  (fictieve) veranderlijke "Datum.jaarfractie" bestaat die aangeeft
   *  welk deel van het jaar er nog rest.
   */
  void trekTerug(double bedrag) {
    saldo = saldo - bedrag;
    voorlopigeIntrest = voorlopigeIntrest - bedrag * rentevoet * Datum.jaarfractie;
  }

  /** Deze methode mag slechts één keer per jaar,
   *  op 31 december, worden uitgevoerd.
   */
  void keerIntrestUit() {
    saldo = saldo + voorlopigeIntrest;
    voorlopigeIntrest = saldo * rentevoet;
  }
}

class Datum {
  static double jaarfractie;
}

class TestSpaarrekening {
  public static void main(String[] args) {
    Spaarrekening sp = new Spaarrekening(
      "Lambik",      // naam
      "Antwerpen",   // adres
      12233,         // rekeningnummer
      0,             // beginbedrag
      0.05);         // rentevoet

    // Stort 1000 op 1 januari
    Datum.jaarfractie = 1.00;
    sp.stort(1000);

    // Stort 1000 op 1 juli
    Datum.jaarfractie = 0.50;
    sp.stort(1000);

    // Trek 1000 terug op 1 oktober
    Datum.jaarfractie = 0.25;
    sp.trekTerug(1000);

    // Stort 5000 op 1 december
    Datum.jaarfractie = 0.0833333;
    sp.stort(5000);

    sp.keerIntrestUit();

    System.out.println("Het eindsaldo bedraagt "
      + sp.geefHuidigeStand());
  }
}

4b. Enkele bijzondere klassen

4b.1 Alfabetisch rangschikken, stap 1

import java.io.*;

class Sorteer {
  public static void main(String[] args) {
    try {
      FileReader r = new FileReader(args[0]);
      BufferedReader b = new BufferedReader(r);

      String[] regel = new String[1000];
      int teller = 0;

      String huidigeRegel = b.readLine();
      while (huidigeRegel != null && teller < regel.length) {
        regel[teller] = huidigeRegel;
        teller++;
        huidigeRegel = b.readLine();
      }
      b.close();
    }
    catch (FileNotFoundException e) {
      System.out.println("Invoerbestand niet gevonden.");
    }
    catch (IOException e) {
      System.out.println("Algemene invoer/uitvoerfout.");
    }
    catch (ArrayIndexOutOfBoundsException e) {
      System.out.println("Geef een bestandsnaam mee als opdrachtregel-parameters.");
    }
  }
}

4b.1 Alfabetisch rangschikken, stap 2

import java.io.*;

class Sorteer {
  public static void main(String[] args) {
    try {
      FileReader r = new FileReader(args[0]);
      BufferedReader b = new BufferedReader(r);

      String[] regel = new String[1000];
      int teller = 0;

      String huidigeRegel = b.readLine();
      while (huidigeRegel != null && teller < regel.length) {
        regel[teller] = huidigeRegel;
        teller++;
        huidigeRegel = b.readLine();
      }
      b.close();

      FileWriter w = new FileWriter(args[1]);
      PrintWriter p = new PrintWriter(w);

      for (int i = 0; i < teller; i++)
        p.println(regel[i]);
      p.close();
    }
    catch (FileNotFoundException e) {
      System.out.println("Invoerbestand niet gevonden.");
    }
    catch (IOException e) {
      System.out.println("Algemene invoer/uitvoerfout.");
    }
    catch (ArrayIndexOutOfBoundsException e) {
      System.out.println("Geef twee bestandsnamen mee als opdrachtregel-parameters.");
    }
  }
}

4b.1 Alfabetisch rangschikken, afwerking

import java.io.*;

class Sorteer {
  public static void main(String[] args) {
    try {
      FileReader r = new FileReader(args[0]);
      BufferedReader b = new BufferedReader(r);

      String[] regel = new String[1000];
      int teller = 0;

      String huidigeRegel = b.readLine();
      while (huidigeRegel != null && teller < regel.length) {
        regel[teller] = huidigeRegel;
        teller++;
        huidigeRegel = b.readLine();
      }
      b.close();

      /* Sorteer volgens BubbleSort: telkens twee
         opeenvolgende regels alfabetisch vergelijken
         en indien nodig verwisselen */
      int herhaling;
      int regelTeller;
      for (herhaling = 0; herhaling < 999; herhaling++)
        for (regelTeller = 0; regelTeller < teller - 1; regelTeller++)
          if (regel[regelTeller].compareTo(regel[regelTeller + 1]) > 0) {
            String temp = regel[regelTeller];
            regel[regelTeller] = regel[regelTeller + 1];
            regel[regelTeller + 1] = temp;
          }

      FileWriter w = new FileWriter(args[1]);
      PrintWriter p = new PrintWriter(w);

      for (int i = 0; i < teller; i++)
        p.println(regel[i]);
      p.close();
    }
    catch (FileNotFoundException e) {
      System.out.println("Invoerbestand niet gevonden.");
    }
    catch (IOException e) {
      System.out.println("Algemene invoer/uitvoerfout.");
    }
    catch (ArrayIndexOutOfBoundsException e) {
      System.out.println("Geef twee bestandsnamen mee als opdrachtregel-parameters.");
    }
  }
}

8. Visueel programmeren met componenten

8.1 Flexibele convertor (duim/centimeter)

import java.awt.*;
import java.awt.event.*;
import javax.swing.*;

public class Convertor extends JPanel implements java.io.Serializable, ActionListener {
  JButton btnConverteer = new JButton("Converteer");
  JLabel lblOorsprong = new JLabel("Euro");
  JLabel lblDoel = new JLabel("Frank");
  JTextField txtOorsprong = new JTextField(15);
  JTextField txtDoel = new JTextField(15);

  public Convertor() {
    setLayout(new GridLayout(3, 2, 10, 10));
    add(txtOorsprong);
    add(lblOorsprong);
    add(btnConverteer);
    btnConverteer.addActionListener(this);
    add(new JPanel());  // opvulsel
    add(txtDoel);
    add(lblDoel);
  }

  public void actionPerformed(ActionEvent e) {
    if (e.getSource().equals(btnConverteer)) {
      try {
        double bedragOorsprong = Double.parseDouble(txtOorsprong.getText());
        double bedragDoel = bedragOorsprong * conversiefactor;
        txtDoel.setText("" + bedragDoel);
      }
      catch (NumberFormatException exc) {
        txtDoel.setText("Error");
      }
    }
  }

  public void setOorsprong(String naam) {
    lblOorsprong.setText(naam);
  }
  public String getOorsprong() {
    return lblOorsprong.getText();
  }

  public void setDoel(String naam) {
    lblDoel.setText(naam);
  }
  public String getDoel() {
    return lblDoel.getText();
  }

  public void setKnoptekst(String tekst) {
    btnConverteer.setText(tekst);
  }
  public String getKnoptekst() {
    return btnConverteer.getText();
  }

  private double conversiefactor = 40.3399;
  public void setFactor(double f) {
    conversiefactor = f;
  }
  public double getFactor() {
    return conversiefactor;
  }
}

Valid HTML 4.0! Valid CSS!