Sunteți pe pagina 1din 11

În programare, deseori trebuie să se repete de câteva ori acelaşi bloc

de comenzi. Această repetare se face prin folosirea buclelor. Java are


trei construcţii de bucle.

for,
while,
do-while

Bucla For

Bucla for se foloseşte atunci când ştim în prealabil cu exactitate de


câte ori trebuie să se execute un bloc de comenzi. Această buclă are
următoarea sintaxă:

for (counter initialization; condition; increment counter) {


conditional code;
}

Primul parametru se foloseşte pentru a crea şi pentru a seta valoarea


iniţială a numărătorului (counter). Al doilea parametru conţine condiţia
pentru numărător - condition (adică până la ce valoare a numărătorului
bucla va fi activă), iar al treilea determină în ce fel se modifică
numărătorul (care este pasul de creştere şi descreştere).
Imaginea 13.1 Bucla For

Următorul exemplu de cod scrie mesajul de bun venit de 4 ori:

for (int counter=1;counter<5;counter++) {


System.out.println("Welcome!");}

În primul rând se declară variabila counter, apoi aceasta se


iniţializează fiind setată la 1. Al doilea parametru conţine condiţia
(counter <5). Blocul de comenzi se va executa atâta timp cât această
condiţie este adevărată, iar condiţia va fi adevărată atâta timp cât
variabila counter este mai mică decât 5. Al treilea parametru măreşte
variabila counter cu unu (counter ++) la fiecare trecere prin buclă.

Numărătorul are o semnificaţie multiplă în buclă. Aceasta este, în


primul rând, unicul mod în care controlăm numărul de executări ale
unui bloc în buclă. Însă, pe lângă aceasta, la fiecare iteraţie a buclei,
numărătorul ne expune valoarea sa pe care o putem folosi. După
terminarea buclei, se încheie existenţa variabilei definite ca numărător
al buclei (dacă am declarat-o în interiorul definiţiei buclei).

Următorul exemplu va afişa numerele de la 0 la 4.

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


System.out.println(counter);
}

Valoarea numărătorului se poate mări sau micşora şi în alte moduri:

for (int counter=0;counter<5;counter+=2) {


System.out.println(counter);
}

În codul de mai sus, cu ocazia fiecărei treceri prin buclă, am efectuat


mărirea numărătorului cu 2, astfel încât la ieşire vom obţine:

0
2
4

Însă, dacă după acest bloc mai adăugăm o linie în care prezentăm
valoarea variabilei counter, se va produce o eroare pentru că variabila
counter a fost declarată şi iniţializată în interiorul buclei.

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


System.out.println(counter);
}
System.out.println(counter);

Dacă dorim să avem un numărător disponibil pentru utilizare şi după


executarea buclei, acest lucru trebuie declarat mai devreme, în afara
definiţiei buclei:
int counter;
for (counter=0;counter<5;counter++) {
System.out.println(counter);
}
System.out.println(counter);

Acest exemplu nu va semnala nicio eroare şi va afişa numerele de la 0


la 5. Poate părea ciudat faptul că, la sfârşit, valoarea variabilei counter
va fi 5, dar este în totalitate logic. Corpul buclei se execută atâta timp
cât valoarea variabilei counter este mai mică decât 5. Dacă am merge
iteraţie cu iteraţie prin buclă, valoarea numărătorului, bucla şi
programul însuşi ar avea următoarea viaţă: bucla s-ar executa de 5 ori,
de atâtea ori de câte se va îndeplini condiţia. La final, valoarea se va
mări cu unu (şi vom obţine valoarea 5), prin care condiţia nu se va mai
îndeplini. Ca rezultat, bucla va fi părăsită, dar valoarea numărătorului
va rămâne în continuare 5. De aceea, după bucla executată astfel,
obţinem valoarea numărătorului 5.

Buclele for se folosesc frecvent pentru trecerea prin şiruri.

De exemplu:

String[] colors = {"red" , "green" , "blue" , "yellow" , "white"};

