In het handboek1 gebruiken we als voorbeeld een vliegtuig met een vast aantal plaatsen. Een array houdt er een aantal instanties van de klasse Passagier bij. Niet op elke index hoeft er naar een object verwezen te worden. Is er geen verwijzing naar een object, dan heb je een lege plaats in het vliegtuig. Beschouw de array plaatsen zoals hieronder afgebeeld.

stereo-installatie

for-each lus

Stel dat we alle namen willen tonen in het Terminalvenster van BlueJ. Een eerste idee is om dit via de for-each lus te doen. Een mogelijke implementatie is dan:

for(Passagier p : plaatsen)
{
    p.print();
}

De lus lijkt het werk te gaan doen want je krijgt geen compilatiefout. Maar bij het uitvoeren van de methode print() krijg je volgende foutmelding:

fout1

Wat is er gebeurd?
Hoe los je dit nu op?

Alvorens je informatie vraag aan een object, moet je controleren of p naar een object wijst. Dit doe je als volgt:

for(Passagier p : plaatsen)
{
    if(p != null)
    {
        p.print();
    }
}

for-lus

Dezelfde redenering kan je nu toepassen bij de for-lus:

for(int index = 0; index < plaatsen.length; index++)
{
    if(plaatsen[index] != null)
    {
        plaatsen[index].print();
    }
}

In plaats van te kijken of een variabele al dan niet naar null verwijst, werk je met de vierkante haken en de index. Voor elke volgende index wordt gecontroleerd of plaatsen[index] niet naar null wijst. Geen null betekent een verwijzing naar een object waarvan je de naam kan tonen in het Terminalvenster.

while-lus

Waarschijnlijk ben je tijdens de oefeningen op volgend probleem gebotst:

Nemen we als voorbeeld het zoeken naar een passagier met een zekere naam, bijvoorbeeld "Scottie"

Een foute oplossing

Zolang de naam van de passagier verschillend is van "Scottie" wordt verder gezocht. De naam van de passagier op index 0 is "Dennis". Er wordt verder gezocht. De naam van de passagier op index 1 wordt getest. Alleen, daar vind je geen verwijzing naar een passagier. Gevolg: een mooie rode NullPointerException.

while(index < plaatsen.length && ! plaatsen[index].getNaam().equals("Scottie"))
{
    index++;
}
Een betere oplossing

Dit probleem oplossen, is niet makkelijk. Vandaar dat we de programmeertaal even verlaten en het probleem in het Nederlands omschrijven. Ons objectendiagram geven we wat meer vorm. Dat helpt het denken vooruit.

stereo-installatie

Zolang de index geldig is, heb je twee gevallen waarbij verder zoeken vereist is.

Plakken we alle puzzelstukje aan elkaar dan krijgen we volgende voorwaarde bij een geldig index:

plaatsen[index] == null || (plaatsen[index] != null && ! plaatsen[index].getNaam().equals("Scottie"))

lazy evaluation

Misschien denk je, wat een gigantische voorwaarde. Kan dat niet eenvoudiger? Jawel. Onderstaande voorwaarde is voldoende.

plaatsen[index] == null || ! plaatsen[index].getNaam().equals("Scottie")

Maar heb je dan geen probleem bij plaatsen[index].getNaam() indien er op de gegeven index niet verwezen wordt naar een object? Het antwoord is neen.

Is er op de gegeven index geen object te bespeuren, dan evalueert het eerste deel van de voorwaarde tot true. Wanneer het eerste deel van een samengestelde voorwaarde bij de logische OF waar is, dan weet je dat de hele logische expressie waar wordt, ongeacht de uitkomst van het tweede deel.

Logische OR

true OR true → true
true OR false → true

Ook Java is dan zo vriendelijk om het tweede deel niet meer te controleren. Is er op de gegeven index geen verwijzing naar een object te bespeuren, dan wordt ! plaatsen[index].getNaam().equals("Scottie") niet meer gecontroleerd. Dus ook geen NullPointerException.

Deze manier van evalueren van samengestelde booleaanse expressies heet lazy evaluation. Waarom nog verder controleren als je het antwoord reeds kent? Het tegenovergestelde bestaat ook en heet strict evaluation. Dat bespreken we hier niet.

De meest elegante oplossing van ons zoekprobleem gaat dan als volgt:

while(index < plaatsen.length && (plaatsen[index] ==  null || ! plaatsen[index].getNaam().equals("Scottie")))
{
    index++;
}