Praktikum nr. 1

Teemad

Esmatutvus Javaga. Käivitamine käsurealt. Andmete sisestamine klaviatuurilt. 

Pärast selle praktikumi läbimist üliõpilane


Märkus! 

Detailid (kataloogid, versioonid jms.) võivad erinevates arvutites (arvutiklassides) olla erinevad. Jälgige lisainfot tahvlil jm.


Kompileerimine ja käivitamine käsurealt

Java programm ei ole esialgu tegelikult midagi muud kui lihtsalt üks tavaline tekst, mille võime koostada näiteks Notepad-i või mõne teise tekstiredaktoriga. Erinevalt Pythonist tuleb Java programmi algtekst lisaks salvestamisele ja käivitamisele vahepeal ka kompileerida. Tegelikult on muidugi olemas spetsiaalseid redaktoreid, mis aitavad programmeerimise erinevates faasides. Esimeses praktikumis piirdume aga sihilikult tavalise tekstiredaktori ja käsurearežiimiga.

Teemegi siis näiteks Notepadiga teksti, mille salvestame näiteks kataloogi  Z:\oop nime all Tere.java. Teksti ei pea ise sisse toksima, vaid võib kopeerida praktikumimaterjalist.

class Tere {
  public static void main(String[] args) {
    System.out.println("Tervist!");
  }
}

Start-nupu ja käsu cmd abil saab käsurearežiimi. Sealt saab Z: ja cd oop abil õigesse kataloogi (Z:\oop). Kompileerimiseks samas kataloogis anda käsurealt käsk

> javac Tere.java

Kui kompileerimine õnnestub, siis kompilaator mingeid teateid ei anna ja pärast töö lõppu ilmub uuesti käsuviip >. Kataloogi tekib fail Tere.class. See class-fail tekibki kompileerimise tulemusena. Edaspidiseks arvutiga kasutamiseks ongi just seda faili vaja. Samas on see fail aga inimesele suhteliselt loetamatu.

Kui kompilaator leiab programmi tekstis vigu, siis kuvab ta ekraanile vastavad teated. Kui Windowsis ilmub veateade The name specified is not recognized as an internal or external command ... või Bad command or file name, siis ei õnnestunud arvutil kompilaatorit javac käivitada. Sel juhul tuleks käsurealt paika panna otsimistee (andes näiteks käsu path "C:\Program Files\Java\jdk1.7.0_02\bin" (sõltub konkreetsest arvutist)) ja proovida uuesti.  

Käsurearežiimis on abiks käsk dir, samuti üles-alla nooleklahvid ja tabeldusklahv. Proovige!

Käivitamiseks samas kataloogis anda käsurealt käsk

> java Tere

Tulemusena väljastatakse

Tervist!

Kui tekkis veateade Exception in thread "main" java.lang.NoClassDefFoundError: Tere (mis näitab, et interpretaator ei leidnud vajalikku class-faili), siis sisestage käsurealt set classpath= ja proovige uuesti.

Esimene Java programm

Analüüsime veidi seda programmi, mis on Pythoni analoogilisest programmist mõnevõrra erinev. Toome mõned punktid, mida tuleb silmas pidada. (Mõned alltoodud punktid on natuke lihtsustatult toodud, aga esialgu ei ole ehk kogu nüansirikkust vajagi.)

Klass

Javas peab kogu programmitekst olema esitatud klassidena. Üks programm võib koosneda (ja väga sageli koosnebki) mitmest klassist. Täna ajame küll üheklassiliste programmidega läbi. Klassinimi pannakse paika võtmesõna class järel. Siit saab ka class-fail oma nime. (Kui näiteks eeltoodud faili korral oleks failinimi olnud nt. Ilves.java, siis oleks ikkagi kompileerimisel tekkinud Tere.class.)

Looksulud { }