for (int i = 0; i < colors.length; i++)


{
System.out.println("Color of element " + i + " is " + colors[i] + ".");
}

Şirul creat mai sus are cinci elemente. Indecşii elementelor sunt de la 0
la 4. De aceea, în condiţie se foloseşte inegalitate strictă pentru ca
programul să nu încerce să acceseze elementul cu indexul 5, care nu
există.

Ştim că există trei părţi la iniţializarea buclei for. În exemplele


precedente, fiecare parte a avut câte un parametru, dar aceasta nu
este o structură obligatorie. Uneori, pentru o singură iniţializare, putem
defini mai mulţi parametri.

Bucla următoare va iniţializa variabilele „i“ şi „a“ şi le va atribui valori


diferite. Apoi, se pune condiţia ca „i“ să fie mai mic decât 10, iar apoi,
se intervine la ambele valori, mărindu-le cu unu:

int i;
int a;
for(i=0,a=5;i<10;i++,a++)
System.out.println(i + ":" + a);

Bucla for va funcţiona chiar dacă nu sunt introduşi toţi cei trei
parametri. Următorul exemplu va fi, de asemenea, valid:

for(int i=0;i<10;) System.out.println(i++);

În acest exemplu, cel de-al treilea parametru a fost omis. De fapt, nu


este omis, ci rămâne complet vid, lucru pe care ni-l indică marcajul ;
aflat după numărul 10.

După o astfel de iniţializare, am făcut incrementarea în cadrul blocului,


ceea ce poate fi foarte periculos. Dacă lipseşte incrementul, putem
cădea într-o aşa-numită buclă moartă (bucla care se execută la infinit)
şi care, în cel mai bun caz, va bloca mediul.

În general, trebuie să ne ferim de buclele moarte, pentru că există


diferite moduri în care o putem produce. Pur şi simplu, aveţi grija ca
bucla dvs. să nu arate astfel încât condiţiile executării ei să se poată
îndeplini întotdeauna.

De exemplu:

for(int i=1;i>0;) System.out.println(i++);

În codul de sus a fost creată o buclă moartă, deoarece condiția este ca


variabila să fie mai mare decât 0, iar această condiție va fi îndeplinită
întotdeauna. La ieșire vor fi scriese numerele pe rând până când
programul va fi întrerupt într-un mod "violent".

Observăm că cele două exemple precedente au fost scrise într-o


singură linie, aceasta datorită aceleiaşi reguli care este valabilă şi
pentru toate celelalte structuri de control al fluxului. După condiţie se
poate scrie doar o singură linie de cod fără paranteze. Dacă doriţi să
scrieţi un bloc (două sau mai multe linii), trebuie să puneţi întregul bloc
între paranteze acolade.

Acordaţi atenţie faptului că în exemplul următor valoarea


numărătorului va rămâne şi după executarea buclei.

int i = 0;
for(i=0;i<10;i++)
System.out.println(i);

Valoarea variabilei „i“ va fi 10 şi după executarea buclei. De aceea,


trebuie să respectăm denumirile standard variabilelor, care se vor
folosi doar cu acest scop. De exemplu, însăşi litera i. Astfel vom şti
întotdeauna că litera respectivă este rezervată pentru buclă şi nu o
vom folosi pentru variabilele curente. Bineînţeles că acesta este doar
un sfat. Pentru denumirea variabilelor în bucle sunt valabile aceleaşi
reguli ca şi pentru denumirea tuturor celorlalte variabile din Java.

Buclele for pot fi imbricate una în alta. În practică, veţi vedea că


programele mai mari sunt formate tocmai din bucle aflate în nişte
bucle mai mari şi care, la rândul lor, se află în bucle şi mai mari. Când
începeţi să creaţi singuri structuri mai complexe (cu bucle imbricate),
aveţi grijă la ordinea executării lor. Nu uitaţi că programul dvs., oricât
de complex ar fi, se execută secvenţial. Dacă, în orice moment, iniţiaţi
un proces, toate celelalte procese se vor opri până când procesul
respectiv se va termina (fireşte, regula aceasta nu este valabilă pentru
programarea în timp real şi pentru programarea multitasking):

