Programmeren in Java/Basis
In dit hoofdstuk zullen we de absolute basis van de Java-syntaxis onder de loep nemen. We gaan nog niet te diep in op het gebruik van alles, we zullen ons bezig houden met zeer rudimentaire programma's. De absolute basis van het programmeren in Java dus!
Hallo wereld
bewerkenWe gaan nu ons eerste Java-programma schrijven, en zo leren werken met de compiler. Hoe je de compiler moet installeren vind je in het hoofdstuk Installatie.
Typ onderstaande code in (let op de hoofdletters, Java is hoofdlettergevoelig). Dit moet gebeuren in een programma dat de code als een tekstbestand opslaat. In Windows is dit bijvoorbeeld Kladblok. In Mac kan je TextEdit gebruiken. Sla de code op in een bestand met de naam Hallo.java.
public class Hallo {
public static void main(String[] args) {
System.out.println("Hallo wereld!");
}
}
Compileren
bewerkenWanneer je vanuit een commandolijn-omgeving (DOS-prompt, UNIX-shell, Windows: Start > Run > typ "cmd" ...)(In Windows 8 krijg je toegang tot de opdracht Uitvoeren door te drukken op de toets met het Windows-logo + R.) werkt, ga je nu naar de map waar het bestand Hallo.java staat. Daar typ je het volgende commando:
javac Hallo.java
Dit zou normaal geen fouten mogen geven (als je compiler goed geïnstalleerd werd). In de map zou nu een bestand met de naam Hallo.class moeten staan. Dit bestand is het klassebestand (class file) met daarin de bytecode van ons "Hallo Wereld"-programma. "javac" is de java-compiler.
Uitvoeren
bewerkenOm de bytecode uit te voeren gebruik je het programma "java". Dit programma leest de bytecode in en voert deze uit:
java Hallo
Je voert dus de naam van de klasse in zonder .class-extensie. Dit zou als resultaat "Hallo wereld!" in de console moeten afdrukken.
Indien je een IDE of iets dergelijks gebruikt en je slechts heel even een schermpje ziet voorbijflitsen, start je toch best via een command line shell of zoek je naar instellingen om dit venster open te houden.
Bespreking
bewerkenIk herneem even de code voor het gemak:
public class Hallo {
public static void main(String[] args) {
System.out.println("Hallo wereld!");
}
}
Op regel 1 maken we een nieuwe klasse aan. Met public geven we aan dat de klasse publiek zichtbaar is; zo'n klasse moet in een bestand zitten met dezelfde naam, gevolgd door .java. In dit geval dus Hallo.java. Meer over klassen vind je in het hoofdstuk Klassen.
Op regel 2 zie je de signatuur voor de main-methode. Dit is de instapmethode, je programma begint altijd met deze methode (later meer over methodes).
Op regel 3 roepen we een methode op uit de Java API, namelijk de methode println. Deze drukt de meegegeven tekst af in de console. De tekst die je meegeeft moet tussen haakjes en tussen aanhalingstekens. In plaats van tekst kan je ook variabelen afdrukken. Daarvoor moet je de naam van de variabele die je wilt afdrukken tussen de haakjes zetten, zonder aanhalingstekens.
Regel 4 en 5 sluiten respectievelijk de main-methode en de klasse Hallo terug af. Dit is verplicht. Tip: Het is een goede gewoonte om wanneer je het begin van bijvoorbeeld een methode schrijft ook onmiddellijk de afsluitende accolade te schrijven. Als je een IDE gebruikt, wordt dit vaak voor je gedaan.
Primitieve variabelen
bewerkenNu willen we toch graag wat meer doen dan enkel een tekst weergeven. We zullen ons eerste programma een beetje opfleuren met een wiskundige berekening met veranderlijken:
Java-code: Hallo.java
public class Hallo {
public static void main(String[] args) {
int a;
int b;
int c;
a = 1;
b = 2;
c = a + b;
System.out.println("1 + 2 = " + c);
}
}
Op regel 3 tot 5 maken we drie variabelen aan met respectievelijk de namen a, b en c. Dit doen we via het sleutelwoord int, wat de afkorting is voor integer. Dit sleutelwoord bepaalt welk soort variabele we aanmaken. Het aanmaken van een variabele noemen we declareren. Het vertelt de compiler dat we een variabele gaan gebruiken met een bepaalde naam en van een welbepaald type. Het declareren van variabelen is in Java verplicht. Als dat niet gebeurt, dan levert dat een foutmelding op tijdens het compileren.
We kunnen nog op een andere manier een reeks variabelen van hetzelfde type declareren door regel 3 tot 5 te schrijven als:
Java-code: Fragment uit Hallo.java
int a, b, c;
Deze laatste manier zorgt voor iets compactere code, maar is verder identiek.
Op regel 6 en 7 geven we zowel de variabele a als b een waarde. Men mag niet eender wat na het gelijkaanteken zetten (zie verder). De actie die we ondernemen heet initialiseren omdat we voor de eerste keer de variabelen een waarde toekennen. Het gelijkaanteken noemen we de toekenningsoperator en lees je best als "wordt" (en niét als "is").
Op regel 8 initialiseren we de variabele c. Niet met een door ons bepaalde waarde maar met de som van de twee variabelen a en b. Het plus-teken is een wiskundige operator.
Op regel 9 tonen we een tekst op het scherm zoals we eerder al deden. Deze tekst is "1 + 2 = ". Daarna schrijven we een plus-teken. Dit keer is de plus geen wiskundige operator maar een speciale "concatenatie"-operator die voor het aaneenzetten van tekst wordt gebruikt (zie het hoofdstuk over Stringbewerkingen).
In Java zitten een paar vaste sleutelwoorden zoals int die bepaalde types van variabelen aangeven. Variabelen die niet meer doen dan één bepaalde waarde bewaren noemen we primitieve variabelen. Welke typen deze waarden kunnen aannemen zijn door Java gedefinieerd en de programmeur kan er geen nieuwe bijmaken. Er zijn in totaal negen primitieve typen. Iedere soort staat voor een eigen type. Hieronder zie je alle primitieve typen:
Sleutelwoord | Betekenis | Aantal bits | Bereik | Voorbeeld |
---|---|---|---|---|
boolean | booleaanse waarde | 1 | true of false | boolean a = true; |
byte | heel klein geheel getal | 8 | −128 (−27) tot 127 (27 − 1) | byte b = 8; |
char | karakter | 16 | Alle BMP-tekens en surrogaatparen | char c = 'a'; |
short | klein geheel getal | 16 | −32768 (−215) tot 32767 (215 − 1) | short d = 658; |
int | geheel getal | 32 | −2147483648 (−231) tot 2147483647 (231 − 1) | int e = 2000000; |
long | groot geheel getal | 64 | −263 tot 263 − 1 | long f = 220000000; |
float | reëel getal | 32 | ±0,14 × 10−64 tot ±0,34 × 1039 | float g = 89.567; |
double | reëel getal (dubbele precisie) | 64 | ±0,49 × 10−325 tot ±0,18 × 10309 | double h = 1000.987; |
void | niets | - | - | void methode() { } |
Variabelen verschillen onderling van formaat, zo zijn er variabelen voor letters (ASCII-karakters), voor gehele getallen (bijvoorbeeld int), voor kommagetallen (double), ...
Ze verschillen daarbij ook nog in de hoeveelheid bits ze in het geheugen innemen. Een gewone int bevat bijvoorbeeld 32 bits ofwel 4 bytes. Andere gehele types zoals bijvoorbeeld short zijn 16 bits, of long (64 bits) groot. Wanneer je grote getallen wilt opslaan, kun je bijvoorbeeld beter een variabele van het long-type gebruiken dan van short. Je denkt hier het best altijd eerst even over na, zodat je niet overbodig veel ruimte inneemt (ook al is deze maar enkele bytes groter).
Het primitieve type void is speciaal. Deze wordt niet gebruikt voor variabelen, maar is alleen om aan te duiden dat een methode niets teruggeeft (zie later). We zullen hem niet direct nodig hebben, onthoud enkel dat het eigenlijk staat voor niets.
Operatoren
bewerkenIn Java laat een operator je toe (wiskundige) bewerkingen uit te voeren met variabelen. We onderscheiden drie grote groepen operatoren: rekenkundige (+, -, *, /, %), logische (&&, ||, !) en relationele (>, <, ==). Daarnaast hebben String-objecten nog een speciale "+" operator ter beschikking waarmee je verschillende Strings tot één String kunt "concateneren" (aaneenschakelen).
De meeste operatoren doen bewerkingen op twee variabelen, dit noemen we binaire operatoren. Er zijn er ook die op één variabele werken, de zogenaamde unaire operatoren. Er zijn slechts vier unaire rekenkundige operatoren: "+" en "-" als toestandsteken en "++" en "--", waarover later meer.
We zijn al drie (binaire) operatoren tegengekomen: De speciale String "+" operator, de rekenkundige "+" operator en de "=" operator die een waarde toekent aan een variabele. Hieronder volgt een lijstje van alle operatoren en een voorbeeld van hun gebruik. Let erop dat je meestal verschillende operatoren tegelijk gaat gebruiken (bv. a = b + c;).
Alle operatoren in Java:
Soort | Type | Symbool | Betekenis | Voorbeeld | Resultaat van het voorbeeld |
---|---|---|---|---|---|
Rekenkundig | Binair | = | Een waarde toekennen aan een variabele | a = 5; | De variabele a (eerder gedeclareerd) krijgt waarde 5 |
Rekenkundig | Binair | + | Waarden/Variabelen bij elkaar optellen | b = a + 1; | De variabele b krijgt de waarde van (a + 1), hier dus 6 |
Rekenkundig | Binair | - | Waarden/Variabelen van elkaar aftrekken | c = b - a; | c krijgt de waarde van het verschil tussen b en a, hier dus 1 |
Rekenkundig | Binair | * | Vermenigvuldigen | d = c * 5; | d krijgt de waarde van c vermenigvuldigd met 5, hier dus 5 |
Rekenkundig | Binair | / | Quotient, deling | e = d / 10; | e krijgt de waarde van d gedeeld door 10, hier 0 of 0.5 (afhankelijk van de types) |
Rekenkundig | Binair | % | Modulus, Rest van deling | f = d % 5; | f krijgt de rest van de deling d / 5, hier dus 0 |
Logisch | Binair | | | Logische OF (op bitniveau) | g = 4 | 5; | g krijgt het resultaat van 100 OF 101 (binair dus), g is dus 101 (wat overeenkomt met 5). |
Logisch | Binair | & | Logische EN (op bitniveau) | h = 4 & 5; | h krijgt het resultaat van 100 EN 101 (binair), h zal dus 100 (4) zijn. |
Logisch | Binair | ^ | Logische exclusieve OF (op bitniveau) | h = 4 ^ 5; | h krijgt het resultaat van 100 EOF 101 (binair), h zal dus 1 zijn. |
Logisch | Unair | ~ | Logische NIET (op bitniveau) | byte i = ~1; | i zal -2 zijn: NOT 0000 0001 = 1111 1110 wat volgens "two's complement" gelijk is aan -2. |
Relationeel | Binair | || | Booleaanse OF (werkt met boolean types) | boolean j = false || true; | j zal "true" zijn want 0 (false) OF 1 (true) geeft 1 (true) |
Relationeel | Binair | && | Booleaanse EN | boolean k = j && false; | k zal false zijn, ongeacht de waarde van j. |
Relationeel | Unair | ! | Booleaanse NOT | boolean l = !false; | l is "not false", dus true. |
Relationeel | Binair | == | "Is linkerlid gelijk aan rechterlid?" | boolean m = (5 == 6); | m zal false zijn omdat 5 niet gelijk is aan zes, de == geeft een boolean als resultaat (true of false). |
Relationeel | Binair | != | "Is linkerlid verschillend van rechterlid?" | boolean n = (5 != 6); | n zal true zijn. |
Relationeel | Binair | > | "Is linkerlid groter dan rechterlid?" | boolean o = (5 > 6); | o zal false zijn. |
Relationeel | Binair | >= | "Is linkerlid groter dan of gelijk aan rechterlid?" | boolean p = (4 >= 4); | p zal true zijn. |
Relationeel | Binair | < | "Is linkerlid kleiner dan rechterlid?" | boolean q = (5 < 6); | q zal true zijn. |
Relationeel | Binair | <= | "Is linkerlid kleiner dan of gelijk aan rechterlid?" | boolean r = (6 <= 5); | r zal false zijn. |
Bijkomende operatoren
bewerkenNaast de bovenstaande operatoren zijn er nog enkele verkorte notaties voor veelgebruikte bewerkingen (eigenlijk samentrekkingen van meerdere bewerkingen):
+=, -=, *=, /=, %=, |=, &=, ^=, ~= en !=;
Allemaal worden zij op dezelfde manier gebruikt. "x += y;" betekent bijvoorbeeld "x = x + y;", "x *= y;" betekent "x = x * y;". Concreet werkt dit als volgt:
Java-code: Codefragment om verkorte operatoren te illustreren:
int a = 5;
a += 5;
System.out.println(a);
Dit codefragment zal 10 als uitvoer hebben. Bovenstaand stukje code kan voluit zo geschreven worden:
Java-code: Codefragment om verkorte operatoren te illustreren:
int a = 5;
a = a + 5;
System.out.println(a);
Natuurlijk moet het linkerlid een variabele zijn die reeds een waarde heeft.
In- en decrement operatoren
bewerkenAls laatste heb je ook nog de increment- en decrementoperatoren. Dit zijn operatoren die je kan gebruiken om een variabele met 1 te verhogen of te verlagen. Ze zien er zo uit: ++ en --. Je kan ze voor of na een variabele zetten om deze variabele te bewerken (bvb. "i++;" zal de variabele i met 1 verhogen, "j--;" zal j met 1 verlagen). Bemerk het verschil in gedrag wanneer de operator voor (preincrementie) of na (postincrementie) de variabele staat.
Java-code: IncrementKort.java
1: public class IncrementKort {
2: public static void main(String[] args) {
3: int a = 1, b = 2, c, d;
4: c = ++a; // a = 2, c = 2
5: c = a++; // a = 3, c = 2 (!)
6: d = --b; // b = 1, d = 1
7: --b; // b = 0
8: ++b; // b = 1
9: b++; // b = 2
10: }
11:}
Bij preincrementie (++a) wordt de variabele eerst met 1 verhoogd/verlaagd en de bewerking heeft als resultaat de nieuwe waarde van de variabele waarop de bewerking werd uitgevoerd. Wanneer je postincrementie (a++) gebruikt, zal het resultaat van de bewerking de waarde van de variabele vóór de incrementie zijn, maar zal de variabele daarna met 1 verhoogd/verlaagd worden. Je merkt ook dat pre- of postincrementie enkel van belang zijn als je het resultaat van de bewerking gebruikt. Als je echter gewoon de waarde van een variabele wilt verhogen of verlagen zijn beide operatoren gelijkwaardig.
Java-code: IncrementLang.java
1: public class IncrementLang {
2: public static void main(String[] args) {
3: int a = 1, b = 2, c, d;
4: a = a + 1; // Deel 1 van: c = ++a;
6: c = a; // Deel 2 van: c = ++a;
7:
8: c = a; // Deel 1 van: c = a++;
9: a = a + 1; // Deel 2 van: c = a++;
10:
11: b = b - 1; // Deel 1 van: d = --b;
12: d = b; // Deel 2 van: d = --b;
13:
14: b = b - 1; // --b;
15: b = b + 1; // ++b;
16: b = b + 1; // b++;
17: }
18:}
Meestal is het gewenst niet elke bewerking op een aparte regel te doen. Een bewerking heeft altijd een resultaat en dat resultaat kan gebruikt worden in een andere bewerking: (a = 2 + 3) kan gebruikt worden als volgt: b = (a = 2 + 3). Zo kan je vlotjes ingewikkelde bewerkingen op één regel plaatsen, maar let erop dat je code nog steeds leesbaar blijft.
Operatorprecedentie
bewerkenIn Java kan je operatoren en variabelen combineren in uitdrukkingen, net zoals men dit doet in wiskundig rekenwerk. Maar als je bijvoorbeeld de volgende code typt, wat is dan de waarde van de variabele resultaat?
Java-code: Precedentie.java
public class Precedentie {
public static void main(String[] args) {
int a = 2, b = 3, c = 4, d = 2, e = 1; // initialiseer enkele variabelen
double resultaat; // declareer een double met de naam "resultaat"
resultaat = (a + b) * c - b / e + (c - d) * a++; // een reeks bewerkingen
}
}
Om dit te weten te komen kan men gebruik maken van volgend schema.
Operatoren op een hogere regel hebben voorrang (precedence) op de operatoren op lagere regels, zij zullen dus het eerst uitgevoerd worden. Operatoren op dezelfde regel hebben geen voorrang op elkaar, zij zullen gewoon van links naar rechts uitgevoerd worden volgens hoe ze in je code staan. Links en rechts associatief betekent dat de operatoren ofwel van links naar rechts ofwel van rechts naar links uitgevoerd worden. Haakjes worden van binnen naar buiten uitgevoerd, net zoals in de gewone wiskundige notatie. Je kan deze standaard operatorvoorrang dus "aanpassen" door gebruik te maken van haakjes.
De waarde van de variabele resultaat is in bovenstaand stukje code trouwens 21.
Nu we alles weten om met variabelen te kunnen werken en we uitvoer naar de gebruiker kunnen sturen, kunnen we bijna echt zinvolle programma's maken, maar het zou handig zijn als ons programma afhankelijk van bepaalde factoren een ander verloop zou krijgen. Hierover gaat de volgende sectie.