Javas on programmi liigendamiseks looksulud (loogelised sulud). Taanete kasutamine ei ole otseselt kohustuslik, aga on väga-väga soovitatav. Looksulud esinevad alati paarikaupa ja nende vahel olev programmi osa moodustab ühe terviku — ploki. Programmi osad asuvad sageli üksteise sees, nii võibki konkreetses kohas olla "avatud" hulk looksulgusid. Jälgida tuleb, et kõik algavad looksulud ka õiges kohas "lõpetataks".  Meie näites on kõige suurem tervik klass ise, mida alustav looksulg on esimese real ja lõpetav looksulg viimasel real. Teine looksulgudega piiritletud osa on meetod main.

Semikoolon ;

Javas on iga direktiivi lõpus semikoolon. Meie näites reas
System.out.println("Tervist!");

Peameetod

Klassis võib sisalduda erinevat laadi asju. Antud juhul on siin vaid üks meetod. Tegemist on peameetodiga, mille nimi on main. Peameetodit sisaldavat klassi nimetatakse peaklassiks ja seda on võimalik käivitada, kusjuures programmi täitmine algab alati just peameetodist.

public static void main(String[] args) {
    System.out.println("Tervist!");
  }

Võtmesõnad public ja static ning tagastustüübi määraja void on peameetodi korral kohustuslikud. Piiritlejat public on vaja, et peameetod oleks käituskeskkonnale kättesaadav, piiritleja static määrab, et tegemist on klassimeetodiga. (Ilma selle piiritlejata oleks tegemist isendimeetodiga, millest räägime nädala-paari pärast.)  Kõikide meetodite puhul on vajalik määrata tagastustüüp. Peameetodi puhul on selleks voidtühitüüp, mida kasutatakse niisuguste meetodite puhul, mis tegelikult väärtust ei tagasta.

Muutujat args saab kasutada käsurealt argumentide etteandmiseks (põhimõtteliselt võib sellele muutujale ka teise nime anda).  Tüüp String[] näitab, et neid argumente käsitletakse kui sõnede järjendit. (Järjenditest räägime järgmises praktikumis.)

Kommentaarid

Programmile saab lisada ka kommentaare —  tekstiosa, mida kompileerimisel eiratakse. Pikemad kommentaarid saab piiritleda sümbolipaaridega /* ja */. Üherealise kommentaari algust märgib sümbolipaar //. Nii saab alustada kommentaari ka programmitekstiga realt, nt.
System.out.println("Tervist!"); // väljastatakse ekraanile
Kommentaarid kujul /** ... */ on kasutatavad automaatse dokumentaatori sisendina.

Ülesanne A1

Lisage programmile teist korda direktiiv System.out.println("Tervist!");
Muutke väljastatavat teksti! Kompileerige! Käivitage!
Kustutage esimese
System.out.println lõpust ln ära. Mis muutub?

Tüübid, muutujad

Javas (erinevalt Pythonist) peab muutuja ja ka meetodi tagastustüüp olema ilmutatult määratud. Kui tahame näiteks kasutada täisarvutüüpi muutujat a, saame kirjeldamisel kasutada tüüpi int:
int a;
Muutujale omistatakse väärtus = abil.
a = 7;
Kirjeldamise ja väärtuse omistamise saab ka ühendada:
int inimesi = 28;

Javas on mõned algtüübid (algavad väikese tähega):
Sõned ei ole Javas algtüüp, vaid on süsteemse klassi String isendid. (Nendest pikemalt nädala-paari pärast.) Põhimõtteliselt ongi uute tüüpide (klasside) loomine Javas programmeerimise aluseks.

Tüübid ja meetodid

Lisaks muutujatele peavad olema tüübid määratud ka meetodite korral. Kui meetod ei tagasta väärtust, siis on tagastustüübiks void (tühitüüp). Kõigil teistel juhtudel aga peab tagastustüüp olema kooskõlas sellega, mis tüüpi väärtuse meetod tagastab. Tagastatakse aga selle avaldise väärtus, mis asub naasmisdirektiivis võtmesõna return järel. Lisaks peab meetodi päises olema määratud ka parameetrite tüübid. Vaatleme näitena meetodit, mis arvutab kahe reaalarvu aritmeetilise keskmise.

