-
Notifications
You must be signed in to change notification settings - Fork 4
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
60 changed files
with
4,645 additions
and
2 deletions.
There are no files selected for viewing
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,5 @@ | ||
# Opgaven week 3 | ||
|
||
- Opgave 1: [Grote getallen](../exercises/grote_getallen.md) | ||
- Opgave 2: [De klasse `OptionalInt`](../problems/opgave-OptionalInt.md) | ||
- Opgave 3: [De klasse `LocalDate`](../problems/opgave-LocalDate.md) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,39 @@ | ||
# Grote getallen | ||
|
||
## Machtsverheffing | ||
|
||
Schrijf een recursieve methode `pow` die een `double` `x` en een `int` `n` accepteert en $x^n$ teruggeeft. | ||
|
||
```{hint} | ||
Een recursieve definitie van deze bewerking is $x^n = x \cdot x^{n-1}$. | ||
Onthoud ook dat alles wat tot de macht nul verheven is, 1 is. | ||
``` | ||
|
||
Optionele uitdaging: je kunt deze methode efficiënter maken, als $n$ even is, door $x^n = \left( x^{n/2} \right)^2$ te gebruiken. | ||
|
||
## Faculteit | ||
|
||
De faculteit van een getal is het product van de getallen 1 tot en met $n$. De recursieve uitwerking is als volgt | ||
|
||
```java | ||
public static int factorial(int n) { | ||
if (n == 1) { | ||
return 1; | ||
|
||
return n * factorial(n - 1); | ||
} | ||
``` | ||
|
||
1. Maak een programma `Big.java` en herschrijf daar de recursieve versie van `factorial` naar een *iteratieve* versie met behulp van een `for`-lus. | ||
|
||
2. Houd een tabel bij van de gehele getallen van 0 tot 30 samen met hun faculteit. Op een bepaald punt rond 15 zul je waarschijnlijk zien dat de antwoorden niet meer juist zijn. Waarom niet? | ||
|
||
3. Converteer `factorial` zodat het de berekening uitvoert met het type `BigInteger` en een `BigInteger` als resultaat teruggeeft. Je kan parameter parameter type laten staan, het zal nog steeds een geheel getal (`int`) zijn. | ||
|
||
4. Probeer de tabel opnieuw bij te houden met jouw aangepaste `factorial` methode. Is het correct tot 30? Hoe hoog kun je het laten gaan? | ||
|
||
5. Optioneel: bij de vorige opgave zal je tegen hetzelfde probleem aanlopen zodra de getallen groter worden. Pas jouw recursieve methode `pow` aan zodat het ook het type `BigInteger` gebruikt. | ||
|
||
```{note} | ||
De opgave Machtsverheffing kan je in het boek vinden in [hoofdstuk 9](https://books.trinket.io/thinkjava2/chapter6.html), de opgave Faculteit in [hoofdstuk 8](https://books.trinket.io/thinkjava2/chapter6.html). | ||
``` |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,163 @@ | ||
# Practicum: Objecten maken van klasse Point | ||
|
||
Dit practicum is een kennismaking met het maken van en werken met objecten in Java. | ||
|
||
## Klasse `Point` | ||
|
||
De klasse `Point` representeert een punt in een twee-dimensionaal vlak. Een object maken van een klasse wordt in de regel gedaan met het *keyword* *new*: | ||
|
||
`<niet-primitief-type> *variabeleNaam* = new <klasse>([argumenten]);` | ||
|
||
Bijvoorbeeld het maken van een object van klasse `Point`: | ||
De onderstaande code maakt bijvoorbeeld een instantie van klasse `Point`. De *referentie* naar dit object wordt opgeslagen in de variabele `point1` Een instantie (Engels: *instance*) is een object. | ||
|
||
```{code-block} java | ||
Point point1 = new Point(); | ||
System.out.println(point1.x + "," + point1.y); | ||
``` | ||
|
||
Deze klasse is standaard in Java aanwezig, maar om hem beschikbaar te maken dient deze geïmporteerd te worden met de onderstaande regel: | ||
|
||
```{code-block} java | ||
import java.awt.Point; | ||
``` | ||
|
||
De import staat in de code *boven* de klasse-definitie maar *onder* de regel die begint met `package` (deze regel is niet altijd aanwezig, in dat geval staan de imports helemaal aan het begin). Een geavanceerde editor zoals IntelliJ zet de imports vaak automatisch in de code. | ||
|
||
Maak een klasse `PracticumPoint` met daarin een main-methode. Neem bovenstaande code over in main. Zorg ook voor de import van `Point`, door de import-regel bovenin `PracticumPoint.java` te plaatsen. Wat zijn de coördinaten van het punt? | ||
|
||
De coördinaten van `point1` opvragen of veranderen kunnen we doen door de properties `x` en `y` rechtstreeks te benaderen: | ||
|
||
```{code-block} java | ||
point1.x = 5; | ||
point1.y = 3; | ||
System.out.println(point1.x + "," + point1.y); // 5,3 | ||
``` | ||
|
||
Voeg bovenstaande regels code toe en test het programma. | ||
|
||
Voeg code toe om de `x`-coördinaat te verhogen met 10. Print vervolgens de coördinaten op het scherm. | ||
|
||
```{code-block} java | ||
point1.x = point1.x + 10; | ||
System.out.println(point1.x + "," + point1.y); // 5,3 | ||
``` | ||
|
||
De variabelen `x` en `y` zijn *properties* van *instanties* van `Point`. Properties van een object worden ook wel *instantie-variabelen* genoemd. Het rechtstreeks benaderen van instantie-variabelen van een object, buiten het object, is ongebruikelijk. Hoewel het technisch gezien kan, is binnen Java de gewoonte (conventies) om instantie-variabelen altijd te lezen of veranderen door middel van aanroep van methodes, zogenaamde `getters` en `setters`. | ||
|
||
In de meeste klassen is het rechtstreeks benaderen van instantie-variabelen zelfs onmogelijk gemaakt. De voornaamste reden dat dit bij `Point` niet het geval is, is dat deze klasse al onderdeel is van de allereerste versie van Java, toen men wat losser omging met properties. | ||
|
||
## Methodes | ||
|
||
*Methodes* zijn vergelijkbaar met *functies* maar ze zijn onderdeel van een bepaalde klasse. Ze zijn beschikbaar via een *klasse* of *object*. Met de onderstaande code kun je bijvoorbeeld de *property* `x` van `point1` opvragen (dat is zo'n `getter` waar we het eerder over hadden): | ||
|
||
`System.out.println( point1.getX() );` | ||
|
||
Met de methodes `getX()` en `getY()` worden de coördinaten opgevraagd. Met de methode `setLocation(int x, int y)` worden de coördinaten veranderd. | ||
|
||
Herschrijf de code in je `main` methode zodat de properties `x` en `y` niet meer worden gebruikt. In plaats daarvan maak je gebruik van de bovenstaande methodes. | ||
|
||
## Constructors | ||
|
||
Bij het maken van een instantie met keyword `new` kunnen argumenten worden meegegeven. Soms is dit verplicht, maar in het geval van `Point` niet. Welke argumenten kunnen worden meegegeven wordt gedefinieerd in de constructor. Soms zijn er meerdere constructors gedefinieerd, waarbij meerdere soorten argumenten mogelijk zijn (*constructor overloading*, vergelijkbaar met *method overloading*). | ||
|
||
De klasse Point heeft drie constructors: `Point()`, `Point(int x, int y)` en `Point(Point p)`. Voeg code toe om een tweede instantie van `Point` te maken met de naam `point2`. Geef aan de constructor de coördinaten `(1, 2)` mee, door de argumenten 1,2 tussen haakjes te zetten achter `new Point`. Print de coördinaten op de console om te testen. | ||
|
||
## Documentatie | ||
|
||
Alle met Java meegeleverde klassen zijn uitvoerig gedocumenteerd. Zo is de documentatie van `Point` te vinden via [deze link](https://docs.oracle.com/en/java/javase/11/docs/api/java.desktop/java/awt/Point.html). | ||
|
||
Onder het kopje "Constructors" vind je de *constructors*. Onder "Method Summary" vind je een overzicht van alle methodes (je verwacht het niet). | ||
|
||
![De documentatie op oracle.com](../images/point-documentatie.png) | ||
|
||
Voeg code toe om `point2` 3 plekken naar rechts en 1 naar onder te verplaatsen. Dit kan gerealiseerd worden met een combinatie van `setLocation`, `getX` en `getY`, maar er is ook een methode die dit in één keer kan doen. Zoek in de documentatie naar deze methode en maak daar gebruik van. Print de nieuwe coördinaten. | ||
|
||
## Methode `toString()` | ||
|
||
Elk object heeft de methode `toString()`. Niet elke klasse heeft een specifieke implementatie, maar als dit het geval is dan geeft `toString()` een string terug met daarin de belangrijkste informatie over een object. Als een object op het scherm wordt afgedrukt met `System.out.println()` dan zorgt de JVM er zelf voor dat `toString()` wordt aangeroepen. Dit is ook het geval als een object aan een string wordt "geplakt" met de + operator (*string concatenation). | ||
|
||
Probeer de regels `System.out.println(point2.toString())` en `System.out.println(point2)` uit; kun je het verschil in uitkomsten verklaren? | ||
|
||
## Methodes met objecten | ||
|
||
Je kunt ook objecten meegegeven worden aan methoden; of, om het preciezer te formuleren, je kunt *verwijzingen* naar objecten meegegeven aan methoden. Dit zijn niet-primitieve datatypes. | ||
|
||
Schrijf de volgende methode: | ||
|
||
```{code-block} java | ||
public static boolean isClose(Point p1, Point p2) | ||
``` | ||
|
||
De methode retourneert `true` als de afstand tussen beide punten kleiner is dan 2,5, en `false` als dit niet het geval is. De afstand tussen twee punten wordt berekend met de stelling van Pythagoras: | ||
|
||
$$ | ||
distance = \sqrt{(x_2-x_1)^2 + (y_2-y_1)^2} | ||
$$ | ||
|
||
Je kunt het onderstaande code-blok gebruiken om de methode te testen: | ||
|
||
```{code-block} java | ||
Point point3 = new Point(2,3); | ||
System.out.println(isClose(point3, new Point(3,3))); // true | ||
System.out.println(isClose(point3, new Point(0,2))); // true | ||
System.out.println(isClose(point3, new Point(0,5))); // false | ||
``` | ||
|
||
## Foutje... | ||
|
||
Gegeven de volgende methode: | ||
|
||
```{code-block} java | ||
public static Point between(Point p1, Point p2) { | ||
double betweenX = (p1.getX() + p2.getX()) / 2; | ||
double betweenY = (p1.getY() + p2.getY()) / 2; | ||
p1.setLocation( betweenX, betweenY ); | ||
return p1; | ||
} | ||
``` | ||
|
||
De methode `between` retourneert het punt dat zich precies tussen de punten `p1` en `p2` bevindt. Coördinaten zijn altijd gehele getallen (*integers*). | ||
|
||
Deze test suggereert dat de methode goed werkt: | ||
|
||
```{code-block} java | ||
Point point4 = new Point(5, 3); | ||
Point point5 = new Point(15, 7); | ||
System.out.println(between(point4, point5)); // [x=10,y=5] | ||
``` | ||
|
||
De methode bevat echter een ernstige fout. Welke fout? Hint: Controleer na uitvoeren van de methode niet alleen naar de return-waarde, maar ook naar `point4` en `point5`... | ||
|
||
Verbeter de fout. | ||
|
||
## Nog een foutje.. | ||
|
||
Gegeven de volgende code: | ||
|
||
```{code-block} java | ||
Point player = new Point(3, 10); | ||
Point monster = new Point(25, 10); | ||
// De loop moet stoppen zodra de speler bij het monster is (als de coördinaten gelijk zijn) | ||
while(player!=monster) { | ||
player.translate(1,0); | ||
System.out.println("Move.."+player); | ||
} | ||
System.out.println("Game over"); | ||
``` | ||
|
||
De bedoeling is dat de speler steeds een stap zet, totdat de speler bij het monster is. Dit is het geval als de coördinaten van `player` en `monster` gelijk zijn. | ||
|
||
Test de code. De code bevat een ernstige fout. Welke? | ||
|
||
Er zijn twee correcte manieren om de coördinaten van `player` en `monster` te vergelijken. Allereerst het vergelijken van zowel de `x`- als de `y`-coördinaten. Verbeter op deze wijze de fout. | ||
|
||
Een andere manier is het vergelijken van de inhoud van de objecten. Dit lijkt te gebeuren in de gegeven code, maar dit is niet het geval. Inhoud van objecten wordt vergelijken met de `equals` methode. Verbeter de fout door gebruik te maken van de `equals` methode. | ||
|
||
De `equals` methode is de gangbare manier om de inhoud van objecten te vergelijken. Wat exact wordt vergeleken, hangt af van de klasse. Net als `toString` is de methode `equals` altijd aanwezig, maar het verschilt per klasse of deze volledig is geïmplementeerd. | ||
|
||
|
||
|
||
|
||
|
||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,63 @@ | ||
# Opgave Klasse `LocalDate` | ||
|
||
De klasse `LocalDate` representeert een datum in de plaatselijke tijdzone. | ||
|
||
De *constructor* van `LocalDate` is niet *public*, waardoor het niet mogelijk is om met het keyword `new` instanties te maken van `LocalDate`. | ||
|
||
De documentatie van `LocalDate` is [hier te vinden](https://docs.oracle.com/en/java/javase/11/docs/api/java.base/java/time/LocalDate.html) | ||
|
||
Onder "Method Summary" - "Static Methods" zijn methodes te vinden waarmee instanties van `LocalDate` worden gemaakt. Daarvan zijn `now` en `of` het belangrijkst. | ||
|
||
## Voorbeeld | ||
|
||
Zie het voorbeeld hieronder: | ||
|
||
```{code-block} java | ||
LocalDate vandaag = LocalDate.now(); | ||
LocalDate lustrum = LocalDate.of(2023, 10, 18); // Hanze lustrum 18 oktober 2023 | ||
System.out.println("Vandaag: " + vandaag); | ||
System.out.println("Hanze lustrum '23: " + lustrum); | ||
if (vandaag.isAfter(lustrum)) { | ||
System.out.println("Het Hanze lustrum feest is al geweest."); | ||
} else { | ||
long d = ChronoUnit.DAYS.between(vandaag, lustrum); | ||
System.out.println("Over " + d + " dagen is het feest"); | ||
} | ||
``` | ||
|
||
De uitvoer van `LocalDate` op het scherm (om precies te zijn: de `toString` methode van `LocalDate`) geeft geen 'mooie' datum, maar een standaard weergave in het *iso8601-formaat* YYYY-MM-DD. | ||
|
||
## Werken met de klasse `LocalDate` | ||
|
||
Maak de onderstaande opgaven. Zoek in de documentatie naar geschikte methodes. Als er wordt gevraagd om een datum op het scherm af te drukken, dan kun je volstaan met een standaard weergave. Als gevraagd wordt naar een weekdag dan is het voldoende om de weekdagen in het Engels af te drukken, zoals deze wordt teruggegeven door bijvoorbeeld de methode `getDayOfWeek`. | ||
|
||
## Kleine opgaven | ||
|
||
We beginnen met wat eenvoudige opgaven om op te warmen. Druk de antwoorden van de onderstaande vragen af: | ||
|
||
- Op welke weekdag valt 10 januari 1965? | ||
- Op welke weekdag viel nieuwjaarsdag (1 januari) in het huidige kalenderjaar? | ||
- Wat is de datum vijf weken na vandaag? | ||
- Hoeveel dagen is het geleden dat Nederland het Europees kampioenschap voetbal won (op 25 juni 1988)? | ||
|
||
## Huidige collegejaar | ||
|
||
Een collegejaar loopt van 1 september tot 1 september van het jaar daarop. Om welk collegejaar het gaat wordt vaak aangegeven met jaartallen. Zo wordt het collegejaar dat begint op 1 september 2023 aangegeven met '23-'24. | ||
|
||
Zet het huidige collegejaar op het scherm. Bedenk een methode om het programma te testen, zodat je zeker weet dat het programma over bijvoorbeeld 9 maanden ook nog de het juiste collegejaar aangeeft. | ||
|
||
## Kerst | ||
|
||
Kerst valt elk jaar op 25 en 26 december. Zet op het scherm hoeveel dagen het nog duurt, voordat het kerst is (eerste kerstdag). | ||
Als het nu eerste of tweede kerstdag is, zet dan op het scherm dat het nu kerst is. | ||
|
||
## Sinterklaas | ||
|
||
Sinterklaas is elk jaar op 5 december. Zet op het scherm de eerstvolgende 10 datums waarop Sinterklaas plaatsvindt. Zet bij elke datum ook op welke weekdag het plaatsvindt. | ||
Als het vandaag Sinterklaas is, dan telt deze mee met de 10. | ||
|
||
## Prinsjesdag | ||
|
||
Prinsjesdag is elk jaar op de derde dinsdag van september. Zet op het scherm de eerstvolgende 5 datums waarop prinsjesdag plaatsvindt. | ||
Als het vandaag prinsjesdag is, dan telt deze mee met de 5 datums op het scherm. | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,77 @@ | ||
# Opgave klasse `OptionalInt` | ||
|
||
Deze opgave gaat over de klasse `OptionalInt`. Deze klasse is handig als het mogelijk moet zijn om een integer-waarde terug te geven waarbij het ook mogelijk is dat er geen waarde aanwezig is (`empty`). | ||
|
||
Naast `OptionalInt` bevat Java ook `OptionalLong`, `OptionalDouble` en de generieke `Optional<T>`. | ||
|
||
## Casus: *Break-even* punt berekenen | ||
|
||
Er is sprake van een *break-even* punt wanneer er geen winst en geen verlies wordt gemaakt. | ||
|
||
Stel dat de kosten voor het maken van een product 80 euro per stuk bedragen. Behalve deze variabele kosten moet er 1000 gereserveerd worden voor de vaste lasten. Het product wordt verkocht voor 100 euro. Per stuk wordt dan 20 euro winst gemaakt ten opzichte van de variabele kosten (€100 - €80 = €20). Om geen verlies meer te maken moeten minimaal 50 stuks worden verkocht (immers €1000 / 20 stuks = 50). | ||
|
||
Met de volgende methode wordt het break-even punt berekend van verkoop van een product aan de hand van vaste kosten, de kosten per stuk en opbrengst per stuk: | ||
|
||
```{code-block} java | ||
public static int berekenBreakeven(double vasteKosten, double kostenPerEenheid, double opbrengstPerEenheid) { | ||
double winstPerEenheid = opbrengstPerEenheid - kostenPerEenheid; | ||
return (int)Math.ceil(vasteKosten / winstPerEenheid); | ||
} | ||
``` | ||
|
||
De volgende hulp-methode wordt gebruikt om het break-even punt op een nette manier weer te geven: | ||
|
||
```{code-block} java | ||
public static void printBreakeven(double vasteKosten, double kostenPerEenheid, double opbrengstPerEenheid) { | ||
int n=berekenBreakeven(vasteKosten, kostenPerEenheid, opbrengstPerEenheid); | ||
System.out.println("Break-even punt: "+n+" eenheden."); | ||
} | ||
``` | ||
|
||
## De klasse `OpgaveOptionalInt` | ||
|
||
Maak een klasse `OpgaveOptionalInt` met daarin de methodes `berekenBreakeven` en `printBreakeven`. Maak een `main` methode waarin je de onderstaande testcode zet. Klopt het resultaat? | ||
|
||
|
||
```{code-block} java | ||
printBreakeven( 1000, 80, 100 ); // 50 | ||
printBreakeven( 12000, 0.75, 1.30 ); // 21819 | ||
``` | ||
|
||
|
||
## Geen break-even punt | ||
|
||
Wat is het resultaat van de volgende test-aanroep? | ||
|
||
```{code-block} java | ||
printBreakeven( 2500, 12, 10.5 ); | ||
``` | ||
|
||
Is dit resultaat reëel/valide? | ||
|
||
Pas de methode `printBreakeven` zodanig aan dat in het geval van geen break-even punt op het scherm "Geen break-even punt" wordt afgedrukt. | ||
|
||
## Ongeldige waardes | ||
|
||
Als een uitkomst niet reëel of valide is, dan heeft dit vaak te maken met ongeldige invoerwaardes. Het afhandelen van ongeldige argumenten is geen onderwerp van deze opgave. De argumenten zijn in dit geval juist wel geldig. Er zijn reële situaties denkbaar waarbij de kostprijs hoger is dan de opbrengst. | ||
|
||
Het break-even punt is negatief omdat de variabele koste hoger zijn dan de opbrengst per stuk. De uitkomst is niet reëel, want het is normaal gesproken niet mogelijk om een negatief aantal producten te verkopen. Wat is in dat geval wenselijk om te retourneren? | ||
|
||
Als een integer geretourneerd moet worden, dan zijn alleen gehele getallen mogelijk als resultaat. De getallen 0 en hoger zijn break-even punten. Eventueel zou een negatief getal gebruikt kunnen worden in het geval er geen break-even punt is. Probleem is dit een enigszins merkwaardig resultaat is, omdat het de suggestie wekt dat het aantal producten negatief kan zijn. Stel dat een programmeur hier geen rekening mee houdt, en bijvoorbeeld gemiddelden gaat berekenen, dan kunnen er ongemerkt vreemde uitkomsten onstaan. | ||
|
||
Een ideale oplossing zou de mogelijkheid zijn om aan te geven dat er *geen uitkomst* is. Hoewel dit in sommige gevallen met `None` of `null` mogelijk is en wordt gedaan (met een omweg ook in Java) hebben deze waardes strikt genomen niet dezelfde betekenis als geen waarde. Het niet-primitieve datatype `OptionalInt` biedt de mogelijkheid om naast een bepaalde integer-waarde aan te geven dat er geen waarde is. | ||
|
||
## OptionalInt gebruiken | ||
|
||
De documentatie van OptionalInt is te vinden op [de documentatie van Oracle](https://docs.oracle.com/en/java/javase/11/docs/api/java.base/java/util/OptionalInt.html). Pas de methode `berekenBreakeven` zo aan dat in plaats van een `int` een `OptionalInt` wordt geretourneerd. | ||
|
||
Als er geen break-even punt is, dan is deze `OptionalInt` empty (maak geen gebruik van `null`). Onder 'Static Methods' in de documentatie vind je de methodes om instanties te maken van `OptionalInt`. | ||
|
||
Pas ook `printBreakeven` aan, zodat deze gebruik maakt van de `OptionalInt`. | ||
|
||
![De statische methoden van `OptionalInt`](../images/opionalint-documentatie.png) | ||
|
||
|
||
|
||
|
||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.