1.4. Izteiksmes un vadības komandas

Mērķi

  • Atšķirt instanču mainīgos un lokālos mainīgos
  • Aprakstīt instanču mainīgo inicializāciju
  • Prast izlabot kompilatora kļūdu: Possible reference before assignment vai The local variable ... may not have been initialized
  • Atpazīt, aprakstīt un lietot Javas operatorus
  • Atšķirt, kuras vienkāršo tipu piešķiršanas operācijas ir atļautas
  • Identificēt boolean izteiksmes un kurās vadības komandās tās vajadzīgas
  • Atpazīt vienkāršo tipu savstarpējo piešķiramību un situācijas, kur vajadzīgs tipa pārveidojums (typecasting)
  • Lietot if, switch, for, while, un do komandas, kā arī break un continue (ar un bez iezīmēm) kā vadības plūsmas konstrukcijas

Ievadjautājumi

  • Kādi mainīgo redzamības līmeņi var būt noderīgi programmētājam? (Piemēram, globālie mainīgie, statiskie klašu un interfeisu mainīgie, instanču mainīgie, lokālie mainīgie. Web gadījumā arī lapas/sesijas/aplikācijas līmenī redzami mainīgie.)
  • Vai vairākām klasēm var būt mainīgie ar to pašu vārdu; kāds ir šo mainīgo redzamības apgabals?
  • Kādas vadības plūsmas konstrukcijas ir sastopamas citās valodās? Kādas metodes lieto, lai programmētu vadības plūsmu, piemēram, ciklā (loop) vai komandā switch.

Mainīgie un redzamības apgabali

Lokālie mainīgie ir:

  • Mainīgie, kuri definēti kādā metodē, sauc par lokālajiem (local variable), automātiskajiem (automatic variable), pagaidu (temporary variable) jeb steka (stack variable) mainīgajiem
  • Šos mainīgos rada uz metodes izpildes laiku, un iznīcina, kad metode beidzas
  • Lokālie mainīgie ir jāinicializē pirms lietošanas; citādi rodas kompilatora kļūda

Redzamības apgabalu piemērs

1  public class ScopeExample {
2      private int i = 1;
3      public void firstMethod() {
4          int i = 4, j = 5; 
5          this.i = i + j;
6          secondMethod(7);
7      }
8      public void secondMethod(int i) {
9          int j = 8; 
10         this.i = i + j;
11     }
12 }

1  public class TestScoping {
2      public static void main(String[] args) {
3          ScopeExample scope = new ScopeExample();
4          scope.firstMethod();
5      }
6  }
Mainīgo redzamības apgabali

Mainīgo (noklusētā) inicializācija

byte
0 (šo vērtību uzstāda neinicializētam klases līmeņa mainīgajam ar tipu byte kā arī neinicializētam byte[] masīva elementam)
short
0
int
0
long
0L
float
0.0F
double
0.0D
char
''
boolean
false
Visi referenču tipi
null

Operatori

Atdalītājsimboli
. [] () ; ,

Tālāk uzskaitīti operatori sakārtoti pēc precedences (operatori, kuri "saista visciešāk", jeb kuriem ir visaugstākā precedence sarakstā doti pirmie).