for(int i=0;i<10;i++)
for(int u=0;u<10;u++)
System.out.println(u);

În mod clar, acest exemplu va scrie variabila „u“ de 100 de ori. Însă,
cât va fi variabila i în fiecare moment al execuţiei?

Deoarece bucla „i“ este o buclă externă, iar bucla „u“ se execută în
interiorul ei, de fiecare dată când se face o iteraţie a buclei „i“, se va
face şi ciclul complet al buclei „u“:

prima iteraţie a buclei i


prima iteraţie a buclei u
a doua iteraţie a buclei u
...
a zecea iteraţie a buclei u
a doua iteraţie a buclei i
....

şi aşa mai departe până la ultima iteraţie a buclei “ i“ când întregul său
ciclu se va termina.

La începutul buclei am menţionat că numărătorul buclei se "măreşte".


Aceasta nu este o regulă obligatorie. Numărătorul se poate micşora
sau poate chiar să nu existe deloc (cum am văzut într-unul dintre
exemplele precedente).

for(i=10;i>0;i--) System.out.println(i);

Bucla foreach

Bucla aceasta este o variaţie a buclei for, menită exclusiv lucrului cu


şiruri şi colecţii. Pentru că încă nu ne-am familiarizat cu termenul de
colecţie, vom vedea utilizarea acestei construcţii pe un exemplu cu
şiruri.

Foreach funcţionează foarte simplu (din punctul de vedere al


utilizatorului), deoarece, practic, nu trebuie să ştim nimic despre şirul
prin care dorim să trecem, în afară de numele lui. La iniţializare,
introducem numele şirului şi numele variabilei pentru care dorim să
preluăm valoarea actuală a şirului la fiecare iteraţie:

int[] arr = {1,2,3,4,5};


for(int val: arr )
System.out.println(val);

În acest exemplu, se trece prin şir şi, la fiecare iteraţie, valoarea


elementului curent se stochează în variabila valoare. Variabila aceasta
se poate folosi în blocul de comenzi fără a schimba valoarea originală
conţinută în elementul curent al şirului.

Priviţi exemplul următor:

int[] numbers = {3, 5, 9};


System.out.println("Numbers in this array are: ");
for (int number : numbers) {
System.out.println(number);
}

La fiecare trecere prin buclă, valoarea elementului curent este scrisă la


ieşire. La sfârşit, rezultatul va fi:

Numbers in this array are:


3
5
9

După cum vedeţi, foreach operează destul de automatizat. Acest lucru


este bine uneori, dar alteori este problematic, fiindcă atunci când
lucrăm cu foreach, nu gestionăm membrii şirului explicit prin indecşii
lor, ci obţinem doar valorile lor. Astfel, putem spune că foreach este
utilă atunci când dorim o citire rapidă şi simplă a unui şir, dar nu şi
pentru orice intervenţie mai serioasă asupra acestuia.

Deşi, în exemplele de până acum, fiecare buclă foreach precedă blocul


cu paranteze acolade, şi aici este valabilă regula conform căreia nu
trebuie neapărat să existe paranteze acolade pentru o singură linie de
cod. Astfel, bucla for din exemplul anterior o putem scrie astfel:

for (int number : numbers) System.out.println(number);

Controlul de flux al buclei

Controlul de flux al buclei se poate face în câteva moduri. Primul mod


este, desigur, prin modificarea manuală a variabilei de control (a
numărătorului).

for(int i=0;i<10;i++)
{
if(i>5) i=10;
System.out.println(i);
}

În acest exemplu, i-am "spus" buclei să se execute atâta timp cât