static double aritkeskmine(double arv1, double arv2) {
    double summa = arv1 + arv2;
    return summa/2;
}

Selle meetodi sisu saaks teha veel lühemaks - vaid üherealiseks: return(arv1 + arv2)/2;
Aga las seal praegu olla ka olemas muutuja summa.

Ülesanne A2

Püüame nüüd selle meetodi programmi sisse panna. Meetodite järjekord tekstis pole oluline, täitmine algab nagunii peameetodist. Küll aga on oluline, et ühe kirjeldus lõppeks enne, kui järgmine algab.

class Keskmised {

  static double aritkeskmine(double arv1, double arv2) {

    double summa = arv1 + arv2;
  return summa/2;
}

  public static void main(String[] args) {
    double a = 1.5;
    double b = 2.25;
    double c = aritkeskmine(a, b);

    System.out.println("Arvude " + a +" ja " + b + " aritmeetiline keskmine on " + c);
   
System.out.println(aritkeskmine(-3.4, 3.4));
  }
}

Ülesanne P1

Palun nüüd pöörduge esimese paberiloleva ülesande juurde ja lahendage see koos paarilisega paberil.

Lisage peameetodis double c = aritkeskmine(a, b) rea järele uus rida

System.out.println("Arvude" + a +" ja " + b + " summa on " + summa);

Tingimusdirektiivid

Tingimusdirektiivi üldine kuju Javas on
if (loogiline avaldis) direktiiv1 else direktiiv2

Tingimusdirektiiv algab sõnaga if, millele järgneb ümarsulgudes loogiline avaldis (avaldis, mille väärtus saab olla kas tõene või väär) ja sellele omakorda direktiiv, mis täidetakse siis, kui avaldis on tõene. Sõnale else aga järgneb direktiiv, mis täidetakse siis, kui loogiline avaldis on väär. Tingimusdirektiivi else-osa võib ka üldse puududa. Ühe direktiivi rollis võib olla ka plokk (programmilõik looksulgude {} vahel).

if (loogiline avaldis)
   {
direktiivid1

   }
else
   {
direktiivid2

       }

Ülesanne A3

Proovige teha mingi lihtne näide, kus on kasutatud if-lauset. 

Lülitidirektiiv

Suurema hulga harude puhul saab kasutada lülitidirektiivi, mille üldkuju on järgmine

