Blakusefekti

Javā tāpat kā citās imperatīvajās programmēšanas valodās, izteiksmes aprēķina mazliet savādāk nekā tradicionālajā matemātikā, t.i. izteiksmju izpildes gaitā jārēķinās, ka mainīgie var iegūt jaunas vērtības pat vienas formulas robežās. Šādas parādības sauc par blakusefektiem (side-effects). Aprakstīsim svarīgākās situācijas, kad Javā rodas blakusefekti.

Operandu aprēķināšanas secība

Izteiksmei vispirms rēķina operandus no kreisās uz labo pusi, pēc tam izpilda operāciju saskaņā ar tās precedenci un asociativitāti.

int[] a = { 0, 0 }; 
int b = 0; 
a[b] = b = 1; 

Trešajā rindiņā vispirms izrēķinām a[b], kurš ir masīva 0-tais elements: a[0], abi pārējie operandi (b un 1) jau ir izrēķināti. Visas darbības šajā fāzē veicam no kreisās uz labo pusi.

Pēc tam veicam piešķiršanas no labās uz kreiso pusi, t.i. vispirms b kļūst 1, bet pēc tam arī a[0] kļūst 1, jo izteiksmei b=1 arī ir vērtība 1.

Pirmspalielināšana un pēcpalielināšana

int a=3;
int b=a++; // sufiksa palielināšana notiek pēc izteiksmes aprēķināšanas, 
           // t.i. beigās b ir 3, un a ir 4. 
int c = 3; 
int d = ++c; // gan c, gan d ir 4. 

Sarežģītāki piemēri:

int a = 3; 
int b = a++ + a++; // a ir 5 un b ir 7
int c = 3; 
int d = 2*c++; // c ir 4 un d ir 6
int[] m = {0, 0, 0, 0}; 
int a = 1; 
m[a++] += a++; // a ir 3 un m ir {0, 2, 0, 0}

Vai šajā piemērā 3. rindiņā saskaitāmos drīkst mainīt vietām tā, lai izteiksmes vērtība nemainītos?

int[] m = {0,1,2,3}; 
int a = 1;
m[a++] = m[a++]++ + m[a++]; // a ir 4 un m ir {0,5,3,3}

Būla izteiksmju "short-circuit" rēķināšana

Būla izteiksmju izskaitļošanā bieži pietiek zināt tikai vienu argumentu. Tā kā false && x ir false un true || x ir true neatkarīgi no tā, kāds ir x, tad Javā šajās situācijās apakšizteiksmi x vispār nerēķina. Šādai situācijai ir praktiski pielietojumi programmēšanā, piemēram,

// funkcija atgriež stringa pirmo burtu vai arī tukšumu, ja stringam nav pirmā burta
int pirmais_burts(String s) {
    if (s == null || s.equals("")) return ' '; 
	return s.charAt(0); 
}

Šajā piemērā metodes izsaukumss.equals("") beigtos beediigi tajos gadiijumos, kad s ir null. Par laimi, saīsinātās rēķināšanas ("short-circuit") dēļ, šis izsaukums nekad nenotiek tad, kad s ir null. Pievērsiet uzmanību arī tam, ka null (nedefinēts) strings un tukšs strings ir divas dažādas lietas un par šiem gadījumiem ir jādomā atsevišķi. Apskatīsim citu - nejaukāku piemēru:

int i = 1; 
int j = i++; 
if ((j+2 > ++i) && ((i += j) <= 4))) {
    i += 4; 
}
System.out.println("i=" + i); 

Ja kāds nodomātu, ka loģisko konjunkciju 3. rindiņā var izrēķināt tikai pēc tam, kad ir izrēķinātas abas apakšizteiksmes, tad sanāktu, ka pēc izteiksmes (j+2 > ++i) izrēķināšanas i kļūst vienāds ar 3, bet pēc izteiksmes ((i += j) <= 4) izrēķināšanas i ir jau 4. Tomēr patiesībā šī pēdējā izteiksme nemaz netiek rēķināta. Tāpēc programma izdrukā "i=3".

Piemēri

  1. Kāda ir šīs programmas izvade?
    /** 
     * Izteiksmees visas apakshizteiksmes vispirms izreekjina
     * virzienaa no kreisaas puses uz labo, peec tam izpilda
     * darbiibas atkariibaa no darbiibu precedences/asociativitaates. 
     * Pieshkjirshana piemeeram ir labeeji asociatiiva. 
     */ 
    
    public class Expressions {
        public static void main(String[] args) {
            int[] a = { 1, 1, 1, 1, 1, 1, 1, 1}; 
            int[] b = { 1, 1, 1, 1, 1, 1, 1, 1}; 
    		int x = 0; 
    		int y = 0; 
    		a[x++] = a[x++] = x = 3;
    		b[++y] = b[++y] = y = 5;
    		for (int i=0; i < a.length ; i++) {
    			System.out.println("a[" + i + "]=" + a[i] + "; " + "b[" + i + "]=" + b[i]); 
    		}
    		System.out.println("x = " + x + ", y = " + y); 
    	}
    }
    

Lapa mainīta 2004-11-15 22:38:12