variabila "i" este mai mică decât 10, cu increment 1 la fiecare iteraţie.
Apoi, în bloc, ne-am "răzgândit" şi i-am spus că, dacă numărătorul este
mai mare decât 5 (deci, 6), numărătorul obţine valoarea 10. Fiindcă
numărătorul a obţinut valoarea prin care bucla nu mai îndeplineşte
condiţiile de executare, bucla este părăsită. Soluţia aceasta va
funcţiona, dar este neîndemânatică, pentru că trebuie să cunoaştem
valoarea ţintită a numărătorului, ceea ce deseori nu va fi posibil.

Celălalt mod (modul corect) este prin folosirea cuvântului cheie Break.
Am cunoscut acest cuvânt în lecţia precedentă, când am spus că
acesta opreşte necondiţionat blocul de cod:

for(int i=0;i<10;i++)
{
if(i>5) break;
System.out.println(i);
}
Prin folosirea acestui cuvânt cheie, bucla noastră nu a pierdut prea
mult din dimensiuni, dar totuşi obţine multe din punctul de vedere al
dinamicii, pentru că acum nu mai trebuie să ştim valoarea finală a
buclei.

for(int i=0;i<10;i++)
{
System.out.print("\n" + i + ":");
for(int u=0;u<10;u++)
{
System.out.print(u);
if(u==5)
break;
}
}

Dacă pornim acest exemplu, se vor scrie zece rânduri, unde fiecare
dintre ele va conţine cifrele de la 0 la 5. Acest lucru este logic, pentru
că de fiecare dată când numărătorul iteraţiilor buclei interioare ajunge
la cinci, acesta se opreşte, în timp ce bucla exterioară continuă să
lucreze.

Însă, uneori se va întâmpla să dorim să setăm o condiţie în cursul


executării buclei, pentru care, atunci când se îndeplineşte, nu vom dori
să facem nicio iteraţie a buclei (fără a părăsi buclă). De exemplu, să ne
închipuim o imensă listă de oameni (câteva milioane). Toţi aceşti
oameni se află în baza de date şi noi dorim să separăm doar o anumită
grupare în care sunt incluşi doar profesori.

Să presupunem că citirea datelor despre profesia fiecărui membru al


listei durează o secundă şi citirea datelor complete despre membru
durează 5 secunde.

Acum să presupunem că procedura citirii subînţelege: citirea datelor


despre profesie, adresă, citirea numelui, citirea prenumelui etc. (ceea
ce, în total, durează 5 secunde). Dacă trecem prin întreaga procedură
pentru fiecare membru, vom pierde câte 5 secunde per membru şi
aceasta înseamnă foarte multe secunde pentru toţi membrii împreună.
Pe de altă parte, putem verifica imediat, la început, dacă membrul este
profesor (ceea ce necesită doar o secundă) şi, dacă nu este, vom
prelua imediat datele următorului membru din listă. Astfel vom
economisi 4 secunde. La o cifră de câteva milioane de membri, aceasta
reprezintă un număr imens de secunde.

Acest exemplu simplu funcţionează automat în mintea umană, dar


programul trebuie să aibă acest lucru accentuat explicit pentru a gândi
astfel. Această accentuare se face prin cuvântul cheie continue.

Aşa ar arăta pseudocodul exemplului menţionat, cu folosirea


cuvântului cheie continue:

for(member=0;member<1000000;member++)
{
if(member!="teacher")
continue;
// logic that reads data
//......
}

Dacă în exemplul de mai sus, în loc de comanda continue, am seta


comanda break, s-ar produce o întrerupere completă a buclei. Aceasta
este diferența dintre break și continue. Comanda continue trece
imediat la următoarea iterație a buclei, în timp ce comanda break
efectuează întreruperea completă a executării buclei și trece la codul
definit sub buclă.

Exemplul următor va afişa toate numerele în afara numărului cinci,


deoarece am accentuat explicit că, atunci când apare numărul 5, se
execută comanda continue, respectiv sărim peste această iteraţie a
buclei.

for(int i=0;i<10;i++)
{
if(i==5)
continue;
System.out.print(i);
}

S-ar putea să vă placă și