switch (avaldis){
   case võimalikväärtus1:
        direktiivid1;
        break;
   case võimalikväärtus2:
        direktiivid2;
        break;
   
   …

   
   default:

        direktiivid juhuks, kui ühtegi ülaltoodud varianti ei kasutata;

Näiteks järgmine programmilõik

int nädalapäev = 4;
switch (nädalapäev) {
    case 1: System.out.println("Esmaspäev"); break;
    case 2: System.out.println("Teisipäev"); break;
    case 3: System.out.println("Kolmapäev"); break;
    case 4: System.out.println("Neljapäev"); break;
    case 5: System.out.println("Reede"); break;
    case 6: System.out.println("Laupäev"); break;
    case 7: System.out.println("Pühapäev"); break;
    default: System.out.println("Vigane päev"); break;
}

Ülesanne A4

Katsetage ka lülitidirektiivi tööd.

Tsüklidirektiivid Javas

Tsüklite programmeerimiseks on keeles Java mitu erinevat konstruktsiooni: kolmikpäisega tsükkel (for), eelkontrolliga tsükkel (while) ja järelkontrolliga  tsükkel (do-while). For-tsüklil on olemas ka lühem versioon järjest nt. järjendi kõigi elementide poole pöördumiseks, aga seda käsitleme edaspidi.

Ülesanne P2

Palun lugege läbi alltoodud kirjeldused ja visandage paberile vastavad plokkskeemid.

Üldtsüklidirektiiv ehk kolmikpäisega tsükkel ehk for-tsükkel:

for (eeltegevused; jätkamistingimus; sammu järeltegevused) {

    // käsud, mida tuleb täita niikaua,

    // kui jätkamistingimus kehtib

}

Tüüpiliselt on eeltegevusteks mingitele muutujatele algväärtuste omistamised. Võimalikud eeltegevused on näiteks järgmised.

int i = 0;

Eeltegevused: kirjeldatakse täisarvutüüpi muutuja i, mis on selle tsükli lokaalne muutuja (st. muutuja i väärtus ei ole väljaspool tsüklit kasutatav) ja omistatakse sellele algväärtus 0.

kordaja = 0.5;

Eeltegevus: omistatakse reaalarvutüüpi muutujale kordaja algväärtus 0.5. Siin ei ole kordaja tsükli lokaalne muutuja, vaid eeldatakse, et see muutuja on kirjeldatud juba enne tsükli täitmist (tüüp on double või float).

int i = 0, summa = 0;

Eeltegevused: kirjeldatakse täisarvutüüpi tsükli lokaalmuutujad i ja summa ning omistatakse neile algväärtused 0.

Jätkamistingimus tuleb seada nii, et tsüklit täidetaks täpselt vajalik arv kordi. Näiteks kui soovime, et tsüklit täidetaks kolm korda, võib tsükli eeltegevusena omistada mingile lokaalmuutujale (tsükliloendajale) algväärtuseks nulli ja igal sammul liita tsükliloendajale ühe. Pärast tsükli esimest sammu on tsükliloendaja väärtus siis 1, pärast teist sammu 2 ja pärast kolmandat sammu 3. Neljandat sammu me enam lubada ei tohi, seega peaks tsükli lõpetama niipea, kui tsükliloendaja saab võrdseks 3-ga või 3-st suuremaks. Jätkamistingimus on lõpetamistingimuse vastandtingimus, ehk antud juhul võib tsüklit jätkata nii kaua, kui tsükliloendaja on veel väiksem kolmest. Olukorda kirjeldava for-tsükli päis on järgmine:

for (int i = 0; i < 3; i = i + 1)

Tsükli sammu järeltegevuseks on sageli mingi muutuja väärtuse suurendamine või vähendamine teatud arvu võrra. Näiteks

i = i + 1;

j = j + 2;

k = k - 1;

Kõiki neid omistamisi saab Java-keeles ka lühemalt kirja panna:

i++;

j+=2;

k--;

Kirjutame näiteks for-tsükli, mis väljastab ekraanile viis korda teksti Tere!.

for (int i = 0; i < 5; i++) {

    System.out.println("Tere!");

}

Kui tsükli sisu koosneb ühest käsust, siis võib loogelised sulud ka ära jätta. 

Eelkontrolliga tsükkel ehk while-tsükkel:

while (jätkamistingimus) {

    // Siia kirjutame käsud, mida tuleb täita niikaua,

    // kui tsükli päises olev jätkamistingimus kehtib.

}

See while-tsükkel on samaväärne for-tsükliga, millel puudub nii eeltegevus kui ka sammu järeltegevus, s.o

for ( ; jätkamistingimus; ) {

    // käsud

}

Järelkontrolliga tsükkel ehk do-while-tsükkel:

do {

    // Siia kirjutame käsud, mida tuleb täita niikaua,

    // kui jätkamistingimus kehtib.

}

while (jätkamistingimus);

Pange tähele, et erinevalt eelkontrolliga tsüklist täidetakse järelkontrolliga tsüklit alati vähemalt üks kord, sest jätkamistingimuse kontroll toimub alles pärast tsükli sisu täitmist.

Ülesanne P3

Kirjutage paberile iga tsüklitüübi jaoks vähemalt üks lihtne ülesanne.

Ülesanne A5

Lahendage ülesandes P3 püstitatud ülesanded.

Andmete sisestamine klaviatuurilt.

Üsna sageli on vaja, et programm saaks andmeid klaviatuurilt. See on Javas veidi töömahukam kui Pythonis. Vaatleme järgmist näidet:

import java.util.Scanner;

class Klaviatuurilt {

  public static void main(String args[]) {

  Scanner scan = new Scanner(System.in);

  System.out.println("Sisesta täisarv");

  int taisarv = scan.nextInt();

  System.out.println("Sisesta reaalarv");

  double ujukomaArv = scan.nextDouble();

  System.out.println("Sisestasid täisarvu: " + taisarv);

  System.out.println(" ja reaalarvu: " + ujukomaArv);

  }

}

Märgime siin, et esimesel real imporditakse valmisklass, mille abil klaviatuurilt sisselugemist teostada. Importimise käsk peab olema enne klassi definitsiooni. Käsuga

Scanner scan = new Scanner(System.in);

luuakse objekt, mille abil on võimalik klaviatuurilt sisestatud arve lugeda. Täisarvu ja reaalarvu (ujukomaarvu) sisselugemine klaviatuurilt toimub vastavalt meetoditega nextInt() ja nextDouble(). Kümnendkoha eraldaja (, või .) sõltub konkreetse arvuti seadetest.

Ülesanne A6

Koostada programm, mis kontrollib, kas klaviatuurilt sisestatud kolm reaalarvu saavad olla kolmnurga külgedeks.

Ülesanne A7

Koostada programm, mis küsib kasutajalt täisarvu ja teeb kindlaks, kas on tegemist paarisarvuga. Programmi töö lõpeb, kui kasutaja sisestab arvu null.  

Ülesanne A8

 Koostada programm, mis toob ekraanile kilogrammi ja naela vastavustabeli (võtame 1 kg = 2.2 naela, kuigi täpsem oleks 2.20462262185 naela):

Kg        Nael

1         2.2

3         6.6

 

...

197       433.4

199       437.8

Selleks, et saada ilusat tabelit, tuleb väljundit vormindada. Veerud saab tekitada tabeldusmärgi abil, mis Javas on "\t". Näiteks System.out.println("abc"+"\t"+"def"); viib sõne def uude veergu. Ujupunktarvude vormindamiseks ja väljastamiseks saab kasutada meetodit System.out.printf. Näiteks  System.out.printf("%.1f",1234.45); määrab väljastatava kuju murdosa pikkuseks 1.

Täiustage programmi nii, et kasutaja käest küsitakse info kilogrammide vahemiku kohta (algus, samm, lõpp).

Ülesanne A9

Koostada programm, mis leiab järgmise summa:
1/3+3/5+5/7+...+95/97+97/99

Täiustage programmi nii, et kasutaja käest küsitakse, mitme esimese liikme summa on vaja arvutada.

Ülesanne P4

Palun arutage ja kirjutage paberile, millised on teie esmamuljed Javast. Millised on suurimad erinevused Pythoniga? Mida oleks vaja veel üle seletada?

Keskkond Eclipse

Alates järgmisest korrast on soovitav kasutada keskkonda Eclipse.Võiksite ka juba täna proovida. 

Eclipse on vabavara, mis töötab erinevatel operatsioonisüsteemidel (Windows, Linux, Solaris ..). Eclipse toetab erinevates programmeerimiskeeltes töötamist (Java, PHP, C++, ...), samuti saab tema abil töötada nt. UML-ga. Eclipse evib hästi palju võimalusi. Meie vaatleme (ja esialgu vajame) neist vaid osasid.

Tegutseme Java projektidega. Põhieesmärgiks on algtekstide toimetamine, süntaktiline silumine ja käivitamine. Silumise hõlbustamiseks saab panna katkestuspunkte, mille abil saab jälgida muutujate väärtuste muutumist.

Teie andmed asuvad töökataloogis (workspace). Sinna peab kasutajal olema õigus kirjutada. Meie puhul sobib selleks nt. Z:-ketta alamkataloog oop. Iga projekt paigutub eraldi alamkataloogi, milles siis on erinevad failid.

Püüdkem nüüd Eclipse käivitada

Kodune ülesanne!

Mõningaid materjale

Teaduskooli programmeerimise kursus