Sunteți pe pagina 1din 12

Laborator Programare Java Lucrarea nr.

LUCRAREA NR. 3
Structuri de date. Excepții.

1. Scopul lucrării

În prima parte a lucrării de laborator se va face o prezentare a structurilor de date în Java iar în a doua parte a
lucrării se vor prezenta exemple privind tratarea excepțiilor în Java.

2. Structuri de date

Vectorii – sunt utilizați pentru a stoca o secvență de valori de același tip. De exemplu, pentru a construi un
vector de 10 numere reale dublă precizie se va scrie:
new double [10]
Numărul de elemente (în exemplul dat acesta este 10) se numește lungimea vectorului. Operatorul new doar
construiește vectorul. Pentru a accesa vectorul va trebui să se stocheze într-o variabilă o referință la vectorul
respectiv:
double [ ] data = new double [10];
Astfel, data este o referință la un vector de 10 numere reale dublă precizie (Figura 1).

Figura 1. Referința la vector și vectorul Figura 2. Stocarea unei valori într-un vector

Când un vector este creat, toate valorile sunt inițializate cu 0 ( pentru un vector de tip int, double sau float),
țe). Fiecare element al vectorului este
false (pentru tipul boolean) sau null (pentru un vector de referin
specificat printr-un indice întreg scris între parantezele drepte [ ]. De exemplu, pentru a atribui o valoare
elementului cu indicele 2 al vectorului data (Figura 2), se va scrie:
Laborator Programare Java Lucrarea nr. 3

data[2] = 29.95;

Pentru a citi valoarea elementului de indice 2 din vectorul data, se poate scrie:
System.out.println ( “ Valoarea elementului de indice 2 din vector este” + data [2] );
Din Figura 2 se observă că primul element al vectorului este data[0] , iar ultimul element data[9] pentru cazul
particular prezentat. Dacă se încearcă accesarea unui element care nu există, se va arunca o excepție și
programul se va termina. De exemplu:
data[10] = 4.6; //EROARE- out of bounds index
Observați îmbunătățirea față de limbajele C și C++ care nu generează nici un mesaj de eroare în această
situație.
În Java, valorile indicilor unui vector sunt cuprinse între 0 și length-1. Accesarea unui element care nu există
este semnalată prin eroare. Cuvântul cheie length returnează numărul de elemente ale unui vector:
data.length reprezintă lungimea vectorului data. Lenght reprezintă un atribut (variabilă membru) al obiectului
vector, nu este o metodă. De asemenea, length este declarată final și public, prin urmare nu se poate atribui o
altă valoare acestei variabile.
Pentru a exemplifica modul de lucru cu vectori, se va prezenta în continuare un exemplu.

/*************************************************************************
* fișier Vector.java
*
* Programul implementează un vector de numere reale.
*
*
* Ieșirea programului este:
* x = 1.0 2.0 3.0 4.0
* y = 5.0 2.0 4.0 1.0
* z = 6.0 4.0 7.0 5.0
* 10z = 60.0 40.0 70.0 50.0
* |x| = 5.477225575051661
* <x, y> = 25.0
* dist(x,y)= 5.0990195135927845
* dir(x) = 0.18257418583505536 0.3651483716701107 0.5477225575051661 0.7302967433402214
*
* Obs! Vector este de asemenea numele unei clase din biblioteca Java.
*
*************************************************************************/

public class Vector {

private final int N; // lungimea vectorului


private double[] data; //

// constructor fără parametri


public Vector(int N) {
Laborator Programare Java Lucrarea nr. 3

this.N = N;
this.data = new double[N];
}

// constructor cu parametri
public Vector(double[] data) {
N = data.length;
this.data = new double[N];
for (int i = 0; i < N; i++)
this.data[i] = data[i];
}
// lungimea vectorului
public int length() {
return N;
}

// produsul scalar a doi vectori


public double dot(Vector that) {
if (this.N != that.N) throw new RuntimeException("Dimensions don't agree");
double sum = 0.0;
for (int i = 0; i < N; i++)
sum = sum + (this.data[i] * that.data[i]);
return sum;
}

// norma Euclidiană a vectorului


public double magnitude() {
return Math.sqrt(this.dot(this));
}

// distanța Euclidiană între doi vectori


public double distanceTo(Vector that) {
if (this.N != that.N) throw new RuntimeException("Dimensions don't agree");
return this.minus(that).magnitude();
}

// suma a doi vectori


public Vector plus(Vector that) {
if (this.N != that.N) throw new RuntimeException("Dimensions don't agree");
Vector c = new Vector(N);
for (int i = 0; i < N; i++)
c.data[i] = this.data[i] + that.data[i];
return c;
}

// diferența a doi vectori


public Vector minus(Vector that) {
if (this.N != that.N) throw new RuntimeException("Dimensions don't agree");
Vector c = new Vector(N);
for (int i = 0; i < N; i++)
c.data[i] = this.data[i] - that.data[i];
return c;
}

// coordonata corespunzătoare
public double cartesian(int i) {
Laborator Programare Java Lucrarea nr. 3

return data[i];
}

// înmulțirea vectorului cu un scalar


public Vector times(double factor) {
Vector c = new Vector(N);
for (int i = 0; i < N; i++)
c.data[i] = factor * data[i];
return c;
}

// vectorul unitate
public Vector direction() {
if (this.magnitude() == 0.0) throw new RuntimeException("Zero-vector has no
direction");
return this.times(1.0 / this.magnitude());
}

// reprezentarea ca șir de caractere a vectorului


public String toString() {
String s = "";
for (int i = 0; i < N; i++)
s = s + data[i] + " ";
return s;
}

// test vector
public static void main(String[] args) {
double[] xdata = { 1.0, 2.0, 3.0, 4.0 };
double[] ydata = { 5.0, 2.0, 4.0, 1.0 };
Vector x = new Vector(xdata);
Vector y = new Vector(ydata);

System.out.println(" x = " + x);


System.out.println(" y = " + y);

Vector z = x.plus(y);
System.out.println(" z = " + z);

z = z.times(10.0);
System.out.println(" 10z = " + z);

System.out.println(" |x| = " + x.magnitude());


System.out.println(" <x, y> = " + x.dot(y));
System.out.println("dist(x, y) = " + x.distanceTo(y));
System.out.println("dir(x) = " + x.direction());

}
}

Vectorii pot stoca elemente primitive ( variabile de tip byte, int, char etc.) sau referințe de obiecte , ca în
următorul exemplu:
Laborator Programare Java Lucrarea nr. 3

class Cărți {
String titlu;
String autor;
}
class TestCărți {
public static void main ( String [ ] args ) {
Cărți [ ] cărțileMele= new Cărți [3]; // crearea unui vector de tip Cărți
cărțileMele[0]= new Cărți ( ); // crearea unui obiect Cărți
cărțileMele[1]= new Cărți ( );
cărțileMele[2]= new Cărți ( );
cărțileMele[0].titlu= “Thinking in Java”; // accesul la obiectele Cărți folosind referințe din vector
cărțileMele[0].autor= “Bruce Eckel”;

}
}

În exemplu prezentat s-au folosit obiecte ale clasei String. Această clasă se găsește în pachetul java.lang.
Este o clasă utilă și des folostă în Java pentru lucrul cu șiruri de caractere.
Vectorii au următoarea limitare: lungimea lor este fixă, aceasta nu poate fi modificată pe parcursul utilizării
vectorului.
Dacă se dorește redimensionarea vectorului, o soluție este de a realoca un nou vector, mai mare și apoi să se
copie elementele vectorului inițial în noul vector folosind o buclă for sau metoda System.arraycopy( ) care
este mai rapidă. Metoda arraycopy(Object src, int srcPos, Object dest, int destPos, int length) copie
elementele din vectorul src în vectorul dest; se copie un număr de length elemente începând de la poziţia
srcPos din vectorul sursă în vectorul destinaţie începând de la poziţia destPos. Dacă src sau dest sunt null,
metoda arraycopy() va arunca o excepţie NullPointerException. Dacă src sau dest sunt vectori de tipuri de
date diferite, metoda arraycopy() va arunca o excepţie ArrayStoreException. Exemplu utilizare arraycopy() :
char[ ] litereHexaSrc = { ‘A’, ‘B’, ‘C’, ‘D’, ‘E’, ‘F’ };
char[ ] litereHexaDest = new char [litereHexaSrc.length];
System.arraycopy( litereHexaSrc, 0, litereHexaDest, 0, litereHexaSrc.length );

Însă această tehnică de copiere este acceptabilă doar în cazul structurilor simple. Pentru date cu o structură
mai complexă, este recomandată o abordare mai dinamică. Solu
ția în acest ca z este folosirea clasei Vector
sau a clasei ArrayList din pachetul java.util.
ArrayList este de fapt o colecție, adică un obiect care grupează mai multe elemente într -o singură unitate.
Prin colecții avem acces la tipuri de date cum ar fi vectori, mulțimi , tabele de dispersie etc. Colec
țiile sunt
folosite pentru memorareași manipularea datelor și pentru transmiterea datelor de la o metodă la alta.
Colecţiile Java vor fi detaliate în următoarea lucrare de laborator.

3. Tratarea excepţiilor în Java


Laborator Programare Java Lucrarea nr. 3

Excepțiile reprezintă evenimente neașteptate, anormale sau situații excepționale care pot apare î n timpul
execuției unui program, cum ar fi: împărțirea la zero (ArithmeticException), radical de ordinul doi dintr-un
număr negativ, accesarea unui element din afara spațiului alocat unui vector
(ArrayIndexOutOfBoundsException), inversa unei matrici singulare, scoaterea unui element dintr-o stivă
goală, încercarea de a accesa un membru al unui obiect printr-o referință nulă (NullPointerException) etc.
Java implementează un mecanism eficient de lucru cu excep
țiile, care permite programatorului să preia
controlul programului în momentul în care apare o excepţie şi să o trateze.
ții programatorul trebuie să creeze un obiect care să conțină informații despre
În aceste situa excepția
respectivă și să -l “arunce” utilizând cuvântul cheie throw. Odată aruncat, obiectul excep
ție este preluat de
mașina Java care va căuta în program secvența de cod (exception handler) care să se ocupe de tratarea
excepției.
O metodă care poate genera o excepție trebuie să specifice acest lucru în declarația metodei , utilizând
cuvântul cheie throws urmat de tipul excepției.
Tratarea excepțiilor se realizează prin intermediul blocurilor try-catch- finally.
Forma generală este:
try {
//instrucţiuni ce pot declanşa excepţii
}
catch(TipExcepție obiectExcepție) {
// instrucţiuni de tratare a excepţiei de clasă TipExcep ție
}
finally {
//instrucţiuni care se execută necondiţionat la sfârşit
}
Blocul try conține secvența de cod care poate genera o excepție. La apariția unei excepții execuția secvenței
din acest bloc este oprită și se caută blocul catch corespunzător pentru tratarea excepției respective. În cazul
în care la execuție nu apare nici o excepție, secvența de cod din blocul try se execută până la capăt după care
se trece la execuția secvenței din blocul finally (dacă acesta este prezent)și apoi se va ieși din try-catch-
finally.
Corespunzător unui bloc try pot exista mai multe blocuri catch. Secvența de cod din blocul finally se execută
indiferent dacă apare sau nu o excepție.
În continuare sunt date câteva exemple pentru a ilustra modul de lucru cu excepţii în limbajul Java.
Deoarece în exemplele prezentate s-a folosit clasa Scanner, mai jos este descrisă pe scurt această clasă.
Laborator Programare Java Lucrarea nr. 3

Clasa Scanner permite formatarea unor date primite pe un stream de intrare.


Pentru a avea utiliza clasa Scanner, aceasta trebuie importată în proiect folosind instrucțiunea import:
import java.util.Scanner;
Pentru citirea datelor de la tastatură se construiește un obiect de tip Scanner folosind constructorul care are
ca parametru obiectul System.in.
Scanner tastatura = new Scanner(System.in);
De exemplu pentru citirea datelor ce vor fi memorate într‐o variabilă String se scrie:
String nume = tastatura.nextLine( );

Pentru citirea datelor ce vor fi memorate într‐o variabilă de tip întreg se poate scrie:
int numar = tastatura.nextInt( );

Exemplul 1.
//****************************************************************
//Exceptii1.java
//
//Citeste un cuvant de la tastatura si afiseaza numarul de aparitii a fiecarei litere
//din cuvantul introdus
//
//****************************************************************

import java.util.Scanner;
public class Exceptii1
{
public static void main(String[] args)
{
int[] counts = new int[26];
Scanner scan = new Scanner(System.in);

//citire cuvant
System.out.print("Introduceti un cuvant: ");
String word = scan.nextLine();

// conversie litere mici in litere mari


word = word.toUpperCase();

//calculul numarului de aparitii a fiecarei litere din cuvantul introdus


for (int i=0; i < word.length(); i++)
counts[word.charAt(i)-'A']++;

//afisare numar aparitii


System.out.println();
for (int i=0; i < counts.length; i++)
if (counts [i] != 0)
System.out.println((char)(i +'A') + ": " + counts[i]);
scan.close();
Laborator Programare Java Lucrarea nr. 3

Ieşirea programului Exceptii1.java:


Introduceti un cuvant: Abracadabra

A: 5
B: 2
C: 1
D: 1
R: 2
sau
Introduceti un cuvant: Abra cadabra
Exception in thread "main" java.lang.ArrayIndexOutOfBoundsException: -33
at iola.Exceptii1.main(Exceptii1.java:29)
Explicați de ce în cazul introducerii sirului “Abra cadabra” se aruncă o excep
ție
ArrayIndexOutOfBoundsException. Modificați programul astfel încât să se ignore caracterele care nu sunt
litere, fără a se întrerupe execuția buclei for în cazul aruncării excepției.

Exemplul 2.

//****************************************************************
//Exceptii2.java
//
//Citeste o succesiune de numere intregi si afiseaza suma acestora
//
//****************************************************************

import java.util.Scanner;

public class Exceptii2


{
public static void main(String[] args)
{
int val, sum=0;
Scanner scan = new Scanner(System.in);

System.out.println("Introduceti un text ce contine o succesiune de numere intregi");


Scanner scanLine = new Scanner(scan.nextLine());

while (scanLine.hasNext())
{
val = Integer.parseInt(scanLine.next());
sum += val;
}
System.out.println("Suma intregilor introdusi este " + sum);
Laborator Programare Java Lucrarea nr. 3

scan.close();
scanLine.close();
}

Ieşirea programului Exceptii2.java:


Introduceti un text ce contine o succesiune de numere intregi
23 344 -34 92 10 -122
Suma intregilor introdusi este 313
sau
Introduceti un text ce contine o succesiune de numere intregi
23 -4 99 f 12 # 100 ab
Exception in thread "main" java.lang.NumberFormatException: For input string: "f"
at java.lang.NumberFormatException.forInputString(Unknown Source)
at java.lang.Integer.parseInt(Unknown Source)
at java.lang.Integer.parseInt(Unknown Source)
at laborator1.Exceptii1.main(Exceptii2.java:25)

Modificaţi programul Exceptii2.java, adăugând o declaraţie try care va curpinde toată bucla while şi “trataţi”
excepţia NumberFormatException într-un bloc catch. Observaţi ce se întâmplă dacă introduceţi un text ce
conţine atât numere întregi cât şi alte caractere. Execuţia buclei while se va opri în momentul în care este
aruncată o excepţie. Ce modificare trebuie făcută astfel încât atunci când este aruncată o excepţie să se
proceseze întregul text introdus, fără a se încheia execuţia buclei while, ca mai jos:
Introduceti un text ce contine o succesiune de numere intregi
Pe birou sunt 5 caiete, 2 carti si 3 pixuri.
Suma intregilor introdusi este 10

Exemplul 3.

//****************************************************************
//Exceptii3.java
//
//Citeste numere intregi de la tastaura si afiseaza factorialul acestora
//
//****************************************************************

import java.util.Scanner;

public class Exceptii3


{
public static void main(String[] args)
{
String continuare = "d";
Scanner scan = new Scanner(System.in);
Laborator Programare Java Lucrarea nr. 3

while (continuare.equals("d") || continuare.equals("D"))


{
System.out.print("Introduceti un numar intreg: ");
int val = scan.nextInt();
System.out.println("Factorial(" + val + ") = "
+ MathUtils.factorial(val));
System.out.print("Doriti sa continuati? (d/n) ");
continuare = scan.next();
}
scan.close();
}
}

//****************************************************************
//MathUtils.java
//
//aceasta clasa contine o metoda pentru calculul factorialului
//
//****************************************************************
public class MathUtils
{
//-------------------------------------------------------------
// Returneaza factorialul numarului dat ca parametru
//-------------------------------------------------------------
public static int factorial(int n)
{
int fac = 1;
for (int i=n; i>0; i--)
fac *= i;
return fac;
}
}

Ieşirea programului Exceptii3.java:

Introduceti un numar intreg:


5
Factorial(5) = 120
Doriti sa continuati? (d/n) d
Introduceti un numar intreg: 8
Factorial(8) = 40320
Doriti sa continuati? (d/n) n

sau

Introduceti un numar intreg: 3


Factorial(3) = 6
Doriti sa continuati? (d/n) d
Laborator Programare Java Lucrarea nr. 3

Introduceti un numar intreg: -5


Factorial(-5) = 1
Doriti sa continuati? (d/n) d
Introduceti un numar intreg: -3
Factorial(-3) = 1
Doriti sa continuati? (d/n) n

sau

Introduceti un numar intreg: 10


Factorial(10) = 3628800
Doriti sa continuati? (d/n) d
Introduceti un numar intreg: 16
Factorial(16) = 2004189184
Doriti sa continuati? (d/n) d
Introduceti un numar intreg: 17
Factorial(17) = -288522240
Doriti sa continuati? (d/n)

Observați că în cazul introducerii unui număr negativ, se afișează valoarea 1. De asemenea, se observă că
pentru numere mai mari decât 16, se afișează un număr negativ. Modificați programul astfel încât să corectați
aceste rezultate ale execuției programului. Folosiți un bloc try-catch, pentru a trata eroarea de tipul
IllegalArgumentException.

4. Implementarea unei stive de obiecte

public class StackOfObjects {


private Node prim; // varful stivei

//lista inlantuita
private class Node {
private Object obj;
private Node next;
}

// crearea unei stive goale


public StackOfObjects() {
prim = null;
}

// verifica daca stiva este goala


public boolean isEmpty() { return (prim == null); }

// adauga un element in stiva


public void push(Object obj) {
Node oldfirst = prim;
prim = new Node();
prim.obj = obj;
prim.next = oldfirst;
}

// sterge si returneaza cel mai recent element adaugat


Laborator Programare Java Lucrarea nr. 3

public Object pop() {


if (isEmpty()) throw new RuntimeException("Depasire stiva");
Object obj = prim.obj; // salvare element
prim = prim.next; // sterge primul nod
return obj; // returneaza elementul salvat
}

public static void main(String[] args) {


StackOfObjects stack = new StackOfObjects();
stack.push("stiva");
stack.push("Aceasta");
System.out.println(stack.pop());
stack.push("o");
stack.push("este");
while (!stack.isEmpty()) {
String s = (String) stack.pop();
System.out.println(s);
}
}
}
5. Verificarea cunoștințelor
Răspundeți la următoare întrebări prin adevărat sau fals:
1) Un bloc try trebuie să fie urmat de un bloc catch și de un bloc finally.
2) Dacă scrii o metodă care ar putea să genereze o excep
ție verificată de compilator, trebuie să incluzi
codul riscant într-un bloc try/catch.
3) Blocurile catch pot fi polimorfe.
4) Numai excepțiile verificate de compilator pot fi interceptate.
5) Dacă definești un bloc try/catch, blocul finally este opțional.
6) Metoda main( ) a programului trebuie să trateze toate excep țiile netratate, lansate către ea.
7) Un bloc try poate avea mai multe blocuri catch.
8) O metodă poate lansa un singur tip de excepții.
9) Un bloc finally poate exista fără un bloc try.
10) Ordinea blocurilor catch nu contează.
11) Excepțiile de execuție trebuie să fie tratate sau declarate.

6. Temă pentru acasă


1. Construiți o coadă de obiecte, folosind ca model implementare unei stive prezentate in laborator.

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