++ -- + - ~ ! (data_type)
Asociativitāte "R to L" (t.i. pielietojot vairākus šos unāros operatorus, iekavas sāk likt no labās puses, piemēram, ++++x ir tas pats kas (++(++x))
* / %
L to R (asociativitāte no kreisās uz labo pusi, piemēram, x*y/z ir tas pats kas (x*y)/z
+ -
L to R
<< >> >>>
L to R
< > <= >= instanceof
L to R
== !=
L to R
&
L to R
^
L to R
|
L to R
&&
L to R
||
L to R
? :
R to L

= *= /= %= += -= <<= >>= >>>= &= ^= |= R to L

Ja ir zināma operatoru asociativitāte un precedence, ikvienā izteiksmē var atjaunot izlaistās iekavas. Piemēram, divas sekojošās izteiksmes ir identiskas:

a = b = d != null && d.day > 31
(a = (b = ((d != null) && (d.day > 31))))

Ievērojiet, ka piešķiršanas operators "=" ir labēji asociatīvs, t.i. ja nav saliktas iekavas, tad vispirms notiek piešķiršana mainīgajam "b" (kas izteiksmē atrodas pa labi) un tikai pēc tam mainīgajam "a" (kas atrodas pa kreisi).

Loģiskie operatori

boolean operatori
Operatora apzīmējumsNosaukums
!NOT-operators, negācija jeb NE-operators
|OR-operators, disjunkcija jeb VAI-operators
&AND-operators, konjunkcija jeb UN-operators
^XOR-operators jeb "izslēdzošā VAI"-operators
Īsslēguma (short-circuit) boolean operatori:]
Operatora apzīmējumsNosaukums
&&Īsslēguma AND operators
||Īsslēguma OR operators

Šos operatorus var lietot sekojoši:

MyDate d;
if ((d != null) && (d.day > 31)) {
    // apstrādā d
}
Bitveida loģiskie operatori

Veselo skaitļu bitveida (bitwise) operatori:

Operatora apzīmējumsNosaukums
~Bitveida negācija
^Bitveida XOR
&Bitveida AND
Bitveida OR

Piemēri 1 baita gadījumam:

Bitveida operatoru piemēri

Bitu nobīde pa labi: operatori >> un >>>

  • Aritmētiskā nobīde pa labi (arithmetic right shift) jeb nobīde pa labi ar zīmi (signed right shift) (>>) lietojams dalīšanai ar divnieka pakāpēm
  • Zīmes bitu nobīdes laikā kopē (negatīvie skaitļi pēc nobīdes joprojām paliek negatīvi)
  • 128 >> 1 ir 128/21 = 64 * 256 >> 4 ir 256/24 = 16 * -256 >> 4 ir -256/24 = -16

Loģiskā nobīde pa labi (logical right shift) jeb bezzīmes nobīde pa labi (unsigned right shift) ( >>> ) ir lietojams bitveida datu manipulācijām. Zīmes bits nobīdes laikā nekopējas (visi skaitļi pēc šādas nobīdes kļūst pozitīvi).

Bitu nobīde pa kreisi: operators <<

Nobīde pa kreisi (left shift) lietojama reizināšanai ar divnieka pakāpēm un bitu manipulācijām:

  • 128 << 1 ir 128 * 21 = 256 * 16 << 2 ir 16 * 22 = 64

Nobīdes operatoru piemēri

Nobīdes operatoru piemēri

Stringu konkatenācija ar +

  • Veic String konkatenāciju, ja kaut viens operands ir String objekts (ja nepieciešams, otro operandu automātiski pārveido par stringu)
  • Izveido jaunu String objektu
int vards = 9; 
Date d = new Date(); 
String s1 = "Vīrs" + " " + "un" + " ";
String s2 = s1 + "vārds=" + vards;    // int -> String konversija
String s3 = s2 + ", datums = " + d;   // java.util.Date -> String konversija
System.out.println(s3); 

Programmas rezultāts izskatās apmēram šādi:

Vīrs un vārds=9, datums = Sun Oct 27 15:00:21 EET 2002

Tipu pārveidošana

  • Ja piešķiršanas operatorā var zust informācija, programmētājam atklāti jāpieraksta piešķiršanas operatoram tipa pārveidojums
  • Piemēram, piešķiršana no long uz int prasa atklātu tipa pārveidojumu:
long bigValue = 99L;
int squashed = bigValue; // nepareizi, vajag pārveidot
int squashed = (int) bigValue; // pareizi

int squashed = 99L; // nepareizi, vajag pārveidot
int squashed = (int) 99L; // pareizi, bet parasti tā neraksta
int squashed = 99;   // pareizi (vesela skaitļa literālis ir ar tipu "int")

Izteiksmju tipu paplašināšana un pārveidošana

  • Mainīgos, ja nepieciešams, automātiski pārveido uz garāku formu (piemēram, no int uz long).
  • Izteiksme ir piešķiršanā saderīga (assignment-compatible), ja mainīgā tips izteiksmes kreisajā pusē ir vismaz tikpat liels (bitu skaits), kā izteiksmes tips labajā pusē
long bigval = 6;        // 6 ir "int", pareizi
int smallval = 99L;  // 99L ir "long", nepareizi

double z = 12.414F;    // 12.414F ir "float", pareizi
float z1 = 12.414;      // 12.414 ir "double", nepareizi

Piemērs, kad tipa paplašinājums var novest pie informācijas zuduma ir "long"->"float" pārveidojums. Sekojoša diagramma parāda visus tos vienkāršo tipu pārveidojumus, kuri ir "tipu paplašinājumi", t.i., kuri notiek bez atklāti uzrakstīta pārveidojuma. (Šāda pārveidojamība ir transitīva, t.i. "int" uzreiz var pārveidoties par "double", bez "long" vai "float" starpstadijas.)

Tipu paplašināšanas grafs

Zarošanās komandas

Vienkāršās zarošanās (if,else) komandas sintakse:

if (boolean expression) {
       statement or block;   
}
if (boolean expression) {
    statement or block;  
} 
else if (boolean expression) {
    statement or block; 
} 
else {
    statement or block;
}

Zarošanās komandas

if, else komandas piemērs

int count;
count = getCount();    // šajā pašā klasē definēta metode
if (count < 0) {
       System.out.println("Kļūda: 'count' vērtība ir negatīva.");
} else if (count > getMaxCount()) {
    System.out.println("Kļūda: 'count' vērtība ir pārāk liela.");
} else {
       System.out.println("Uz šīsdienas pusdienām nāks " + count +
                                             " cilvēki.");
}

Zarošanās komandas

Parametriskās zarošanās (switch) komandas sintakse:

switch (expr1) {
     case constant2:
          statements;
          break;
     case constant3:
          statements;
          break;
     default:
          statements;
          break;
}

Zarošanās komandas

switch komandas piemērs:

switch ( carModel ) {
    case DELUXE:
        addAirConditioning();
        addRadio();
        addWheels();
        addEngine();
        break;
    case STANDARD:
        addRadio();
        addWheels();
        addEngine();
        break;
    default:
        addWheels();
        addEngine();
}

Zarošanās komandas

Komanda "break" katra "case" beigās reizēm šķiet traucējoša un pat bīstama (ja to aizmirst ierakstīt, vadība pāriet uz nākamo case). Aplūkosim piemēru, kur izpildāmās darbības starp vairākiem "case" daļēji pārklājas (tad "break" komandu mēdz būt izdevīgi nerakstīt).

switch ( carModel ) {
    case THE_WORKS:
        addGoldPackage();
        add7WayAdjustableSeats();
    case DELUXE:
        addFloorMats();
        addAirConditioning();
    case STANDARD:
        addRadio();
        addDefroster();
    default:
        addWheels();
        addEngine();
}

Ciklu komandas

for cikls:

for (init_expr; boolean testexpr; alter_expr) {
    statement or block;
}

Piemērs:

for (int i = 0; i < 10; i++) {
       System.out.println("Are you finished yet?");
}
System.out.println("Finally!");

Ciklu komandas

while cikls:

while (boolean) {
    statement or block;
}

Piemērs:

int i = 0;

while (i < 10) {
     System.out.println("Are you finished yet?");
     i++;
}
System.out.println("Done");

Ciklu komandas

do/while cikls:

do {
    statement or block;
} while (boolean test);

Piemērs:

int i = 0;

do {
     System.out.println("Are you finished yet?");
     i++;
} while (i < 10);
System.out.println("Done");

Cikla vadības plūsmas maiņa

  • break [label]; * continue [label]; *
    label: statement;  // statement apzīmē ciklu (citādi uz iezīmi pārlekt nevar)
    

Javas sintakse ļauj iezīmi uzlikt jebkurai programmas rindiņai, bet aizlēkt var tikai uz iezīmēm, kuras raksta cikla sākumā. "continue" lec uz attiecīgā cikla sākumu, bet "break" - uz komandu tieši aiz attiecīgā cikla beigām.

Cikla vadības plūsmas maiņa

break komanda:

do {
    statement;
        if (condition is true) {
        break;
    }
    statement;
} while (boolean expression);

Cikla vadības plūsmas maiņa

continue komanda:

do {
    statement;
    if (boolean expression) {
        continue;
    }
    statement;
} while (boolean expression);

Cikla vadības plūsmas maiņa

break komanda ar iezīmēm:

outer: do {
        statement;
                do {
            statement;
                        if (boolean expression) {
                break outer;
                        }
            statement;
                } while (boolean expression);
        statement;
} while (boolean expression);

Cikla vadības plūsmas maiņa

continue komanda ar iezīmēm:

test: do {
    statement;
        do {
        statement;
                if (condition is true) {
            continue test;
        }
        statement;
    } while (condition is true);
    statement;
} while (condition is true);

Jautājumi paškontrolei

  • Atšķirt instanču un lokālos mainīgos
  • Aprakstīt, kā inicializē instanču mainīgos
  • Prast izlabot kompilatora kļūdu Possible reference before assignment
  • Atpazīt, aprakstīt un lietot Javas operatorus
  • Atšķirt pareizas un nepareizas vienkāršo tipu piešķiršanas komandas

Jautājumi paškontrolei

  • Prast atrast boolean izteiksmes, t.sk. vadības plūsmas konstrukcijās
  • Prast ierakstīt nepieciešamos vienkāršo tipu pārveidojumus
  • Lietot if, switch, for, while un do, kā arī break un continue komandas ar iezīmēm.

Diskusiju tēmas

  • Kādus datu tipus vairums programmēšanas valodu lieto, lai grupētu līdzīgus datu elementus?
  • Kā uz visiem vienas grupas (piemēram, matricas) elementiem var veikt vienu un to pašu operāciju?
  • Kurus datu tipus lieto programmēšanas valoda Java?