Metode. Scopul unei variabile. Recursivitate.
O clasa reprezinta un
Deoarece Java este un limbaj orientat spre
obiecte, codul este definit in interiorul unei sablon (template) al
clase.
unui obiect.
In clasa definim starea
si comportamentul
obiectului.
Metode. Scopul unei variabile. Recursivitate.
Starea este Cu alte cuvinte putem spune ca clasele sunt
alcatuite din campuri (proprietati/atribute) si
reprezentata de metode.
campuri (numite si
proprietati), iar
comportamentul este
definit cu ajutorul
metodelor.
Metode. Scopul unei variabile. Recursivitate.
De exemplu: obiectul public class Cat {
“pisica” are o stare: String color;
int hairLength;
este de culoare gri, String breed;
are parul scurt, public void makeSound(){
System.out.println("Miau");
}
rasa British Shorthair public void eat(){
System.out.println("I'm eating....");
si un comportament: }
miauna, toarce, }
//......
mananca, doarme.
Metode. Scopul unei variabile. Recursivitate.
De ce sunt importante metodele?
De ce avem nevoie de metode?
Metode. Scopul unei variabile. Recursivitate.
Un program este un
De ce sunt importante metodele?
set de obiecte care
De ce avem nevoie de metode? interactioneaza
unele cu celelalte
prin intermediul
metodelor.
Metodele contin instructiuni care sunt
executate cand metodele sunt apelate.
Metode. Scopul unei variabile. Recursivitate.
In alte limbaje intalnim concepte similare
dar denumite diferit, in unele limbaje sunt
numite functii (Javascript) sau proceduri
(Cobol, Pascal).
Metode. Scopul unei variabile. Recursivitate.
Sintaxa unei metode:
<access modifier> <static> <return value type> <method name> (<arguments>){
<method body>
}
//Exemplu concret
public static void main(String[] args) {
// write your code here
}
Metode. Scopul unei variabile. Recursivitate.
Sintaxa unei metode:
<access modifier> <static> <return value type> <method name> (<arguments>){
<method body>
}
//Exemplu concret
public static void main(String[] args) {
// write your code here
}
Modificatorul de acces – este optional si defineste tipul de acces pe care il avem asupra
metodei. Modificatorii de access sunt public, private, default(nespecificat) sau protected.
Metode. Scopul unei variabile. Recursivitate.
Sintaxa unei metode:
<access modifier> <static> <return value type> <method name> (<arguments>){
<method body>
}
//Exemplu concret
public static void main(String[] args) {
// write your code here
}
Static - daca o metoda este statica asta inseamna ca apartine clasei, daca nu este statica
apartine instantei/obiectului.
Metode. Scopul unei variabile. Recursivitate.
Sintaxa unei metode:
<access modifier> <static> <return value type> <method name> (<arguments>){
<method body>
}
//Exemplu concret
public static void main(String[] args) {
// write your code here
}
Tipul returnat de metoda – este obligatoriu
O metoda poate returna un rezultat, de exemplu o metoda care calculeaza o suma returneaza
un rezultat de tip numeric (int, long, double, float).
Metode. Scopul unei variabile. Recursivitate.
Sintaxa unei metode:
<access modifier> <static> <return value type> <method name> (<arguments>){
<method body>
}
//Exemplu concret
public static void main(String[] args) {
// write your code here
}
Rezultatul returnat de metoda poate fi de orice tip:
- primitive: int, char, boolean, double;
- clase wrapper: Integer, Boolean, Float;
- clase definite de noi sau de limbajul Java: String, MyClass, Pisica.
- void: este un tip special care este folosit atunci cand metoda nu returneaza nimic, asadar
daca avem o metoda care nu trebuie sa returneze o valoare, ci doar sa afiseze un mesaj de
exemplu, in acest caz returnType va fi cuvantul cheie “void”.
Metode. Scopul unei variabile. Recursivitate.
Sintaxa unei metode:
<access modifier> <static> <return value type> <method name> (<arguments>){
<method body>
}
//Exemplu concret
public static void main(String[] args) {
// write your code here
}
Numele metodei – este obligatoriu
Programatorul alege numele metodei, insa trebuie sa tina seama de cateva bune practici si
reguli:
- numele metodei nu poate fi un cuvant cheie din limbajul Java, de exemplu “public”, “static”, “new”, “class”
- nu poate incepe cu numere
- trebuie sa inceapa cu litera mica si sa respecte regula de scriere camel case daca este alcatuit din mai multe cuvinte
- e de preferat sa arate o actiune, sa contina un verb, care sa arate ce anume face metoda respectiva, de exemplu: print
sau printText, calculateSum, changeName, deleteValue.
Metode. Scopul unei variabile. Recursivitate.
Sintaxa unei metode:
<access modifier> <static> <return value type> <method name> (<arguments>){
<method body>
}
//Exemplu concret
public static void main(String[] args) {
// write your code here
}
Exemple de ASA NU: sumaADouaNumereIntregi(…), plimbareCuBicicletaPrinPadure(…), abc(…)
Metode. Scopul unei variabile. Recursivitate.
Sintaxa unei metode:
<access modifier> <static> <return value type> <method name> (<arguments>){
<method body>
}
//Exemplu concret
public static void main(String[] args) {
// write your code here
}
Argumentele unei metode – sunt definite in interiorul a doua paranteze rotunde
- parantezele sunt obligatorii chiar daca metoda nu asteapta nici un parametru,
deci daca avem 0 argumente tot trebuie sa punem parantezele, altfel semnatura metodei nu
este valida
Metode. Scopul unei variabile. Recursivitate.
Sintaxa unei metode:
<access modifier> <static> <return value type> <method name> (<arguments>){
<method body>
}
//Exemplu concret
public static void main(String[] args) {
// write your code here
}
Corpul metodei
- corpul metodei sta in interiorul a doua acolade obligatorii pentru metodele concrete,
- corpul metodei poate avea zero, una sau mai multe linii de cod si reprezinta logica executata
de metoda.
Recapitulare …
Metode. Scopul unei variabile. Recursivitate.
Ce este o clasa?
Metode. Scopul unei variabile. Recursivitate.
O clasa reprezinta un
Ce este o clasa?
sablon (template) al
unui obiect. Clasa este
alcatuita din campuri
(proprietati) (starea
obiectului) si metode
(comportamentul
obiectului).
Metode. Scopul unei variabile. Recursivitate.
Ce reprezinta numele metodei?
Metode. Scopul unei variabile. Recursivitate.
• este obligatoriu
Ce reprezinta numele metodei?
• trebuie sa fie cat mai descriptiv
• trebuie sa arate o actiune
• trebuie scris camelCase
• trebuie sa nu fie cuvant cheie din java
• Trebuie sa incepa cu o litera,
underscore sau $ (dollar sign)
Metode. Scopul unei variabile. Recursivitate.
Ce returneaza o metoda?
Metode. Scopul unei variabile. Recursivitate.
• tipul returnat este obligatoriu
Ce returneaza o metoda?
• cand nu returneaza o valoare atunci
tipul specificat trebuie sa fie void
• daca metoda returneaza o valoare,
atunci in interiorul ei regasim cuvantul
cheie return;
• rezultatul returnat de metoda poate fi de
orice tip: primitiv, clasa wrapper, clasa
definita de noi sau de limbajul Java
Metode. Scopul unei variabile. Recursivitate.
Cum se numeste metoda de intrare in orice
program Java?
Metode. Scopul unei variabile. Recursivitate.
Cum se numeste metoda de intrare in orice
program Java?
• main
Metode. Scopul unei variabile. Recursivitate.
Cum se numeste blocul de cod din interiorul
acoladelor unei metode?
Metode. Scopul unei variabile. Recursivitate.
Cum se numeste blocul de cod din interiorul
acoladelor unei metode?
• Corpul metodei.
Metode. Scopul unei variabile. Recursivitate.
Ce contine corpul metodei?
Metode. Scopul unei variabile. Recursivitate.
Ce contine corpul metodei?
• Logica executata de metoda. Poate
contine oricate instructiuni.
Metode. Scopul unei variabile. Recursivitate.
Care este diferenta dintre o metoda statica si
una non-statica?
• O metoda este statica apartine clasei, o
metoda non-statica apartine instantei.
Scopul. (en: scope)
Metode. Scopul unei variabile. Recursivitate.
In limbajul Java putem specifica accesibilitatea sau
scopul unei variabile, a unei metode, unui
constructor sau a unei clase cu ajutorul
modificatorilor de acces.
Metode. Scopul unei variabile. Recursivitate.
Exista 4 modificatori de acces, in ordine de la • private - putem accesa membrul doar din
cel mai restrictiv la cel mai permisiv: interiorul clasei; o metoda cu modificatorul
private nu poate fi accesata din afara clasei
• default - accesul este in cadrul pachetului.
Modificatorul de acces default este atunci cand
nu specificam nici un alt modificator de acces,
asadar nu e nevoie sa scriem cuvantul default,
este implicit default daca nu este specificat unul
din ceilalti modificatori de acces.
• protected - accesul este in cadrul pachetului si in
subclase (vom vorbi de subclase in viitor)
• public - membrul poate fi accesat de oriunde
Metode. Scopul unei variabile. Recursivitate.
Access modifier within class within package outside package outside package
by subclass only
private Yes No No No
default Yes Yes No No
protected Yes Yes Yes No
public Yes Yes Yes Yes
Metode. Scopul unei variabile. Recursivitate.
Pana acum am vazut care este scopul
variabilelor si metodelor setat cu ajutorul
modificatorilor de acces.
Avem asadar urmatoarele 3 cazuri:
In continuare avem scopul unei variabile din 1 Class level scope (scop la nivel de clasa):
perspectiva locului in care aceasta este
declarata. - Variabilele din acest scope se mai numesc si
member variables.
- Variabilele sunt declarate in interiorul clasei, dar in
afara oricarei metode.
- Pot fi accesate direct de oriunde din interiorul
clasei
Metode. Scopul unei variabile. Recursivitate.
2. Method level scope (scop la nivel de metoda) -
local variables:
- Variablele declarate la nivel de metoda au scopul la
nivelul metodei respective.
- Ele nu pot fi accesate din afara metodei in care
este declarata
Metode. Scopul unei variabile. Recursivitate.
3. Block scope (scop la nivel de bloc)
- o variabila declarata in interiorul unei perechi de
acolade dintr-o metoda, au scopul doar in interiorul
acoladelor respective
- un bloc de cod poate fi scris ca atare sau poate
apartine instructiunilor if, while, for.
- in cazul instructiunii for, variabilele declarate pe
randul instructiunii, intre paranteze rotunde, au
scopul pana la terminarea acoladei.
Metode. Scopul unei variabile. Recursivitate.
Putem spune despre scope ca:
- variabilele locale au scopul in interiorul blocului de
cod in care au fost declarate
- variabilele de instanta – sunt disponibile de la
declarare si pana cand obiectul este sters din
memorie
- variabilele de clasa (static) – sunt disponibile de la
declarare pana ce programul termina executia
Recursivitate
Metode. Scopul unei variabile. Recursivitate.
Recursivitatea. Este procesul prin care o metoda se apeleaza pe ea
insasi in mod continuu.
O astfel de metoda se numeste metoda recursiva.
Inputul la fiecare apel recursiv trebuie sa fie diferit
pentru ca la un moment dat apelul recursiv sa se
finalizeze.
Ce se intampla daca nu avem pusa o conditie de
iesire?
Metode. Scopul unei variabile. Recursivitate.
Recursivitatea.
Daca nu este pusa o conditie de iesire poate rezulta
o bucla infinita. Rezultand eroarea
StackOverflowError.
Acest lucru se intampla pentru ca memoria stack
devine insuficienta daca sunt prea multe apeluri
recursive.
Metode. Scopul unei variabile. Recursivitate.
Memoria stack tine apelurile metodelor unele peste
altele, prima este cea mai de jos si ultima este cea
Recursivitatea. pozitionata sus. Apoi le executa incepand cu cea mai
recenta spre cea mai veche.
Metode. Scopul unei variabile. Recursivitate.
In general recursivitatea foloseste mai multe resurse
decat loops si daca inputul are multe elemente
poate duce la StackOverflowError.
Recursivitatea.
Atunci cand folosim recursivitatea codul tinde sa fie
mai concis.
Recursion vs Iteration (loops)
http://www.cs.cornell.edu/info/courses/spring-98/
cs211/lecturenotes/07-recursion.pdf
Despre
Programarea
Orientata spre
Obiect
Programarea Orientata spre Obiect
Programarea orientata spre obiect (P.O.O.) este o
paradigma de programare in care programele sunt
reprezentate sub forma unor colectii de obiecte ce
comunica intre ele prin intermediul metodelor lor.
Programarea Orientata spre Obiect
Limbaje de programare care folosesc paradigma P.O.O.:
Java,
C++,
C#,
Python,
etc.
Programarea Orientata spre Obiect
O aplicatie Java poate fi definita ca o colectie de obiecte ce
comunica intre ele prin invocarea metodelor lor.
Programarea Orientata spre Obiect
Clasele si obiectele sunt doua dintre conceptele de baza in P.O.O.
Programarea Orientata spre Obiect
Ce sunt obiectele?
Programarea Orientata spre Obiect
Ce sunt obiectele? Obiectele reprezinta
entitati din lumea reala si
au stare (campuri) si
comportament (metode).
Fiecare obiect reprezinta
instanta unei clase.
Programarea Orientata spre Obiect
Exemple de obiecte
Programarea Orientata spre Obiect
Catel
Stare:
Exemple de obiecte culoare, rasa, talie
Comportament:
latra, mananca,
doarme, daDinCoada
Copac
Stare:
inaltime, tip, varsta
Comportament:
infloreste, faceFructe
Programarea Orientata spre Obiect
Ce este o clasa?
Programarea Orientata spre Obiect
Ce este o clasa?
O clasa reprezinta un
sablon (template) al unui
obiect. Obiectele sunt
create pe baza claselor.
Programarea Orientata spre Obiect
Reguli pentru definirea unei clase:
- intr-un fisier cu extensia .java pot fi definite mai multe clase, insa doar
o clasa poate fi publica;
- fisierul .java care contine clasa publica are acelasi nume ca si clasa, de
exemplu clasa publica Catel se gaseste in Catel.java ;
- blocul unei clase este definit de acolade.
Programarea Orientata spre Obiect
Cum cream un obiect?
Programarea Orientata spre Obiect
Cum cream un obiect?
Catel catel = new Catel();
Programarea Orientata spre Obiect
Obiectele se aloca pe heap.
Pentru ca un obiect sa poata fi folosit, este necesara cunoasterea adresei
lui.
System.out.println(catel); //ro.company.Catel@7c30a502
Programarea Orientata spre Obiect
Catel azorel = new Catel();
Cuvantul azorel este o referinta care indica catre o zona de memorie
initializata cu template-ul clasei Catel. Cu ajutorul referintei putem accesa
obiectul din memorie.
Pentru a putea avea acces la operatiile furnizate de catre un obiect,
trebuie sa detinem o referinta spre acel obiect.
Programarea Orientata spre Obiect
Catel azorel = new Catel();
Referintele sunt denumiri / variabile care arata unde se afla un obiect in
memorie. In Java obiectele nu pot fi accesate direct, ci doar prin referinte.
Programarea Orientata spre Obiect
Cate obiecte avem in exemplul de mai jos?
Catel azorel = new Catel();
System.out.println(azorel);
//ro.company.Catel@7c30a502
Catel max = azorel;
System.out.println(max);
//ro.company.Catel@7c30a502
Programarea Orientata spre Obiect
Avem un singur obiect ce are adresa in memorie:
ro.company.Catel@7c30a502.
Catel azorel = new Catel();
Insa avem doua referinte catre aceeasi zona de
System.out.println(azorel);
memorie: azorel si max.
//ro.company.Catel@7c30a502
Atribuirea de referinte nu creeaza o copie a
obiectului.
Catel max = azorel;
System.out.println(max);
Daca am fi creat un nou obiect folosind cuvantul
//ro.company.Catel@7c30a502
cheie new atunci atunci s-ar fi alocat un nou
spatiu in memorie.
Programarea Orientata spre Obiect
Cate obiecte avem in exemplul de mai jos?
Catel azorel = new Catel();
System.out.println(azorel);
//ro.company.Catel@7c30a502
Catel max = new Catel();
System.out.println(max);
//ro.company.Catel@49e4cb85
Programarea Orientata spre Obiect
Catel azorel = new Catel();
System.out.println(azorel);
//ro.company.Catel@7c30a502 Pentru ca acum folosim new de
doua ori, azorel refera un obiect in
Catel max = new Catel(); memorie, iar max alt obiect.
System.out.println(max); Asadar avem doua obiecte.
//ro.company.Catel@49e4cb85
Programarea Orientata spre Obiect
Am vazut pana acum ca o clasa contine:
- cuvantul cheie class,
- denumire,
- specificatori de acces
- membri (campuri si metode) cu specificatori de acces
Orice clasa contine in plus cel putin un constructor.
Programarea Orientata spre Obiect
Ce este un constructor?
Programarea Orientata spre Obiect
Ce este un constructor?
Un constructor este un bloc
de cod ce este apelat la
crearea unui nou obiect.
Programarea Orientata spre Obiect
Reguli pentru definirea unui constructor:
- constructorul are acelasi nume precum clasa in care este declarat.
- constructorul poate avea orice modificator de acces.
- constructorul nu are return type, nici macar void
Programarea Orientata spre Obiect
Exemplu de constructor fara parametri:
public class Catel {
public Catel() {
}
}
Programarea Orientata spre Obiect
Nu este obligatoriu ca programatorul sa defineasca un constructor intr-o clasa.
In cazul in care programatorul nu defineste un constructor, atunci compilatorul va
insera un constructor default, fara argumente.
Daca programatorul defineste un constructor, atunci compilatorul nu mai insereaza
constructorul default.
Programarea Orientata spre Obiect
Este de asemenea posibil ca un constructor sa primeasca si argumente, asemanator
unei metode.
Aceste argumente sunt folosite pentru a initializa starea obiectului nou creat.
Programarea Orientata spre Obiect
package ro.company;
public class Catel {
//stare
private String rasa;
private Integer varsta;
public Catel(String rasa, Integer varsta) {
this.rasa = rasa;
this.varsta = varsta;
}
}
In exemplul de mai sus, in clasa Catel am declarat un constructor care asteapta doi
parametri: rasa si varsta.
Programarea Orientata spre Obiect
Deoarece am definit constructorul respectiv, compilatorul nu va adauga automat un
constructor default (care nu asteapta parametri).
Asta inseamna ca daca incercam sa cream un obiect de tipul Catel fara sa trimitem cei
doi parametri asteptati, codul nu va compila.
Catel azorel = new Catel(); //NU COMPILEAZA
La crearea obiectului va trebuie sa apelam constructorul astfel:
Catel azorel = new Catel(“Poodle", 2);
Programarea Orientata spre Obiect
Cuvantul cheie this refera instanta curenta a clasei unde este folosit.
Poate fi folosit de metodele non-statice pentru a se referi la instanta curenta.
Exemplu:
public class Catel {
//stare
private String rasa;
private Integer varsta;
public Catel(String rasa, Integer varsta) {
this.rasa = rasa;
this.varsta = varsta;
}
}
Programarea Orientata spre Obiect
Supraincarcarea
Supraincarcarea este procedeul prin care putem avea mai multi constructori in aceeasi
clasa, dar care difera prin parametrii pe care acestia ii asteapta.
Programarea Orientata spre Obiect
public class Catel {
private String rasa;
private Integer varsta;
public Catel() {
}
public Catel(Integer varsta) {
this.varsta = varsta;
}
public Catel(String rasa, Integer varsta) {
this.rasa = rasa;
this.varsta = varsta;
//putem avea un constructor care primeste aceeasi parametri, dar ordinea acestora difera (au tip diferit)
public Catel(Integer varsta, String rasa) {
this.varsta = varsta;
this.rasa = rasa;
}
}
Programarea Orientata spre Obiect
Daca avem clasa Composer care are proprietatile name si favouriteSong, nu putem avea doi constructori cu aceeasi parametri, dar
inversati pentru ca tipul lor este acelasi (String)
public class Composer {
private String name;
private String favouriteSong;
public Composer(String name, String favouriteSong) { //nu compileaza, denumirea referintei nu conteaza ci tipul
this.name = name;
this.favouriteSong = favouriteSong;
}
public Composer(String favouriteSong, String name) { //nu compileaza
this.favouriteSong = favouriteSong;
this.name = name;
}
}
Programarea Orientata spre Obiect
Putem aplica supraincarea atat constructorilor, cat si metodelor.
Asadar intr-o clasa putem avea mai multe metode cu aceeasi denumire, dar cu
parametri diferiti.
Programarea Orientata spre Obiect
Exemple de metode supraincarcate:
class Baker {
public boolean bakeBread(String recipe) {
// do something
}
protected void bakeBread(String recipe, LocalTime time) {
// do something else
}
// chiar daca are acelasi numar de parametri cu metoda de mai sus, tipul acestora difera (difera pozitia lor)
public void bakeBread(LocalTime cookingTime, String recipe) {
// bake the bread differently
}
// daca mai adaugam inca o metoda care primeste o lista cu doua argumente,
//dar acestea au acelasi tip ca o alta metoda definita in aceeasi clasa, atunci codul nu va compila
public void bakeBread(LocalTime cookingTime, String ingredients) {
// NU COMPILEAZA
}
}
Programarea Orientata spre Obiect
Exemple de metode supraincarcate:
public class Composer {
public void writeSong() {
System.out.println("Na nana na");
}
public void writeSong(String style) {
System.out.println("Here is a " + style + " song: la lala la");
}
public void writeSong(String style, String key) {
System.out.println("I wrote a " + style + " song in " + key);
}
public static void main(String[] args) {
Composer composer = new Composer();
composer.writeSong();
composer.writeSong("rock");
composer.writeSong("pop", "C major");
}
}
Programarea Orientata spre Obiect
Memoria Java
JVM imparte spatiul de memorie in doua parti:
1. Stack
2. Heap
Programarea Orientata spre Obiect
Spatiul de stocare stack
Este o regiune din memoria computerului care stocheaza temporar variabilele create
de fiecare metoda din programul Java.
Stack este o structura de date de tipul LIFO (last in, first out).
Cand programul termina de executat o metoda, toate variabilele stocate pe stack
folosite de metoda respectiva, sunt sterse de pe stack, regiunea de memorie
respectiva eliberandu-se pentru a putea stoca o alta variabila locala.
Tot acest proces se intampla automat, programatorul nu trebuie sa se ocupe de
alocare/eliberare memorie deoarece CPU-ul organizeaza memoria stack eficient,
citirea si scrierea variabilelor facandu-se foarte rapid.
Programarea Orientata spre Obiect
Spatiul de stocare stack este limitat. Cand memoria stack este plina, Java arunca o
eroare de tipul java.lang.StackOverflowError.
In memoria Stack blocurile se stocheaza in ordinea LIFO in timp ce memoria Heap
foloseste alocare dinamica pentru a aloca si dealoca blocuri de memorie.
Programarea Orientata spre Obiect
Spatiul de stocare Heap
Este folosit pentru alocarea dinamica a memoriei pentru obiecte si clasele continute
de JRE la runtime. Obiectele sunt stocate in memoria Heap, iar referintele catre aceste
obiecte sunt stocate in memoria Stack.
Obiectele au acces global, pot fi accesate de oriunde din aplicatie.
Cand memoria heap este plina, Java arunca o eroare de tipul
java.lang.OutOfMemoryError.
Programarea Orientata spre Obiect
Pentru mai multe informatii despre cele doua : https://www.baeldung.com/java-stack-
heap
Recapitulare
OOP
La ce ne ajuta constructorii?
OOP
La ce ne ajuta constructorii?
Constructorii ne ajuta la
crearea de noi obiecte.
OOP
Unde sunt alocate obiectele nou create?
OOP
Unde sunt alocate obiectele nou create?
Pe heap.
OOP
Cum putem accesa obiectele stocate in
memoria heap?
OOP
Cum putem accesa obiectele stocate in
memoria heap?
Cu ajutorul referintelor.
OOP
Unde sunt stocate referintele?
OOP
Unde sunt stocate referintele?
Pe stack.
OOP
Cati constructori definiti de programator avem
in urmatorul exemplu:
public class Person {
private int age;
private String name;
public void Person() {
//do something
}
}
OOP
Cati constructori definiti de programator avem
in urmatorul exemplu:
public class Person {
private int age;
private String name; Zero
public void Person() {
//do something
}
}
OOP
Care sunt regulile pentru definirea unui
constructor?
OOP
Care sunt regulile pentru definirea unui
constructor?
- constructorul are acelasi nume precum clasa in care este
declarat.
- constructorul poate avea orice modificator de acces.
- constructorul nu are return type, nici macar void
OOP
Cati constructori definiti de programator sau de
catre Java avem in urmatorul exemplu:
public class Person {
private int age;
private String name;
}
OOP
Cati constructori definiti de programator sau de
catre Java avem in urmatorul exemplu:
public class Person {
private int age;
private String name; - unu, constructorul default definit de Java
}
OOP
Cati constructori definiti de programator sau de
catre Java avem in urmatorul exemplu:
public class Person {
private int age;
private String name;
public Person(int age, String name) {
this.age = age;
this.name = name;
}
}
OOP
Cati constructori definiti de programator sau de
catre Java avem in urmatorul exemplu:
public class Person {
private int age;
private String name; - unu, constructorul definit de programator care primeste
doua argumente
public Person(int age, String name) {
this.age = age;
this.name = name;
}
}
OOP
Dar in urmatorul exemplu, cati constructori
avem?
public class Person {
private int age;
private String name;
public Person() {
}
public Person(int age) {
this.age = age;
}
public void Person(String name) {
this.name = name;
}
public Person(int age, String name) {
this.age = age;
OOP
Dar in urmatorul exemplu, cati constructori
avem?
public class Person {
private int age;
private String name;
public Person() {
- trei
}
public Person(int age) {
this.age = age;
}
public void Person(String name) {
this.name = name;
}
public Person(int age, String name) {
this.age = age;
OOP
Cum se cheama procedeul prin care putem
avea mai multi constructori care primesc
argumente diferite?
OOP
Cum se cheama procedeul prin care putem
avea mai multi constructori care primesc Supraincarcare.
argumente diferite?
OOP
Constante
OOP
O constanta in Java este o variabila a carei valoare nu se
mai poate schimba o data ce a fost initializata.
OOP
Avantajele utilizarii constantelor intr-o aplicatie Java:
- codul este mai usor de citit si de inteles;
- constanta este pastrata in memorie (in cache) de JVM => performanta este imbunatatita.
OOP
Sintaxa:
static final <var_type> NAME_SOMETHING = value;
OOP
Cuvantul cheie static asociat variabilei ne arata faptul ca variabila apartine clasei, nu instantelor
clasei respective.
OOP
Cuvantul cheie final ne arata faptul ca valoarea continuta de variabila nu poate fi modificata, este
finala.
OOP
public class ConstantsExamples {
public static final int MAX_VALUE = 60;
public static void main(String[] args) {
MAX_VALUE = 70; // NU COMPILEAZA
}
}
OOP
public class ConstantsExamples {
public static final int MAX_VALUE; // NU COMPILEAZA
public static void main(String[] args) {
MAX_VALUE = 70; // NU COMPILEAZA
}
}
O variabila de clasa final trebuie sa fie initializata de la declarare.
OOP
Este suficient sa stim ca o variabila de clasa final trebuie initializata cu o valoare de cand este
declarata si aceasta valoare nu mai poate fi modificata. Spunem despre variabilele final ca sunt
constante.
OOP
La fel ca orice alta variabila, o constanta are un tip si o denumire. Exista o conventie care spune ca
denumirea constantei trebuie scrisa cu majuscule, iar daca este alcatuita din mai multe cuvinte,
atunci despartirea se face prin underscore.
Exemple:
public static final int SECONDS_PER_MINUTE = 60;
public static final String FIRST_DAY_OF_THE_WEEK = "Monday";
OOP
Enum
OOP
Tipul enum este un tip de date special ce reprezinta un set predefinit de constante.
OOP
Ca sa cream o clasa de tip enum vom folosi cuvantul cheie enum. Enum-ul contine
constante scrise cu majuscule, separate prin virgula.
public enum DaysOfWeek {
MONDAY,
TUESDAY,
WEDNESDAY,
THURSDAY,
FRIDAY,
SATURDAY,
SUNDAY
}
OOP
Principiile OOP
Abstractizare (Abstractization)
Polimorfism (Polymorphism)
Mostenire (Inheritance)
Incapsulare (Encapsulation)
A-PIE
OOP
Incapsularea
OOP
Incapsularea
Este procedeul prin care variabilele unei clase sunt inaccesibile altor clase, ele nu pot fi accesate direct
de catre alte clase, ele pot fi accesate doar prin intermediul metodelor clasei in care se gasesc.
Incapsularea este cunoscuta ca "ascunderea datelor" (data hiding). Ascunderea se face cu ajutorul
modificatorului de acces private.
Datorita incapsularii, accesul si modificarea starii unui obiect se poate face doar prin accesori si
mutatori. Accesorii si mutatorii sunt metode publice cunoscute ca getteri si setteri. Setterii pot contine
conditii business.
OOP
Avantajele incapsularii
1. Clasa are control asupra informatiilor ce sunt stocate in variabilele continute de aceasta.
2. Ascunderea datelor: nu cunoastem implementarea din clasa pe care o accesesam, nu cunoastem
decat ca transmitem anumite valori catre metodele setter si variabilele vor fi initializate. Prin
incapsulare atingem si o forma de abstractizare.
3. Incapsularea ne ofera flexibilitate in sensul in care putem face ca variabilele sa fie read-only sau
write-only in functie de cerinte. Daca vrem ca utilizatorul sa nu aiba decat drept de citire asupra unei
variabile, omitem metoda setter. Daca dorim ca utilizatorul sa nu aiba decat drept de scriere asupra
unei variabile, atunci omitem getterul.
4. Incapsularea sporeste reutilizarea codului si usurinta implementarii unor noi cerinte precum si
usurinta in testarea codului.
Recapitulare
OOP
Ce este o constanta?
OOP
Ce este o constanta?
O constanta este o variabila a
carei valoare nu se mai poate
schimba odata ce a fost
initializata.
OOP
Ce inseamna final?
OOP
Ce inseamna final?
Cuvantul cheie final ne arata
faptul ca valoarea continuta
de variabila nu poate fi
modificata.
OOP
O metoda poate fi final?
OOP
O metoda poate fi final?
Da. Atat metodele cat si
clasele pot fi final insa spre
deosebire de variabilele final
au alta semnificatie.
OOP
Ce este gresit in urmatoarea bucata de cod?
public class ConstantsExamples {
public static final Integer maxValue
maxValue = 100_000;
}
OOP
Ce este gresit in urmatoarea bucata de cod?
public class ConstantsExamples {
public static final Integer maxValue;
Variabila de clasa maxValue este final
maxValue = 100_000; asadar trebuie initializata de la
} declarare. In plus, deoarece este
constanta, bunele practici spun ca
trebuie scrisa cu majuscule:
MAX_VALUE.
OOP
Ce este un enum?
OOP
Ce este un enum?
Enum este un tip de date ce
reprezinta un set de
constante.
OOP
Urmatorul enum este scris corect?
public class enum Months {
JANUARY,
FEBRUARY,
MARCH,
APRIL,
MAY,
JUNE,
JULY,
// ....
DECEMBER
}
OOP
Urmatorul enum este scris corect?
public class enum Months {
JANUARY,
FEBRUARY, Nu. Daca este enum, nu are ce cauta
MARCH,
APRIL,
cuvantul class.
MAY,
JUNE,
JULY,
// ....
DECEMBER
}
OOP
Ce este gresit in urmatorul enum?
public enum DaysOfWeek {
MONDAY;
TUESDAY;
WEDNESDAY;
THURSDAY;
FRIDAY;
SATURDAY;
SUNDAY;
}
OOP
Ce este gresit in urmatorul enum?
public enum DaysOfWeek {
MONDAY; Valorile din enum sunt despartite prin
TUESDAY; virgula.
WEDNESDAY;
THURSDAY;
FRIDAY; In exemplul de mai sus, ele sunt
SATURDAY; despartite prin punct si virgula => codul
SUNDAY;
} nu va compila.
OOP
Care sunt cele 4 principii OOP?
OOP
Care sunt cele 4 principii OOP?
Incapsulare, mostenire,
abstractizare si polimorfism.
OOP
Ce este incapsularea?
OOP
Ce este incapsularea?
Este procedeul de ascundere a starii unei clase
(starea este data de variabile, ascunderea se
face cu ajutorul modificatorului de acces
private), accesul si modificarea starii unui
obiect realizandu-se doar prin metodele
speciale: getter si setter.
OOP
Care este scopul metodelor getter?
OOP
Care este scopul metodelor getter?
Getterii ne ajuta sa obtinem starea unui obiect.
OOP
Care este scopul metodelor setter?
OOP
Care este scopul metodelor setter?
Setterii ne ajuta sa initializam sau sa modificam
starea unui obiect in conditiile implementate
de noi.
OOP
In clasa Employee este implementata
incapsularea?
public class Employee {
private String name;
public String getDenumire() {
return name;
}
public void setDenumire(String denumire) {
if (denumire.length() > 3) {
this.name = denumire;
} else {
// display error message
}
}
}
OOP
In clasa Employee este implementata
incapsularea?
public class Employee { Da. Insa denumirea metodelor getter si setter
private String name; nu respecta bunele practici.
Denumirile metodelor ar fi trebuit sa fie
public String getDenumire() { getName si setName, insa nici getDenumire si
return name; setDenumire nu sunt gresite. Codul compileaza
}
cu succes.
public void setDenumire(String denumire) {
if (denumire.length() > 3) {
this.name = denumire;
} else {
// display error message
}
}
}
OOP
Ce metode trebuie omise daca dorim ca
utilizatorul sa aiba doar drept de citire asupra
starii unui obiect?
OOP
Ce metode trebuie omise daca dorim ca
utilizatorul sa aiba doar drept de citire asupra
starii unui obiect?
Metodele setter.
OOP
Mostenirea
OOP
Mostenirea in Java se refera la abilitatea unei clase de a mosteni de la
o alta clasa membrii acesteia (campuri si metode).
OOP
Ideea din spatele mostenirii este ca o clasa sa poata fi construita pe
baza altei clase existente. Pe langa proprietatile mostenite, clasa poate
contine propriile ei campuri si metode.
OOP
Cuvantul cheie care indica mostenirea este extends. Cand clasa A
mosteneste clasa B, mai putem spune ca A extinde pe B.
OOP
Mostenirea reprezinta o relatie IS-A cunoscuta si sub denumirea de
relatie parinte-copil.
public class Flower {}
public class Rose extends Flower {}
Rose IS-A Flower
OOP
Clasa care mosteneste proprietatile altei clase se numeste subclasa
(clasa-copil, clasa derivata).
OOP
Clasa care este mostenita de catre o alta clasa se numeste superclasa
(clasa-parinte, clasa de baza).
OOP
O clasa poate extinde cel mult o alta clasa.
OOP
Tipuri de mostenire in limbajul Java: single, multilevel, hierarchical
class B extinde A | class B extinde A si class c extinde class C | class B si C extind A
OOP
In mostenirea singulara, subclasele mostenesc
caracteristicile unei singure superclase.
OOP
In mostenirea multilevel, clasa-copil mosteneste
clasa-parinte pe care o extinde, iar daca clasa-
parinte extinde la randul ei o alta clasa, atunci
clasa-copil va mosteni si proprietatile
respectivei clase.
OOP
In ceea ce priveste mostenirea ierarhica, o clasa deserveste ca
superclasa (clasa de baza) pentru mai multe subclase.
OOP
Principalul avantaj al mostenirii este reutilizarea codului.
Respectand astfel principiul DRY – Don’t Repeat Yourself.
OOP
In limbajul Java exista o clasa care este superclasa tuturor celorlalte clase (definite
de Java sau construite de programator). Aceasta este clasa Object.
Atunci cand o clasa nu extinde explicit o alta clasa, ea extinde implicit clasa Object.
OOP
O clasa poate avea o singura superclasa, insa o superclasa poate avea oricate subclase.
Deoarece o clasa nu poate extinde mai multe clase putem pastra o complexitate redusa.
OOP
O subclasa mosteneste toti membrii de la clasa ei parinte*.
Constructorii nu sunt membri asadar ei nu sunt mosteniti de subclasa, dar pot fi invocati din
interiorul subclasei.
*Daca o clasa are membri (campuri, metode) declarati private, acestia nu sunt accesibili din
interiorul subclasei. Retinem ca modificatorul de acces private restrictioneaza accesul din
exteriorul clasei.
OOP
Conceptul de mostenire ne ajuta sa nu duplicam cod, clasele copil avand access la membrii non-
private ai claselor parinte, ii pot folosi ca atare sau ii pot suprascrie.
De asemenea subclasele pot avea propriile campuri si metode.
OOP
Clasele definite folosind specificatorul final nu pot fi mostenite.
public final class A {
//..
}
//NU COMPILEAZA
public class B extends A {
//..
}
OOP
Suprascrierea
OOP
Suprascrierea este capacitatea unei subclase de a avea o implementare
specifica a unei metode deja existente in superclasa.
OOP
Cand o metoda din subclasa are aceeasi semnatura (nume si parametrii)
si acelasi tip returnat ca metoda din superclasa atunci spunem despre
metoda din subclasa ca suprascrie metoda din superclasa.
OOP
Pe metodele din clasa copil care suprascriu metode din clasa parinte
putem adauga adnotarea @Override.
Aceata adnotare este optionala.
Avantejele folosirii ei sunt:
- ne atentioneaza ca metoda pe care este pusa suprascrie o alta metoda
din clasa parinte (este o adnotare marker).
- suntem atentionati cand exista erori de scriere sau cand metoda ce va
fi suprascrisa nu exista in clasa parinte.
Exemplu
- shoW(){} nu suprascrie show(){};
- process(String name) nu suprascrie process(int number);
OOP
Exemplu @Override:
public class A {
void process(String name){
System.out.println("processing...");
}
}
public class B extends A {
@Override
void process(String name) {
super.process(name);
}
}
OOP
Modificatorul de acces al metodei suprascrise trebuie sa permita un acces
egal sau mai mare decat metoda care o suprascrie.
De exemplu o metoda protected in superclasa, poate fi suprascrisa de o
metoda publica in subclasa.
OOP
public class Flower {
protected int getNumberOfPetals() {
return 5;
}
}
//this is OK, even public is ok
public class Rose extends Flower {
protected int getNumberOfPetals() {
return 15;
}
}
//this is NOT OK
public class Rose extends Flower {
private int getNumberOfPetals() {
return 15;
}
}
OOP
Metodele declarate ca final in clasa parinte, nu pot fi suprascrise.
Asa cum variabilele final nu pot fi reinitializate, valoarea declarata initial
este finala, nici metodele declarate cu specificatorul final nu pot fi
suprascrise.
OOP
public class Flower {
public final int getNumberOfPetals() {
return 5;
}
}
public class Rose extends Flower {
//this is NOT OK
public int getNumberOfPetals() {
return 15;
}
}
OOP
Super
OOP
Cuvantul cheie super este similar cuvantului cheie this.
OOP
Daca this ne ajuta sa ne referim la clasa in interiorul careia
ne aflam, cu ajutorul cuvantului cheie super putem accesa
membri din clasa parinte.
OOP
Mostenirea si
constructorii in Java
OOP
In limbajul de programare Java, constructorul fara
argumente din superclasa este apelat automat in
constructorul subclasei.
Daca superclasa are un constructor ce primeste unul sau
mai multe argumente iar cel fara argumente lipseste, atunci
toate subclasele trebuie sa apeleze pe prima linie din
constructorul lor, constructorul respectiv din superclasa
folosind super.
OOP
Metodele equals() si
hashCode()
OOP
Parintele tuturor obiectelor din Java este Object.
public class Book {
// implementare...
}
este echivalent cu
public class Book extends Object {
// implementare...
}
OOP
Clasa Object contine cateva metode ce sunt mostenite de
toate celelalte clase.
Dintre aceste metode amintim:
toString(),
equals()
hashCode().
OOP
Doua obiecte sunt egale daca folosim operatorul de
comparare == doar daca au aceeasi adresa in memorie.
Folosim == doar pentru a compara primitive.
Pentru a compara obiecte folosim metoda .equals().
OOP
Implementarea default a metodei equals() din clasa Object
verifica daca doua obiecte au aceeasi adresa in memorie la
fel ca si operatorul ==.
Rezulta ca doua obiecte sunt egale folosind .equals() doar
daca au aceeasi adresa in memorie.
OOP
public class Book extends Object {
public static void main(String[] args) {
Book book1 = new Book();
Book book2 = new Book();
System.out.println(book1.equals(book1)); //true
System.out.println(book1 == book1); //true
System.out.println(book1.equals(book2)); //false
System.out.println(book1 == book2); //false
}
}
OOP
Dar daca avem urmatorul exemplu. Ce vor afisa cele doua linii in care este apelata
metode equals?
public class Book extends Object {
private String author;
private String title;
public Book(String author, String title) {
this.author = author;
this.title = title;
}
public static void main(String[] args) {
Book book1 = new Book("J. R. R. Tolkien", "The Hobbit");
Book book2 = new Book("J. R. R. Tolkien", "The Hobbit");
System.out.println(book1.equals(book1));
System.out.println(book1.equals(book2));
}
}
OOP
Desi din punctul nostru de vedere este vorba despre aceeasi carte intrucat are
acelasi autor si acelasi titlu, implementarea default a metodei equals() compara
doar adresele din memorie.
Atunci care este scopul folosirii metodei equals pentru compararea
obiectelor?
OOP
Putem suprascrie metoda equals() astfel incat sa comparam starea a doua obiecte.
Daca starea a doua obiecte ce au adrese diferite in memorie este la fel, atunci putem considera ca cele
doua obiecte sunt egale.
public boolean equals(Book book) {
if (this.author.equalsIgnoreCase(book.author) && this.title.equalsIgnoreCase(book.title)) {
return true;
}
return false;
}
Book book1 = new Book("J. R. R. Tolkien", "The Hobbit"); //true
Book book2 = new Book("J. R. R. Tolkien", "The Hobbit"); //true
OOP
Metoda hashcode() este mostenita de toate obiectele din clasa Object.
Aceasta returneaza o valoare int dupa aplicarea unui algoritm de hashing Obiectului.
Daca apelam metoda hashcode() pe un obiect a carui stare nu s-a modificat trebuie sa primim output
aceeasi valoare.
Person person = new Person();
System.out.println(person.hashCode());
OOP
Person person = new Person();
System.out.println(person.hashCode());
Implementarea default a metodei hashCode() din clasa Object nu ia in calcul in algoritmul de hashing si
starea obiectului Person. De aceea aceasta trebuie suprascrisa.
public class Person {
private String name;
@Override
public int hashCode() {
return Objects.hash(name);
}
}
OOP
Exista un contract intre metoda equals() si hashCode() de aceea atunci cand implementam metoda equals()
este bine sa implementam si metoda hashCode() in clasele noastre.
public class Person {
private String name;
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
Person person = (Person) o;
return Objects.equals(name, person.name);
}
@Override
public int hashCode() {
return name != null ? name.hashCode() : 0;
}
OOP
Contractul dintre equals() si hashCode():
Doua obiecte egale au acelasi hashCode, insa doua obiecte
cu acelasi hashCode nu sunt neaparat egale.
Recapitulare
OOP
Ce inseamna ca o clasa B mosteneste o alta
clasa A?
OOP
Ce inseamna ca o clasa B mosteneste o alta
clasa A?
Clasa B mosteneste campurile si metodele
clasei A. Prin mostenire clasa B isi insuseste
membrii clasei A.
OOP
Care este cuvantul cheie care indica
mostenirea?
OOP
Care este cuvantul cheie care indica
mostenirea?
Extends
OOP
Ce tip de relatie indica mostenirea?
OOP
Ce tip de relatie indica mostenirea?
E relatie de tipul IS-A sau parinte-copil.
OOP
Cum se mai numesc superclasele?
OOP
Cum se mai numesc superclasele?
Clase parinte sau clase de baza.
OOP
Cum se mai numesc subclasele?
OOP
Cum se mai numesc subclasele?
Clase copil sau derivate.
OOP
Cate clase poate extinde o clasa?
OOP
Cate clase poate extinde o clasa?
Una.
OOP
Cum se numeste mostenirea in care o clasa
mosteneste indirect membrii superclasei
superclasei sale?
OOP
Cum se numeste mostenirea in care o clasa
mosteneste indirect membrii superclasei
superclasei sale?
Mostenire multilevel.
OOP
Cate subclase poate avea o clasa-parinte?
OOP
Cate subclase poate avea o clasa-parinte?
Oricate.
OOP
Cum se numeste parintele tuturor claselor din
Java?
OOP
Cum se numeste parintele tuturor claselor din
Java?
Object.
OOP
Ce este suprascrierea?
OOP
Ce este suprascrierea?
Suprascrierea este capacitatea unei subclase
de a avea o implementare specifica a unei
metode deja existente in superclasa.
OOP
Care sunt conditiile minime pe care trebuie sa
le respecte o metoda ca sa se considere ca
suprascrie o metoda din clasa parinte?
OOP
Care sunt conditiile minime pe care trebuie sa
le respecte o metoda ca sa se considere ca
suprascrie o metoda din clasa parinte?
Metoda care suprascrie trebuie sa aiba aceeasi
semnatura, acelasi tip returnat, iar
modificatorul de acces al metodei suprascrise
trebuie sa permita un acces egal sau mai mare
decat metoda care o suprascrie.
OOP
La ce ne ajuta cuvantul cheie super?
OOP
La ce ne ajuta cuvantul cheie super?
Cuvantul cheie super ne ajuta sa accesam
membri din clasa parinte.
OOP
Ce face implementarea default a metodei
equals()?
OOP
Ce face implementarea default a metodei
equals()?
Equals() verifica daca doua obiecte au aceeasi
adresa in memorie.
OOP
Ce va afisa urmatoarea bucata de cod?
String str1 = "Hello";
String str2 = new String("Hello");
String str3 = "Hello";
System.out.println(str1 == str2);
System.out.println(str1.equals(str2));
System.out.println(str1 == str3);
System.out.println(str1.equals(str3));
OOP
Ce va afisa urmatoarea bucata de cod?
String str1 = "Hello";
String str1 = "Hello"; String str2 = new String("Hello");
String str2 = new String("Hello"); String str3 = "Hello";
String str3 = "Hello";
System.out.println(str1 == str2); //false
System.out.println(str1 == str2); System.out.println(str1.equals(str2)); //true
System.out.println(str1.equals(str2)); System.out.println(str1 == str3); //true
System.out.println(str1.equals(str3)); //true
System.out.println(str1 == str3);
System.out.println(str1.equals(str3));
OOP
Ce va afisa urmatoarea bucata de cod?
public class Person {
private String name;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
public class Main {
public static void main(String[] args) {
Person p1 = new Person();
p1.setName("John");
Person p2 = new Person();
p1.setName("John");
System.out.println(p1 == p2);
OOP
Ce va afisa urmatoarea bucata de cod?
public class Person {
private String name;
public String getName() {
return name; Prima oara va afisa false pentru ca obiectele nu se compara
} cu ==, p1 si p2 nu au aceeasi adresa in memorie.
public void setName(String name) {
A doua oara va afisa tot false, chiar daca folosim metoda
this.name = name;
equals() pentru ca in clasa Person nu avem suprascrisa
} metoda equals(). In acest caz equals() verifica tot daca
} obiectele au aceeasi adresa in memorie. Nu tine cont de
starea/propretatile obiectelor.
public class Main {
public static void main(String[] args) {
Person p1 = new Person();
p1.setName("John");
Person p2 = new Person();
p1.setName("John");
OOP
Abstractizarea
OOP
Abstractizarea consta in ascunderea implementarii in spatele unei interfete.
Un obiect poate executa actiuni, poate comunica cu alte obiecte, isi poate schimba
starea fara a dezvalui cum au fost implementate aceste facilitati.
OOP
De exemplu daca avem un CreditCardValidator cu metoda boolean
validateCreditCard(int numarCard); noi putem folosi metoda validateCreditCard(...)
fara a stii neaparat care este implementarea.
Ne intereseaza doar ca daca apelam metoda si ii trimitem un numar de card vom
primi un raspuns, true daca cardul este valid si false daca este invalid.
OOP
Abstractizarea in Java este realizata folosind interfete si clase abstracte.
OOP
Clasele abstracte
OOP
O clasa abstracta este o clasa declarata folosind specificatorul abstract.
Poate avea metode abstracte si/sau concrete.
Daca o clasa contine cel putin o metoda abstracta, clasa respectiva trebuie sa
fie declarata abstracta, cuvantul abstract devine obligatoriu.
Sintaxa:
public abstract class Animal {
}
OOP
O metoda abstracta este o metoda care nu are implementare, dupa semnatura
metodei urmeaza punct si virgula in loc de acolada, ea poate fi declarata intr-o
clasa abstracta (cuvantul abstract este obligatoriu) sau intr-o interfata
(cuvantul abstract este implicit adaugat de compilator).
public abstract boolean hasFur();
OOP
Exemplu de clasa abstracta:
public abstract class Restaurant {
//abstract method
abstract String serveMeal();
//concrete method
void collectIngredients() {
String[] ingredients = {"flour", "sugar", "eggs", "butter"};
// do something with the ingredients
}
}
OOP
O clasa abstracta nu poate fi instantiata adica nu putem crea noi instante ale
clase folosind cuvantul cheie new.
Restaurant restaurant = new Restaurant(); //DOES NOT COMPILE
OOP
In schimb ea poate fi extinsa (extends) si deserveste ca baza pentru clasele
care o extind. Clasa abstracta devine folositoare cand este extinsa de o clasa
concreta.
O clasa concreta este prima subclasa non-abstracta care extinde clasa
abstracta. Clasa concreta este obligata sa implementeze toate metodele
abstracte mostenite.
public class ItalianRestaurant extends Restaurant {
String serveMeal() {
// return some cooked meal
}
}
OOP
Clasele concrete care extind clase abstracte trebuie sa ofere o implementare
pentru toate metodele abstracte mostenite.
OOP
Chiar daca o clasa abstracta nu poate fi instantiata direct, ea poate fi
instantiata prin clasele care o extind.
Restaurant restaurant = new ItalianRestaurant();
OOP
Folosim clase abstracte atunci cand vrem sa construim o baza pentru unul sau
mai multe obiecte a caror relatie cu clasa abstracta este IS-A.
OOP
Cuvantul cheie abstract poate fi aplicat claselor
si metodelor, dar nu si variabilelor.
OOP
O clasa abstracta nu poate fi final. Prin definitie, o clasa final este o clasa ce nu poate fi
mostenite. Insa scopul claselor abstracte este ca ele sa poata fi extinse.
OOP
O metoda abstracta nu poate fi final.
Metodele final sunt metode care nu pot fi suprascrise.
O metoda abstracta este o metoda ce nu are implementare si care trebuie sa fie
implementata (suprascrisa) in subclase.
Totodata o metoda abstracta nu poate fi privata din acelasi motiv.
OOP
Clasele abstracte pot avea membri definiti ca private, protected, default sau public, insa metodele
abstracte au modificatorul de acces public in mod implicit.
private abstract boolean hasFur(); // Nu compileaza, nu putem avea si private si abstract
abstract boolean hasFur(); //Compileaza, este public este adaugat de compilator
Recapitulare
OOP
Ce este abstractizarea?
OOP
Ce este abstractizarea?
Abstractizarea este un principiu OOP care consta in
ascunderea implementarii in spatele unei interfete.
OOP
Ce cuvant ne indica daca o clasa este abstracta
sau nu?
OOP
Ce cuvant ne indica daca o clasa este abstracta
sau nu?
Cuvantul cheie abstract.
OOP
Este obligatoriu ca o clasa abstracta sa aiba
metode abstracte?
OOP
Este obligatoriu ca o clasa abstracta sa aiba
metode abstracte?
Nu este obligatoriu ca o clasa abstracta sa aiba metode
abstracte. O clasa poate exista fara sa aiba nici o metoda,
doar ca ea nu ne ajuta la nimic.
OOP
O clasa abstracta poate contine metode
concrete?
OOP
O clasa abstracta poate contine metode
concrete?
Da, o clasa abstracta poate contine atat metode abstracte,
cat si concrete.
OOP
Ce este o metoda concreta?
OOP
Ce este o metoda concreta?
O metoda concreta este o metoda ce are un corp aflat intre
doua acolade. Corpul poate contine zero, una sau mai
multe instructiuni. O metoda ce nu are acolade, ci
declararea ei se termina in punct si virgula este o metoda
abstracta si se marcheaza cu specificatorul abstract.
OOP
Am spus ca o clasa abstracta poate contine atat
metode abstracte, cat si metode concrete.
O clasa non-abstracta poate contine metode
abstracte?
OOP
Am spus ca o clasa abstracta poate contine atat
metode abstracte, cat si metode concrete.
O clasa non-abstracta poate contine metode
abstracte? Nu.
OOP
Ce afiseaza urmatoarea bucata de cod?
public abstract class Printer {
public void printText(String text) {
System.out.println(text);
}
}
public class Main {
public static void main(String[] args) {
Printer printer = new Printer();
printer.printText("Hello!");
}
}
OOP
Ce afiseaza urmatoarea bucata de cod?
public abstract class Printer {
public void printText(String text) {
System.out.println(text);
} Codul nu compileaza deoarece Printer este o clasa
} abstracta, iar clasele abstracte nu pot fi instantiate (nu
putem avea new Printer()).
public class Main {
public static void main(String[] args) {
Printer printer = new Printer();
printer.printText("Hello!");
}
}
OOP
Cum am fi putut folosi clasa printer?
OOP
Cum am fi putut folosi clasa printer?
Cu ajutorul unei clase concrete care sa extinda clasa
Printer.
OOP
Ce tip de relatie au o clasa concreta ce extinde
o clasa abstracta?
OOP
Ce tip de relatie au o clasa concreta ce extinde
o clasa abstracta?
IS-A.
OOP
Exemplu de relatie IS-A cu obiectele din jur
Rose IS-A Flower
Chihuahua IS-A Dog
Romanian IS-A Language
OOP
Incapsulare vs. Abstractizare
OOP
Incapsularea reprezinta ascunderea informatiei (data hiding), pe cand
abstractizarea este ascunderea implementarii (detail hiding).
OOP
Folosim o clasa abstracta atunci cand vrem:
- ca respectiva clasa sa nu poata fi instantiata
- sa manipulam un set de clase printr-o interfata comuna
- sa reutilizam o serie de metode si campuri din aceasta clasa in clasele derivate.
OOP
Reguli pentru definirea si folosirea claselor abstracte:
1.) Clasele abstracte nu pot fi instantiate direct (folosind cuvantul cheie new).
2.) Clasele abstracte pot contine orice numar de metode abstracte si nonabstracte.
3.) Clasele abstracte nu pot fi final sau private.
4.) O clasa abstracta care extinde o alta clasa abstracta mosteneste toate metodele
abstracte din clasa mostenita.
5.) Prima clasa concreta care extinde o clasa abstracta trebuie sa implementeze toate
metodele abstracte.
OOP
Reguli pentru definirea metodelor abstracte:
1.) Metodele abstracte pot fi definite doar in clase abstracte.
2.) Metodele abstracte nu pot fi declarate final sau private.
3.) O metoda abstracta nu poate avea implementare in clasa abstracta in care se afla.
4.) Implementarea unei metode abstracte in subclasa se face urmarind aceleasi reguli ca
suprascrierea unei metode.
OOP
Reguli pentru suprascrierea unei metode:
- metoda din subclasa trebuie sa aiba aceeasi semnatura ca metoda din superclasa
- metoda din subclasa trebuie sa returneze acelasi tip ca metoda din superclasa (sau tip
covariant)
- modificatorul de acces al metodei din subclasa trebuie sa permita acces egal sau mai mare
decat metoda din superclasa
OOP
Tip de date covariant
In limbajul Java este obligatoriu sa specificam tipul de date returnat de o metoda.
Daca metoda nu returneaza o valoare, atunci cuvantul cheie folosit este void.
O metoda poate returna valori primitive: char, short, boolean, int, double, etc.
De asemenea poate returna tipuri de date referinta. Tipurile de date referinta sunt clase din
Java sau clase scrise de programator: String, Integer, Boolean, etc.
OOP
Cand spunem ca o metoda care suprascrie o metoda din clasa de baza trebuie sa returneze un
tip de date covariant, ne referim la faptul ca tipul de date trebuie sa fie subclasa pentru tipul
de date returnat de metoda suprascrisa.
Deci in suprascriere tipul de date returnat nu trebuie sa fie neaparat acelasi ci poate fi si de tip
copil al tipului de date suprascris.
OOP
Interfete
OOP
O interfata este un tip de date abstract ce defineste o lista de metode publice abstracte pe
care orice clasa care implementeaza interfata este obligata sa le implementeze.
O interfata este o colectie de metode abstracte. Pe langa metode abstracte, o interfata poate
contine constante, metode default si metode statice.
OOP
O interfata este similara unei clase abstracte, insa o clasa abstracta contine si implementarea
comportamentului pe cand o interfata doar defineste comportamentul.
OOP
Relatia dintre o interfata si clasa care o implementeaza este IS. (Truck is Loadable)
OOP
Interfata indica un comportament al clasei care o implementeaza.
Putem sa avem si clase si interfete denumite astfel:
Dog IS CanWalk
Bird IS CanSing
Unde IS se inlocuieste cu implements.
Sau mai putem avea:
Bicycle IS Vehicle
Circle IS GeometricFigure
De asemenea este comun ca in aplicatiile cu un anumit tip de arhitectura sa avem interfete cu denumiri ca:
PersonService
VehicleInformationService
RemoteControlService
Si clase concrete care implementeaza interfetele de mai sus si au denumirea:
PersonServiceImplementation
VehiculeInformationServiceImpl
RemoteControlServiceImpl
OOP
Interfata este folosita pentru a descrie un contract intre clase: o clasa care implementeaza o
interfata va implementa metodele definite in interfata.
OOP
Spre deosbire de clasele abstracte care sunt extinse folosind specificatorul extends, interfetele
sunt implementate folosind specificatorul implements.
OOP
//modificatorul de acces poate fi public sau nespecificat
//cuvantul cheie abstract este asumat (putem sa-l omitem, il va pune compilatorul)
//cuvantul cheie interface (obligatoriu, este in locul cuvantului cheie class)
//Runnable este denumirea interfetei
public abstract interface Runnable {
//in interfete putem defini constante
//public static final sunt cuvinte cheie asumate
public static final int MAX_KM = 10;
int MIN_KM = 1;
//public abstract = cuvinte cheie asumate, le putem omite
public abstract int getMaxKm();
}
OOP
Implementarea unei interfete
//deoarece clasa concreta Dog implementeaza interfata Runnable, trebuie sa implementam
metoda getMaxKm
public class Dog implements Runnable {
@Override
public int getMaxKm() {
return 0;
}
}
OOP
Reguli pentru definirea interfetelor
1.) Interfetele, la fel ca si clasele abstracte, nu pot fi instantiate direct.
2.) O interfata poate avea zero sau mai multe metode.
3.) O interfata nu poate fi avea specificatorul final, modificatorii de acces private
sau protected.
4.) Toate metodele non-default dintr-o interfata au modificatorii public abstract
adaugati automat de compilator.
OOP
Metode default
O metoda default este o metoda definita intr-o interfata ce are cuvantul cheie
default asociat. Pentru metodele default trebuie sa furnizam o implementare in
interiorul interfetei.
Metodele default au fost adaugate in Java 8. Necesitatea metodelor default a
aparut pentru a asigura backward compatibility pentru interfetele vechi.
public default double getTemperature() {
return 36.5;
}
OOP
Clasele concrete pot suprascrie metodele default, dar nu sunt obligate sa faca
asta cum este in cazul metodelor abstracte.
Metodele default trebuie sa fie publice, daca vor fi marcate ca private sau
protected codul nu va compila.
//NU COMPILEAZA
protected default double getTemperature() {
return 36.5;
}
OOP
Daca programatorul nu specifica nici un modificator de acces pentru o metoda
default, compilatorul oricum pune automat modificatorul public.
//public este asumat, il putem omite
default double getTemperature() {
return 36.5;
}
OOP
Nu putem avea metode default in clase concrete sau in clase abstracte.
public abstract class Animal {
public abstract boolean hasFur();
//NU COMPILEAZA
public default double getTemperature() {
return 36.5;
}
}
OOP
De asemenea, interfetele pot contine si metode statice similare metodelor
statice din clase. Metodele statice definite in interfete nu sunt mostenite de
clasele concrete ce implementeaza interfetele respective.
Metodele statice definite in interfete trebuie sa fie publice.
public static int getMinKm() {
return 0;
}
OOP
Pentru a referi o metoda statica dintr-o interfata, trebuie sa folosim numele interfetei.
De exemplu:
public interface Runnable {
//metoda statica
public static int getMinKm() {
return 0;
}
}
public class Dog implements Runnable {
public int getMaxKm() {
return Runnable.getMinKm(); //asa referim metoda statica din interfata
}
}
OOP
Am vazut in exemplul anterior ca intr-o interfata putem avea variabile.
//in interfete putem defini constante
//public static final sunt cuvinte cheie asumate (puse de compilator) deci le putem omite
public static final int MAX_KM = 10;
int MIN_KM = 1;
OOP
1.) Variabilele dintr-o interfata sunt public static final. Acesti trei specificatori sunt asumati, daca
nu sunt pusi de programator, atunci vor fi pusi automat de compilator.
Nu putem avea intr-o interfata variabile private sau protected.
//NU COMPILEAZA
private static final int MAX_KM = 10;
2.) Avand in vedere ca variabilele dintr-o interfata sunt final, atunci este obligatoriu sa le
initializam cu o valoare de la declarare.
//NU COMPILEAZA
public static final int MAX_KM;
OOP
Clase abstracte
vs
Interfete
OOP
Folosim o clasa abstracta atunci cand:
- relatia dintre clasa abstracta si clasa concreta este IS-A, (Dog is an Animal)
- reutilizam o serie metode si campuri din aceasta clasa in clasele derivate.
- avem acelasi comportament dar si aceeasi implementare a unui comportament in mai multe
clase
OOP
Folosim o interfata atunci cand:
- vrem sa avem doar o descriere a structurii, fara implementari
- avem doar acelasi compotament in mai multe clase dar nu si aceeasi implementare a lui
- relatia dintre interfata si clasa care o implementeaza este IS (Car is Movable)
OOP
Compozitia
OOP
Compozitia este conceptul prin care putem implementa o relatie de HAS-A intre doua clase.
OOP
Asemenea mostenirii, folosim compozitia pentru a reutiliza cod si
pentru a avea un design software cat mai simplu.
OOP
In Java compozitia este realizata prin declararea unor
obiecte ca variabile de instanta, campuri.
OOP
Asocierea poate fi de 4 feluri:
1. one-to-one: Country – President
2. one-to-many: Country – City
3. many-to-one: City – Country
4. many – to – many: Country – Currency (euro)
OOP
Exemplu:
public class Job { ... }
public class Person {
//compozitie,
private Job job;
}
OOP
Polimorfism
OOP
Polimorfismul este unul din conceptele esentiale din programarea orietata pe
obiect si reprezinta capacitatea obiectelor de a lua mai multe forme.
OOP
Orice obiect care trece testul IS-A mai mult de o data este considerat polimorfic.
Astfel putem spune ca toate obiectele Java sunt polimorfice deoarece trec testul
IS-A cu propriul tip, dar si cu clasa Object (clasa parinte a tuturor claselor din
Java).
OOP
Polimorfismul ne ajuta sa executam o singura actiune in moduri diferite, cu alte
cuvinte putem defini o interfata care sa aiba mai multe implementari.
OOP
Cea mai comuna utilizare de polimorfism este atunci cand folosim o referinta cu
tipul clasei parinte pentru a ne referi la un obiect al clasei copil.
Am mai vazut exemple de polimorfism si in lectiile anterioare, cand am discutat
despre abstractizare de exemplu:
Restaurant restaurant = new ItalianRestaurant();
OOP
Obiectul “restaurant” este instantiat cu o referinta catre clasa ItalianRestaurant,
insa deoarece el are tipul de date Restaurant are acces doar la metodele din clasa
Restaurant.
OOP
Putem accesa un obiect prin intermediul unei referinte. Referinta poate avea un
singur tip de date. Odata declarat, acest tip nu mai poate fi schimbat.
Tipul referintei determina metodele pe care le putem apela.
OOP
Exista doua tipuri de polimorfism:
1. Polimorfismul compile-time (polimorfism parametric sau polimorfism static) – obtinut prin
supraincarcarea metodelor.
2. Polimorfismul runtime (polimorfism de mostenire) – obtinut prin suprascrierea metodelor.
OOP
Polimorfismul compile-time este obtinut prin mecanismul de supraincarcare a unei metode. Selectia
metodei apelate se realizeaza la compilare (early binding).
Supraincarcarea este procedeul prin care putem avea mai multe metode cu acelasi nume in aceeasi
clasa, dar cu semnaturi diferite.
Semnatura poate sa difere in trei moduri:
- numarul de parametri;
- tipul de date al parametrilor;
- ordinea in care apar acesti parametri.
OOP
public class Composer {
public void writeSong() {
System.out.println("Na nana na");
}
public void writeSong(String style) {
System.out.println("Here is a " + style + " song: la lala la");
}
public void writeSong(String style, String key) {
System.out.println("I wrote a " + style + " song in " + key);
}
public static void main(String[] args) {
Composer composer = new Composer();
composer.writeSong();
composer.writeSong("rock");
composer.writeSong("pop", "C major");
}
}
Rezultat:
Na nana na
Here is a rock song: la lala la
I wrote a pop song in C major
OOP
Polimorfismul la runtime este obtinut prin mecanismul de suprascriere a unei metode. Selectia
metodei se realizeaza la rulare (late binding, runtime binding, dynamic binding).
OOP
//superclass Atunci cand declaram un obiect in acest fel, avem acces doar la
public class Book {
public void printInfo() { metodele din superclasa, nu si la cele din subclasa. Insa, deoarece
}
System.out.println("Just a book.");
metoda printInfo() este suprascrisa in subclasa, la runtime va fi
} folosita implementarea din subclasa.
//subclass of Book
public class ScienceFictionBook extends Book {
@Override
Ce rezultat va fi afisat daca rulam metoda main:
public void printInfo() { “Just a book.” sau “S.F. Book”?
System.out.println("S.F. Book");
}
public void printAdditionalInfo() {
System.out.println("The best S.F. Book");
}
}
public class Main {
public static void main(String[] args) {
//cand declaram un obiect in felul acesta, vom avea acces doar la metodele din clasa de baza
Book sfBook = new ScienceFictionBook();
//avem acces doar la metoda disponibile in clasa Book, adica la printInfo()
sfBook.printInfo();
}
OOP
Recapitularea regulilor de suprascriere a unei metode
- cele doua metode (cea originala si cea suprascrisa) trebuie sa aiba aceeasi lista de parametri;
- metoda suprascrisa trebuie sa returneze acelasi tip de date cu cel al metodei originale sau un
subtip al acestuia (tip de date covariant);
- modificatorul de acces la metodei suprascrise nu poate fi mai restrictiv decat cel al metodei
originale;
- metodele declarate final nu pot fi suprascrise;
- daca metoda nu este vizibila in clasa copil (este private), atunci nu poate fi suprascrisa. Putem avea
in clasa copil o metoda cu aceeasi semnatura si return type, doar ca nu se considera suprascriere.
OOP
Casting
OOP
Type Casting
In limbajul Java, variabilele pot fi de doua tipuri:
- primitive: byte, short, char, int, long, float, double si boolean.
- referinte
Cele 8 tipuri de date primitive au un anumit numar de biti la declarare dupa cum urmeaza:
byte - 8 bits
short - 16 bits
char - 16 bits
int - 32 bits
float - 32 biti
long - 64 biti
double - 64 biti
boolean - nu este numeric, poate lua valorile true sau false
OOP
Atunci cand vrem sa convertim o primitiva mai mica la o primitiva mai mare, nu trebuie sa facem
nimic special. Java se ocupa de convertirea valorii automat.
//de la int pe 32 de biti la long pe 64 de biti
int x = 1;
long y = x;
float a = 1.2f;
double b = a;
Aceasta conversie poate fi facuta automat deoarece atunci cand trecem de la un tip de date mai mic
la unul mai mare nu exista riscul sa pierdem informatie.
OOP
Nu acelasi lucru se poate spune despre conversia de la un tip de date mai mare la unul mai mic.
int x = 1;
long y = x;
int z = y; // NU COMPILEAZA
//trebuie sa facem cast ca sa mearga
int z = (int) y;
OOP
In exemplul anterior am vazut ca initial variabila de tip long y este initializata cu valoarea variabilei
de tip int x (valoarea 1). Atunci cand vrem sa initializam variabila de tip int z cu valoarea lui y,
compilatorul ne atentioneaza si este necesar ca intai sa ii facem cast la tipul int variabilei y.
float a = 1.2f;
double b = a; //COMPILEAZA pentru ca double este un tip de date mai mare decat float
float c = b; // NU COMPILEAZA
float c = (float) b;
OOP
Conversia de tip boxing/unboxing
In Java fiecare primitiva are o clasa wrapper asociata: Byte, Short, Character, Integer, Long, Float,
Double si Boolean.
Conversia de la primitiva la clasa wrapper si invers se face prin doua procedee numite boxing si
unboxing si este realizata de catre Java.
int a1 = 123;
Integer a2 = a1;
int a3 = a2;
OOP
Variabilele ce au tipul o clasa Wrapper pot fi convertite la tipul String cu ajutorul metodei toString().
Toate clasele Wrapper suprascriu metoda toString() din clasa Object.
Integer integer = 10;
String string = integer.toString();
OOP
Un String poate fi asignat unei variabile de tip Integer (sau de oricare alt tip clasa Wrapper) cu
ajutorul metodei valueOf().
De asemenea, un String poate fi asignat unei primitive cu ajutorul metodelor de tip parse. De
exemplu clasa wrapper Integer are o metoda statica parseInt care primeste ca parametru un String
si returneaza o variabila de tip int.
Integer integer2 = Integer.valueOf(string);
int i = Integer.parseInt(string);
OOP
Acelasi lucru este valabil si pentru alte clase Wrapper si primitiva asociata, singura exceptie de la
aceasta regula fiind Character.
Double d1 = Double.valueOf("12.5");
double d2 = Double.parseDouble("13.4");
Boolean b1 = Boolean.valueOf("true");
boolean b2 = Boolean.parseBoolean("false");
OOP
Numeric promotion
Pentru a executa o operatie aritmetica (adunare, scadere, etc.) este necesar ca ambii operanzi sa fie
compatibili din punct de vedere al numarului de biti alocati.
OOP
Java aplica urmatoarele reguli:
1. daca unul dintre operanzi este double, celalalt operand va fi promovat la tipul
double
2. altfel, daca unul din operanzi este float, atunci si celalalt operand va fi promovat la
tipul float
3. altfel, daca unul din operanzi este long, atunci si celalalt operand va fi promovat la
tipul long
4. altfel, ambii operanzi sunt considerati de tipul int
OOP
Exemplul 1:
//primul operand este de tip int
int o1 = 10;
//al doilea operand este de tipul long
long o2 = 20;
//rezultatul adunarii celor doi operanzi va avea tipul long
long result = o1 + o2;
//daca incercam sa stocam rezultatul adunarii intr-o variabila de tip int, nu va compila
int result2 = o1 + o2;
//insa daca facem cast astfel, vom putea stoca rezultatul intr-o variabila de tip int
int result3 = (int) (o1 + o2);
//sau putem face cast la int doar pentru operandul de tip long, astfel ca rezultatul dintre doi
operanzi de tip int va avea tot tipul int
int result4 = o1 + (int) o2;
OOP
Exemplul 2:
short s1 = 5;
short s2 = 3;
//rezultatul operatiei dintre doi operanzi cu tip mai mic decat int va fi convertit automat la int
int result5 = s1 - s2;
//daca incercam sa stocam rezultatul intr-o variabila de tip short, codul nu va compila
short result6 = s1 - s2;
//daca vrem ca rezultatul sa aiba tipul short, este necesar sa facem cast
short result7 = (short) (s1 - s2);
//castul trebuie facut la rezultatul operatiei, daca facem cast la fiecare operand in parte, codul tot nu
va compila
short result8 = (short) s1 - (short) s2;
OOP
Cum procedam pentru a stoca o valoare de tip double intr-o variabila de tipul int?
Codul de mai jos compileaza?
double d1 = 10;
int i1 = d1;
OOP
Nu compileaza. Trebuie sa facem cast variabilei de tip double la int.
double d1 = 10;
int i1 = (int) d1;
OOP
Dar daca vrem sa stocam valoarea lui i1 la loc intr-o variabila de tip double, sa zicem d2.
Codul va compila de data aceasta?
double d1 = 10;
int i1 = (int) d1;
double d2 = i1;
OOP
Da, va compila. Java poate face automat conversia la un tip mai mare. Insa atunci cand
vrem sa trecem de la un tip mai mare la unul mai mic exista posibilitatea pierderii de
date.
OOP
Daca afisam variabila d2 ce valoare credeti ca are, avand in vedere ca este de tipul
double?
double d1 = 10;
int i1 = (int) d1;
double d2 = i1;
System.out.println(d2);
OOP
Daca afisam variabila d2 ce valoare credeti ca are, avand in vedere ca este de tipul
double?
double d1 = 10;
int i1 = (int) d1;
double d2 = i1;
System.out.println(d2); //10.0
OOP
Acum sa facem acelasi test, doar ca vom asigna variabile d1 valoarea 10.99.
Ce valoare va avea d2 la final?
double d1 = 10.99;
int i1 = (int) d1;
double d2 = i1;
System.out.println(d2);
OOP
Valoarea lui d2 este 10.0. Prin conversia la int s-a pierdut informatia zecimala.
OOP
Byte este un tip de date pe 8 biti. Asta inseamna ca poate stoca pana la 2 la puterea a 8-a numere.
2 la puterea a 8-a este egal cu 256. Pentru ca byte accepta si numere pozitive si numere negative, atunci 256
se imparte in mod egal si astfel se obtin 128 de numere negative si 128 de numere pozitive.
Este usor sa testam acest lucru astfel:
byte b1 = Byte.MAX_VALUE;
byte b2 = Byte.MIN_VALUE;
System.out.println("Byte ia valori intre " + b2 + " si " + b1); //Byte ia valori intre -128 si 127
Valoarea maxima pe care o poate tine un byte este 127.
Ce se intampla daca avem o variabila de tip int cu valoarea 130 si vrem sa o stocam intr-o variabila de tip byte
(care este mai mica)?
int i = 130;
byte b3 = (byte) i;
System.out.println(b3); //-126
int i = 258;
byte b3 = (byte) i;
System.out.println(b3);//2
OOP
Upcasting
Putem face cast de la un tip la altul nu doar intre primitive si clasele Wrapper din Java sau
clasa String, ci si intre clasele scrise chiar de noi.
Mostenirea este strans legata de upcasting.
Procedeul de conversie de la o subclasa la o superclasa se numeste upcasting.
Upcasting-ul este facut automat de compilator.
OOP
//parent class
public class Flower {
//...
}
//child class of Flower
public class GardenFlower extends Flower {
//...
}
//gardenFlower este o referinta de tip GardenFlower ce refera un obiect al clasei GardeFlower
GardenFlower gardenFlower = new GardenFlower();
//datorita relatiei de mostenire, putem asigna referinta gardenFlower unei referinte de tip Flower
//conversia la tipul Flower se face automat deoarece GardenFlower este un subtip al lui Flower
Flower flower = gardenFlower;
//puteam de asemenea sa facem conversia si explicit, dar un IDE inteligent de atentioneaza ca acest cast este
redundant
Flower anotherFlower = (Flower) gardenFlower;
OOP
Downcasting
Daca avem nevoie sa folosim o variabila cu tipul Flower pentru a apela o metoda disponibila doar in
clasa GardenFlower?
Putem face asta cu ajutorul downcasting. Downcasting reprezinta conversia de la o clasa parinte la o
clasa copil.
//gardenFlower este declarata cu tipul Flower, dar refera un obiect de tipul GardenFlower.
//putem face asta pentru ca Flower si GardenFlower sunt inrudite (GardenFlower o mosteneste pe Flower, este un
subtip al lui Flower)
Flower gardenFlower = new GardenFlower();
//pentru a putea apela metoda smellsGood() din clasa GardenFlower, e necesar sa facem un cast
((GardenFlower) gardenFlower).smellsGood();
OOP
In proiectele complexe, inainte de a face downcast de la un tip la alt tip,
este comun sa folosim operatorul instanceof.
Operatorul instanceof ne ajuta sa verificam daca un obiect este o
instanta a unui anumit tip de date (clasa, subclasa, interfata).
Verificarea returneaza un boolean: true sau false.
OOP
Flower flower = new Flower();
GardenFlower gardenFlower = new GardenFlower();
//verificam daca variabila flower este instanta a clasei Flower
System.out.println(flower instanceof Flower); //true
//verificam daca variabila gardenFlower este instanta a clasei GardenFlower
System.out.println(gardenFlower instanceof GardenFlower); // true
//verificam daca variabila gardenFlower este instanta a clasei Flower care este parinte pentru GardenFlower
System.out.println(gardenFlower instanceof Flower); // true
//verificam daca variabila flower este instanta a clasei GardenFlower
System.out.println(flower instanceof GardenFlower); // false
OOP
Dar urmatoarea linie, ce credeti ca va afisa?
System.out.println(flower instanceof Object);
Recapitulare
OOP
Ce este o interfata?
OOP
Ce este o interfata?
O interfata este un tip de date abstract ce defineste o lista
de metode publice abstracte pe care orice clasa care
implementeaza interfata este obligata sa le implementeze.
OOP
Ce tipuri de metode poate contine o interfata?
OOP
Ce tipuri de metode poate contine o interfata?
1. Metode abstracte.
2. Metode default
3. Metode statice
OOP
Care este relatia dintre o interfata si clasa care
o implementeaza?
OOP
Care este relatia dintre o interfata si clasa care
o implementeaza?
IS.
OOP
Car IS Movable
Glass IS Breakable
Dog IS Lovable
Book IS Readable
Exemple
Interfata indica un comportament al clasei care o
implementeaza.
Putem sa avem si clase si interfete denumite astfel:
Dog IS CanWalk
Bird IS CanSing
Unde IS se inlocuieste cu implements.
Sau mai putem avea:
Bicycle IS Vehicle
Circle IS GeometricFigure
De asemenea este comun ca in aplicatiile cu un
anumit tip de arhitectura sa avem interfete cu
denumiri ca:
PersonService
VehicleInformationService
RemoteControlService
OOP
Care este contractul dintre o clasa si o
interfata?
OOP
Care este contractul dintre o clasa si o
interfata?
O clasa care implementeaza o interfata va implementa
metodele abstracte definite in interfata.
OOP
Este o problema in acest cod? (poate fi corect)
public class Readable {
public boolean isPrinted();
}
OOP
Este o problema in acest cod? (poate fi corect)
public class Readable {
public boolean isPrinted();
} o clasa nu poate avea metode abstracte.
OOP
Este o problema in acest cod? (poate fi corect)
public interface class Readable {
public boolean isPrinted();
}
OOP
Este o problema in acest cod? (poate fi corect)
public interface class Readable {
public boolean isPrinted();
} cuvantul class este in plus, trebuie sa-l scoatem ca sa
compileze.
OOP
Este o problema in acest cod? (poate fi corect)
public interface Readable {
public boolean isPrinted();
}
OOP
Este o problema in acest cod? (poate fi corect)
public interface Readable {
public boolean isPrinted();
} interfata este definita corect, codul compileaza
OOP
Este o problema in acest cod? (poate fi corect)
public final interface Readable {
public boolean isPrinted();
}
OOP
Este o problema in acest cod? (poate fi corect)
public final interface Readable {
public boolean isPrinted();
} o interfata nu poate fi final.
OOP
Este o problema in acest cod? (poate fi corect)
interface Readable {
public boolean isPrinted();
}
OOP
Este o problema in acest cod? (poate fi corect)
interface Readable {
public boolean isPrinted();
} interfata este definita corect, codul compileaza
OOP
Este o problema in acest cod? (poate fi corect)
protected interface Readable {
public boolean isPrinted();
}
OOP
Este o problema in acest cod? (poate fi corect)
protected interface Readable {
public boolean isPrinted();
} o interfata nu poate fi definita ca protected sau private. By
default este publica.
OOP
Este o problema in acest cod? (poate fi corect)
public interface Readable {
private static int NUMBER_OF_PAGES = 300;
public boolean isPrinted();
}
OOP
Este o problema in acest cod? (poate fi corect)
public interface Readable {
private static int NUMBER_OF_PAGES = 300;
variabilele dintr-o interfata sunt public static final
public boolean isPrinted();
}
OOP
Este o problema in acest cod? (poate fi corect)
public interface Readable {
int NUMBER_OF_PAGES = 300;
public boolean isPrinted();
}
OOP
Este o problema in acest cod? (poate fi corect)
public interface Readable {
int NUMBER_OF_PAGES = 300;
codul este corect deoarece specificatorii “public static
public boolean isPrinted(); final” sunt asumati, compilatorul ii pune automat. Noi ii
} putem omite pe toti sau doar pe unii dintre ei.
OOP
Este o problema in acest cod? (poate fi corect)
public interface Readable {
int NUMBER_OF_PAGES = 300;
public static final Boolean HAS_COVERS;
public boolean isPrinted();
}
OOP
Este o problema in acest cod? (poate fi corect)
public interface Readable {
int NUMBER_OF_PAGES = 300;
public static final Boolean HAS_COVERS; Variabila HAS_COVERS nu a fost initializata, codul nu va
compila.
public boolean isPrinted();
}
OOP
Este o problema in acest cod? (poate fi corect)
public interface Readable {
public boolean isPrinted();
public int getAverageNumberOfPages() {
return 300;
}
}
OOP
Este o problema in acest cod? (poate fi corect)
public interface Readable {
public boolean isPrinted();
metoda getAverageNumberOfPages nu va compila
public int getAverageNumberOfPages() { deoarece este o metoda concreta si ii lipseste cuvantul
return 300; cheie “default” sau cuvantul cheie “static”.
}
}
OOP
Este o problema in acest cod? (poate fi corect)
public interface Readable {
public boolean isPrinted();
public default int
getAverageNumberOfPages() {
return 300;
}
}
public class Main {
public static void main(String[] args) {
Readable book = new Readable();
}
}
OOP
Este o problema in acest cod? (poate fi corect)
public interface Readable {
public boolean isPrinted();
Readable este interfata, iar interfetele nu pot fi instantiate.
public default int
getAverageNumberOfPages() {
return 300;
}
}
public class Main {
public static void main(String[] args) {
Readable book = new Readable();
}
}
OOP
Dar daca modificam clasa Main astfel:
public interface Readable {
public boolean isPrinted();
public default int
getAverageNumberOfPages() {
return 300;
}
}
public class Main {
public static void main(String[] args) {
Readable book;
}
}
OOP
Dar daca modificam clasa Main astfel:
public interface Readable {
public boolean isPrinted();
codul compileaza, dar momentan nu putem face nimic cu
public default int book. Codul este incomplet, dar nu este gresit.
getAverageNumberOfPages() {
return 300;
}
}
public class Main {
public static void main(String[] args) {
Readable book;
}
}
OOP
Cand folosim clase abstracte si cand folosim
interfete?
OOP
Cand folosim clase abstracte si cand folosim Folosim o clasa abstracta atunci cand:
interfete? - relatia dintre clasa abstracta si clasa concreta este IS-A,
(Dog is an Animal)
- reutilizam o serie metode si campuri din aceasta clasa in
clasele derivate.
- avem acelasi comportament dar si aceeasi implementare
a unui comportament in mai multe clase
Folosim o interfata atunci cand:
- vrem sa avem doar o descriere a structurii, fara
implementari
- avem doar acelasi compotament in mai multe clase dar
nu si aceeasi implementare a lui
- relatia dintre interfata si clasa care o implementeaza este
IS (Car is Movable)
OOP
Ce este compozitia?
OOP
Ce este compozitia?
Compozitia este conceptul prin care putem implementa o
relatie de HAS-A intre doua clase.
Compozitia este o asociere intre doua obiecte distincte.
Asocierea poate fi de 4 feluri:
1. one-to-one: Country – President
2. one-to-many: Country – City
3. many-to-one: City – Country
4. many – to – many: Country – Currency (euro)
OOP
De ce folosim compozitia?
OOP
De ce folosim compozitia?
Asemenea mostenirii, folosim compozitia pentru a reutiliza
cod si pentru a avea un design software cat mai simplu.
OOP
Cum implementam compozitia?
OOP
Cum implementam compozitia?
Implementam compozitia prin declararea unor
obiecte ca variabile de instanta, campuri.
OOP
Cand si de ce folosim compozitia?
OOP
Cand si de ce folosim compozitia?
Folosim compozitia atunci cand vrem:
- sa reutilizam cod;
- sa aratam ca relatia dintre doua clase este HAS-A;
- sa avem un design software cat mai simplu.
OOP
Ce este polimorfismul?
OOP
Ce este polimorfismul?
Polimorfismul reprezinta capacitatea obiectelor de a
lua mai multe forme.
OOP
De ce obiectele din Java sunt polimorfice?
OOP
De ce obiectele din Java sunt polimorfice?
Toate obiectele Java sunt polimorfice deoarece trec
testul IS-A cu propriul tip, dar si cu clasa Object.
OOP
Care este cea mai comuna utilizare a
polimorfismului?
OOP
Care este cea mai comuna utilizare a
polimorfismului?
Cea mai comuna utilizare de polimorfism este atunci
cand folosim o referinta cu tipul clasei parinte
pentru a ne referi la un obiect al clasei copil.
OOP
Care sunt cele doua tipuri de polimorfism?
OOP
Care sunt cele doua tipuri de polimorfism?
1. Polimorfismul compile-time (polimorfism
parametric sau polimorfism static)
2. Polimorfismul runtime (polimorfism de
mostenire)
OOP
Cum obtinem polimorfismul compile-time?
OOP
Cum obtinem polimorfismul compile-time?
Polimorfismul compile-time este obtinut prin
supraincarcarea metodelor.
OOP
Ce este supraincarcarea?
OOP
Ce este supraincarcarea?
Supraincarcarea este procedeul prin care putem
avea mai multe metode cu acelasi nume in aceeasi
clasa, dar cu semnaturi diferite.
OOP
Cum obtinem polimorfismul runtime?
OOP
Cum obtinem polimorfismul runtime?
Polimorfismul runtime este obtinut prin
suprascrierea metodelor.
OOP
Ce este suprascrierea?
OOP
Ce este suprascrierea?
Suprascrierea este capacitatea unei subclase de a
avea o implementare specifica a unei metode deja
existente in superclasa.
OOP
Cand se considera ca o metoda este
suprascrisa?
OOP
Cand se considera ca o metoda este
suprascrisa?
Cand o metoda din subclasa are aceeasi semnatura
si acelasi tip returnat ca metoda din superclasa
atunci spunem despre metoda din subclasa ca
suprascrie metoda din superclasa.
OOP
Care sunt cele doua tipuri de variabile din Java?
OOP
Care sunt cele doua tipuri de variabile din Java?
Primitive si referinte.
OOP
Care sunt cele 8 tipuri de date primitive?
OOP
Care sunt cele 8 tipuri de date primitive?
byte - 8 bits
short - 16 bits
char - 16 bits
int - 32 bits
float - 32 biti
long - 64 biti
double - 64 biti
boolean - nu este numeric, poate lua valorile true
sau false
OOP
In functie de ce anume consideram ca un tip de
date primitiv este mai mare sau mai mic decat
alt tip de date primitiv?
OOP
In functie de ce anume consideram ca un tip de
date primitiv este mai mare sau mai mic decat
alt tip de date primitiv? In functie de numarul de biti alocati la declararea
variabilei.
OOP
Cum se face conversia de la un tip de date mai
mare la unul mai mic?
OOP
Cum se face conversia de la un tip de date mai
mare la unul mai mic?
Trebuie sa facem cast la tipul de date mai mic.
OOP
De ce trebuie sa facem cast manual?
OOP
De ce trebuie sa facem cast manual?
Deoarece exista riscul sa pierdem informatie.
OOP
Cum se face conversia de la un tip de date mai
mic la unul mai mare?
OOP
Cum se face conversia de la un tip de date mai
mic la unul mai mare?
Conversia se face automat, nu e nevoie sa o faca
programatorul.
OOP
Ce este o clasa wrapper?
OOP
Ce este o clasa wrapper?
O clasa wrapper este o clasa al carei obiect contine
o primitiva.
OOP
Cate clase wrapper sunt?
OOP
Cate clase wrapper sunt?
Opt clase wrapper, cate una pentru fiecare
primitiva.
byte - Byte
short - Short
char - Character
int - Integer
float - Float
long - Long
double - Double
boolean – Boolean
OOP
Cum se numesc procedeele de conversie de la o
primitiva la clasa wrapper asociata si invers?
OOP
Cum se numesc procedeele de conversie de la o
primitiva la clasa wrapper asociata si invers?
Boxing si unboxing.
OOP
Aceste procedee se fac automat sau trebuie sa
specifice programatorul ca vrea sa converteasca
de la int la Integer, de exemplu?
OOP
Aceste procedee se fac automat sau trebuie sa
specifice programatorul ca vrea sa converteasca
de la int la Integer, de exemplu? Se fac automat.
OOP
Cum procedam daca vrem sa convertim o
variabila cu tipul Integer la tipul String?
OOP
Cum procedam daca vrem sa convertim o
variabila cu tipul Integer la tipul String?
Cu ajutorul metodei toString() pe care o apelam pe
referinta de tip Integer.
OOP
Cum procedam daca vrem sa convertim o
variabila cu tipul int la tipul String?
OOP
Primitivele nu au metode, deci nu putem apela metoda
toString() pentru o variabila de tipul int.
Cum procedam daca vrem sa convertim o Putem in schimb sa facem boxing la clasa wrapper Integer si
variabila cu tipul int la tipul String? apoi sa apelam toString().
int a = 0;
Integer b = a;
String str = b.toString();
Sau ne putem folosi de metoda statica toString ce primeste
ca parametru un int si returneaza o valoare de tip String,
metoda ce se regaseste in clasa wrapper Integer.
int a = 0;
String str = Integer.toString(a);
Aceasta metoda exista si in alte clase wrapper, de exemplu in
clasa Double si o putem folosi astfel:
String strFromDouble = Double.toString(10.02);
Sau
String strFromChar = Character.toString('c');
OOP
Exista 4 reguli pe care Java le aplica intr-o
anumita ordine in cazul operatiilor aritmetice.
Care sunt regulile respective?
OOP
Exista 4 reguli pe care Java le aplica intr-o
anumita ordine in cazul operatiilor aritmetice.
Care sunt regulile respective?
1. daca unul dintre operanzi este double, celalalt operand va
fi promovat la tipul double
2. altfel, daca unul din operanzi este float, atunci si celalalt
operand va fi promovat la tipul float
3. altfel, daca unul din operanzi este long, atunci si celalalt
operand va fi promovat la tipul long
4. altfel, ambii operanzi sunt considerati de tipul int
OOP
Ce este upcasting?
OOP
Ce este upcasting?
Upcasting este procedeul de conversie de la o subclasa la o
superclasa.
OOP
Ce legatura trebuie sa existe intre doua clase ca
sa putem aplica upcasting?
OOP
Ce legatura trebuie sa existe intre doua clase ca
sa putem aplica upcasting?
O legatura de mostenire, una dintre clase trebuie sa fie
copilul celeilalte.
OOP
Care este procedeul invers al lui upcasting?
OOP
Care este procedeul invers al lui upcasting?
Downcasting.
OOP
Si ce reprezinta downcasting?
OOP
Si ce reprezinta downcasting?
Downcasting este procedeul de conversie de la o superclasa
la o subclasa.
OOP
Ce operator trebuie folosit inainte de a face
downcasting?
OOP
Ce operator trebuie folosit inainte de a face
downcasting?
Operatorul instanceof.
OOP
Ce verificam cu ajutorul lui instanceof?
OOP
Ce verificam cu ajutorul lui instanceof?
Verificam daca un obiect este o instanta a unui anumit tip de
date.
OOP
Ce tip de date returneaza verificarea cu ajutorul
lui instanceof?
OOP
Ce tip de date returneaza verificarea cu ajutorul
lui instanceof?
Returneaza un boolean (una din valorile true sau false).
OOP
Nested Classes
OOP
Nested class este o clasa declarata in interiorul altei clase sau interfete.
OOP
O clasa are campuri si metode care reprezinta membrii clasei.
In plus, o clasa poate contine o alta clasa. Clasa continuta se numeste inner
class (clasa interioara) sau nested si este tot un membru al clasei din care face
parte.
OOP
Clasele nested sunt folosite pentru a putea grupa clase si/sau interfete intr-un singur loc.
OOP
Sintaxa:
class MyClass {
//code
class MyInnerClass {
//code
}
}
OOP
Clasa care contine o clasa inner (interioara) se numeste clasa outer (exterioara).
OOP
Clasele inner (sau nested) pot fi statice sau non-statice.
OOP
1. Static Nested Classes
O clasa nested statica este o clasa interioara ce are asociat specificatorul static, asadar este un
membru static al clasei din care face parte.
O clasa nested statica poate fi accesata fara a instantia clasa outer.
La fel ca membrii statici, o clasa nested statica nu are acces la variabilele de instanta si la metodele
clasei outer.
Sintaxa
class MyClass {
//fields
static class MyInnerClass {
//code
}
//methods
}
OOP
2. Non-Static Nested Classes
O clasa nested non-statica poate fi de trei feluri:
2A.) Inner Class
2B.) Method-local Inner Class
2C.) Anonymous Inner Class
OOP
2A.) Clasa inner
Spre deosebire de o clasa normala, o clasa inner poate fi declarata cu
modificatorii de acces private si protected.
Daca o clasa inner este private, atunci ea nu poate fi accesata din exteriorul
clasei outer.
OOP
2B.) Method-local Inner Class
In Java putem scrie o clasa in interiorul unei metode. Clasele create in interiorul
unei metode se numesc local inner classes. Metoda apartine clasei outer.
La fel ca variabilele locale (variabile declarate in interiorul unei metode), scopul
unei clase inner este restrictionat la metoda in care este declarata.
Pentru a apela metodele dintr-o clasa inner locala, trebuie sa instantiem clasa in
interiorul metodei.
OOP
2C.) Anonymous Inner Classes
Clasele anonime ne ajuta sa facem codul mai concis.
Acestea ne permit sa declaram si sa instantiem o clasa in acelasi timp.
Sunt ca niste clase locale, cu exceptia faptului ca nu au un nume.
Le folosim atunci cand trebuie sa utilizam o clasa locala o singura data.
O clasa anonima este o expresie.
OOP
Folosim clase nested atunci cand vrem sa grupam logic clase folosite intr-un singur loc.
Daca o clasa este folosita doar intr-o alta clasa, atunci ar fi logic sa o includem in clasa respectiva
pentru a le avea pe amandoua in acelasi loc.
Aceasta arhitectura ar putea face codul mai usor de citit si de mentinut.
OOP
Folosirea claselor nested sporesc incapsularea astfel:
- sa consideram doua clase A si B
- clasa B are nevoie de acces la membrii clasei A
- din cauza aceasta trebuie sa declaram membrii clasei A cu un modificator de acces altul decat
private pentru a putea fi accesibili din exteriorul clasei
Avantajele ascunderii clasei B in interiorul clasei A ar fi urmatoarele:
- nu avem acces la implementarea clasei B din exterior
- membrii clasei A pot fi declarati private, iar B ar putea sa-i acceseze fiind o clasa inner
OOP
Compararea obiectelor
OOP
Compararea a doua obiecte se poate face folosind metoda equals().
Insa aceasta comparatie ne spune doar daca obiectele sunt egale sau nu.
OOP
Intr-o structura de date putem avea obiectele intr-o anumita ordine.
Pentru a ordona obiectele trebuie sa le putem compara intre ele astfel incat sa
putem stabili daca un obiect este mai mic, mai mare sau egal cu altul.
OOP
Clasa String din Java implementeaza interfata Comparable si suprascrie metoda compareTo(String
str) de aceea putem compara doua String-uri intre ele.
String greet1 = “hello”;
String greet2 = “hi”;
greet1.compareTo(greet2); //-4 - pentru ca va compara valoarea fiecarui caracter din primul
String transformata in codul sau unicode cu valorile caracterelor din celalalt String.
String greet3 = “hello”
greet1.compareTo(greet3); //0
Daca String-urile au aceleasi caractere returneaza 0, iar daca am compara aceleasi String-uri cu
metoda equals() am primi raspuns true.
OOP
Daca avem un Array de String putem sorta structura de date
folosind Array.sort(numele_array-ului).
Acest lucru este posibil datorita faptului ca String implementeaza
interfata Comparable si suprascrie metoda compareTo(String
anotherString) ceea ce face posibila sortarea array-ului nostru in
ordine alfabetica.
OOP
Putem folosi metoda sort() a clasei Array si pentru alte tipuri de date din Java, atat pentru
primitive, clase din limbaj (Integer, Boolean, etc.) sau pentru clase create de noi.
int[] numbers = new int[]{9,7,6,2,1,2,4,4,10,2,10,20};
Arrays.sort(numbers);
System.out.println(Arrays.toString(numbers)); //[1, 2, 2, 2, 4, 4, 6, 7, 9, 10, 10, 20]
OOP
Pentru a folosi metoda sort() pentru clasele create de noi acestea trebuie sa implementeze
interfata Comparable si metoda compareTo(). Implementarea metodei compareTo() o scriem noi
in functie de necesitati.
OOP
Folosind interfata Comparable implementarea metodei compareTo este tight-coupled (strans
legata) de clasa comparata si nu putem avea decat o singura implementare a metodei
compareTo().
OOP
Un alt mod prin care putem realiza compararea obiectelor
este prin utilizarea interfetei Comparator.
OOP
Folosind Comparator putem avea oricate implementari ale
interfetei pentru o clasa, astfel putem compara de fiecare
data in functie de alta proprietate in functie de necesitati.
OOP
Avand in vedere aspectele anterior mentionate pentru a
compara doua obiecte de acelasi tip este de preferat sa
folosim interfata Comparator.
OOP
Interfata Comparator nu va fi implementata de clasa comparata ci de o noua clasa al carei
obiecte vor avea ca scop compararea clasei data in definitia noii clase:
Exemplu:
public class EmployeeNameComparator implements Comparator<Employee> {
...
}
OOP
Acest tip de implementare a Comparator este loose-coupled (decuplata) de clasa comparata si
putem avea oricate clase de tip Comparator avem nevoie pentru o clasa pe care vrem sa o
comparam. De exemplu putem avea pentru o clasa Employee, o clasa care implementeaza
Comparator si care compara numele angajatilor, o alta clasa care implementeaza Comparator
care compara salariul angajatilor, etc.
OOP
public class EmployeeSalaryComparator implements Comparator<Employee> {
@Override
public int compare(Employee o1, Employee o2) {
return o1.getSalary() - o2.getSalary();
}
}
Employee employee1 = new Employee("John", 30000);
Employee employee2 = new Employee("Mike", 15000);
EmployeeSalaryComparator employeeSalaryComparator = new EmployeeSalaryComparator();
System.out.println(employeeSalaryComparator.compare(employee2, employee1) > 0); //false
OOP
Obiectele de tip Comparator pot fi date si ca parametru metodei
Array.sort(array, comparator) pentru a sorta o structura de date.
OOP
Atat Comparator cat si Comparable pot fi folosite si
cu alte structuri de date precum List, Set etc.
OOP
Generics
OOP
Java Generics au fost introduse in Java 1.5 cu scopul de a adauga un strat
suplimentar de abstractizare peste tipurile de date.
OOP
Mai mult decat atat, Generics au fost introduse pentru a adauga mai
multa stabilitate proiectelor complexe si pentru a reduce numarul de
posibile bug-uri ce au loc la runtime, eliminand necesitatea de a face
cast.
OOP
Avem o metoda generica care primeste ca parametru un array de tip T (T poate fi orice tip de date) si
care afiseaza elementele array-ului.
public <T> void displayArray(T[] arr) {
for (T element : arr) {
System.out.println(element);
}
}
In Java exista "generic methods" care sunt metode ce au o singura semnatura, dar pot fi apelate cu
argumente de tipuri diferite.
Compilatorul asigura corectitudinea oricaror tipuri de date folosite.
Metodele generice au urmatoarele proprietati:
- metodele generice au inainte de return type un asa-zis type parameter
- type parameter este un operator diamond ce include tipul de date
- metodele generice pot avea mai multe tipuri de parametri in signatura separate prin virgula
- corpul metodei generice este similar unei metode normale.
OOP
Garbage Collection
OOP
Garbage Collection este un proces care sterge din memorie obiectele care nu mai sunt folosite.
OOP
Java stie ca un obiect nu va mai fi folosit atunci cand referinta sa este
out of scope (blocul de cod unde aceasta a fost definit a terminat
executia) sau atunci cand nu mai exista o referinta valida catre acel
obiect (referintele obiectelor sunt null sau refera alte obiecte).
public void process(){
Object o = new Object();
Object o2 = new CustomObject();
o2 = null; //new CustomObject(); este eligibil pentru stergere
}
//new Object(); este eligibil pentru stergere deoarece referinta o este
out-of-scope
OOP
Garbage Collection ruleaza atunci cand procesorul este liber sau atunci
cand memoria Heap este aproape plina.
Nu ii putem spune noi cand sa ruleze dar ii putem sugera cu
System.gc();
OOP
Garbage Collection functioneaza in doi pasi:
- Mark – identifica zonele de memorie folosite si nefolosite
- Sweep – sterge obiectele identificate ca fiind nefolosite
OOP
In JVM gasim mai multe implementari ale Garbage Collectorului
despre care puteti invata mai multe de aici:
https://www.baeldung.com/jvm-garbage-collectors
OOP
Imutabilitatea
OOP
Imutabilitatea este conceptul prin care restrictionam modificarea starii
unui obiect dupa ce aceasta a fost initializat.
OOP
Incapsularea restrictioneaza accesul nedorit al obiectelor, insa prin
imutabilitate restrictionam complet modificarea unui obiect.
OOP
Imutabilitatea ne asigura ca un obiect odata
creat nu va mai fi modificat ulterior.
OOP
Obiectele imutabile sunt thread-safe, deci pot fi folosite de
multiple threaduri fara a avea anomalii de scriere sau citire.
De asemenea obiectele imutabile pot fi folosite ca si obiecte
cheie in colectii de tip Map.
OOP
Dezavantajul folosirii obiectelor imutabile ar fi ca nu pot fi
refolosite cu alte informatii ceea ce creaza multe obiecte eligibile
pentru stergere de catre Garbage Collection.
OOP
Clasa String din Java este un exemplu de obiect imutabil. De
fiecare data cand incercam sa modificam un String in memorie
se genereaza un alt obiect cu noua valoare, vechea valoare fiind
eligibila pentru stergere de catre Garbage Collection.
OOP
String str1 = "hello";
str1.toUpperCase();
//Ce va afisa urmatoarea linie de cod?
System.out.println(str1);
OOP
String str1 = "hello";
str1.toUpperCase();
//Ce va afisa urmatoarea linie de cod?
System.out.println(str1); //hello
Apelul metodei toUpperCase() al clasei String nu modifica obiectul str1. Clasa String
fiind imutabila, inseamna ca obiectul str1 nu poate fi modificat.
Metoda toUpperCase() returneaza un alt obiect cu valoarea “HELLO”.
Obiectul “HELLO” este eligibil pentru Garbage Collection deoarece in exemplul anterior
acest obiect nu este referit.
OOP
String str1 = "hello";
str1 = str1.toUpperCase();
//Ce va afisa urmatoarea linie de cod?
System.out.println(str1);
OOP
String str1 = "hello";
str1 = str1.toUpperCase();
//Ce va afisa urmatoarea linie de cod?
System.out.println(str1); //HELLO
In acest exemplu String-ul “hello” nu va mai fi referit si va fi eligibil pentru stergere de
catre Garbage Collection iar referinta str1 va referi un nou obiect “HELLO”.
OOP
In afara de clasele/obiectele imutabiledin limbajul Java putem crea si propriile clase pe
baza carora sa instantiem obiecte imutabile.
OOP
Cum initializam starea unui obiect de la declarare?
OOP
Folosind un constructor cu parametrii care initializeaza campurile obiectului.
OOP
Cum putem modifica starea obiectului dupa initializare?
OOP
Folosind metode setter. Insa exista si ale moduri prin care
putem modifica starea unui obiect cum ar fi alte metode sau
chiar metodele getter.
OOP
Cum putem limita modificarea starii unui obiect dupa
initializare?
OOP
Reguli pentru a crea un obiect imutabil:
- Omitem setterii
- Campurile/starea obiectului trebuie sa fie declarate cu specificatorul private
- Clasa trebuie sa fie final, astfel eliminam posibilitatea ca ea sa fie extinsa
- Tipul de date returnat de getteri sa fie imutabil sau sa returnam o copie
Recapitulare
OOP
Ce este o clasa nested?
OOP
Ce este o clasa nested?
O clasa nested este o clasa declarata in interiorul altei
clase.
OOP
Cand si de ce folosim clase nested?
OOP
Cand si de ce folosim clase nested?
Clasele nested sunt folosite pentru a putea grupa clase
si/sau interfete intr-un singur loc facand codul mai usor de
citit si de intretinut.
OOP
De cate tipuri pot fi clasele inner?
OOP
De cate tipuri pot fi clasele inner?
Clasele inner (sau nested) pot fi statice sau non-statice.
OOP
De cate tipuri pot fi clasele inner non statice?
OOP
De cate tipuri pot fi clasele inner non statice?
2A.) Inner Class
2B.) Method-local Inner Class
2C.) Anonymous Inner Class
OOP
Pot exista clase cu modificator de access private
sau protected?
OOP
Pot exista clase cu modificator de access private
sau protected?
Da, dar trebuie sa fie inner classes.
OOP
Pot exista clase cu specificator static?
OOP
Pot exista clase cu specificator static?
Da, dar trebuie sa fie inner classes.
OOP
Prin cate moduri putem compara un obiect?
OOP
Prin cate moduri putem compara un obiect?
Prin 3 moduri:
- folosind metode equals() (putem verifica daca doua
obiecte sunt egale sau nu)
- implementand interfata Comparable
- implementand interfata Comparator
Implementand Comparator sau Comparable putem vedea
daca un obiect este mai mic, mai mare sau egal cu un obiect
de acelasi tip.
OOP
Care modalitatea de preferat prin care putem
compara doua obiecte?
OOP
Care modalitatea de preferat prin care putem
compara doua obiecte?
Folosind o implementare a interfetei Comparator, codul
nostru este loose-coupled (decuplat) si putem avea cate un
obiect care implementeaza Comparator pentru fiecare
dintre proprietatile obiectului.
OOP
La ce folosesc Generics?
OOP
La ce folosesc Generics?
Folosind Generics putem scrie metode reutilizabile cu mai
multe tipuri de date, eliminand necesitatea de a face cast.
Cele mai importante beneficii introduse de generics sunt:
- eliminarea codului duplicat
- eliminarea eventualelor erori de casting
OOP
Ce este Garbage Collection?
OOP
Ce este Garbage Collection?
Garbage Collection este un proces care sterge din memorie
obiectele care nu mai sunt folosite.
OOP
In Java, cand este un obiect eligibil pentru a fi
sters din memorie?
OOP
In Java, cand este un obiect eligibil pentru a fi
sters din memorie?
Java stie ca un obiect nu va mai fi folosit atunci cand referinta
sa este out of scope (blocul de cod unde aceasta a fost definit
a terminat executia) sau atunci cand nu mai exista o referinta
valida catre acel obiect (referintele obiectelor sunt null sau
refera alte obiecte).
OOP
Cand este executat Garbage Collectorul?
OOP
Cand este executat Garbage Collectorul?
Garbage Collection ruleaza atunci cand procesorul este liber
sau atunci cand memoria Heap este aproape plina.
Nu ii putem spune noi cand sa ruleze dar ii putem sugera cu
System.gc();
OOP
Ce este Imutabilitatea?
OOP
Ce este Imutabilitatea?
Imutabilitatea este conceptul prin care restrictionam
modificarea starii unui obiect dupa ce aceasta a fost initializat.
OOP
Care este diferenta dintre Imutabilitate si
Incapsulare?
OOP
Care este diferenta dintre Imutabilitate si
Incapsulare?
Incapsularea restrictioneaza accesul nedorit al obiectelor, insa
prin imutabilitate restrictionam complet modificarea unui
obiect.
OOP
Care sunt regulile pentru a crea un obiect
imutabil?
OOP
Care sunt regulile pentru a crea un obiect
imutabil?
- Omitem setterii
- Campurile/starea obiectului trebuie sa fie declarate
cu
specificatorul private
- Clasa trebuie sa fie final, astfel eliminam posibilitatea
ca ea sa
fie extinsa
- Tipul de date returnat de getteri sa fie imutabil sau sa
returnam
o copie
Collections
Collections-Exceptions-Working with files-Multithreading-Unit tests-VCS
Structuri de date
Collections-Exceptions-Working with files-Multithreading-Unit tests-VCS
Structurile de date reprezinta o modalitate de a stoca si
organiza informatia astfel incat sa fie utilizata in mod eficient.
Collections-Exceptions-Working with files-Multithreading-Unit tests-VCS
Array-urile sunt o colectie de elemente stocate secvential
(unul dupa altul). Aceasta organizare de elemente este
realizata cu ajutorul structurilor de date.
In limbajul de programare Java mai exista si alte modalitati de a
organiza datele in memorie.
Collections-Exceptions-Working with files-Multithreading-Unit tests-VCS
Tipurile de structuri de date sunt:
- structuri de date primitive: acestea sunt chiar tipurile de date
primitive (int, char, float, etc.) care stocheaza o singura valoare.
- structuri de date non-primitive.
Collections-Exceptions-Working with files-Multithreading-Unit tests-VCS
Structurile de date non-primitive sunt la randul lor de doua feluri:
- lineare: datele sunt stocate intr-o maniera secventiala
(Arrays, Linked list, Stacks, Queues)
- non-lineare (Trees)
Collections-Exceptions-Working with files-Multithreading-Unit tests-VCS
Structurile de date mai pot fi clasificate si dupa felul in care este
alocata memoria:
- statice: dimensiunea structurii de date este alocata la compile time,
deci dimensiunea este fixa.
- dinamice: dimensiunea structurii de date este alocata la run time,
asadar dimensiunea este flexibila.
Collections-Exceptions-Working with files-Multithreading-Unit tests-VCS
Operatiile pe care le putem performa pe structurile de date includ:
- cautarea unui element
- sortarea structurii de date in ordine ascendenta/descendenta
- inserarea unui element
- modificarea unui element
- stergerea unui element
Collections-Exceptions-Working with files-Multithreading-Unit tests-VCS
Structuri de date din limbajul Java:
Array, Linked List. Stack. Queue, etc.
Collections-Exceptions-Working with files-Multithreading-Unit tests-VCS
Avantajele utilizarii structurilor de date:
- codul scris poate fi mai eficient din punct de vedere la timpului
consumat si al spatiului utilizat daca utilizam structurile de date
optime;
- structurile de date pot fi reutilizate => reutilizarea face ca
programul sa fie mai performant;
- structurile de date au un nivel de abstractizare in sensul in care
clientul ce utilizeaza structurile de date nu cunoaste
implementarea, are acces doar la interfata si la metodele oferite de
aceasta, fara sa stie de fapt cum se petrec lucrurile in spate.
Collections-Exceptions-Working with files-Multithreading-Unit tests-VCS
Collections framework
Collections-Exceptions-Working with files-Multithreading-Unit tests-VCS
Collections framework este un set de interfete, implementari si
algoritmi (metode pentru sortare, cautare, etc.).
Collections framework implementeaza cele mai importante structuri
de date abstracte.
Este mai mult o librarie decat un framework.
Collections-Exceptions-Working with files-Multithreading-Unit tests-VCS
Colectiile sunt grupuri de obiecte tratate ca o entitate. Unele dintre ele
pot sa inlocuiasca Array.
Collections-Exceptions-Working with files-Multithreading-Unit tests-VCS
De retinut este faptul ca nu putem adauga primitive in colectii, ci doar obiecte.
Primitivele vor fi automat convertite in clasele lor wrapper,
int -> Integer, boolean -> Boolean, etc.
Collections-Exceptions-Working with files-Multithreading-Unit tests-VCS
Cele mai importante colectii sunt reprezentate prin interfetele:
List, Queue, Set, Map (chiar daca nu este o subinterfata a interfetei Collections)
Collections-Exceptions-Working with files-Multithreading-Unit tests-VCS
List
Collections-Exceptions-Working with files-Multithreading-Unit tests-VCS
Principalele particularitati ale interfetei List:
→ elemente sunt ordonate si sunt accesibile folosindu-ne de un index
→ se pastreaza ordinea inserarii
→ poti adauga la o pozitie specificata, doar daca pe aceasta pozitie exista
deja un element sau null
→ daca pozitia nu e specificata, elementul va fi adaugat la coada
Implementarile interfetei List pot sa inlocuiasca Array-urile, fiind mai eficiente
si dinamice. Daca unui Array trebuie sa-i specificam dimensiunea si aceasta
nu poate fi modificata ulterior, unui ArrayList nu trebuie sa-i specificam
dimensiunea de la declarare, aceasta putand avea 0 sau mai multe elemente.
Collections-Exceptions-Working with files-Multithreading-Unit tests-VCS
Cele mai importante implementari ale interfetei List sunt ArrayList si LinkedList
si este bine sa inlocuim Array in codul nostru cu una dintre aceste
implementari pentru un plus de performanta si flexibilitate.
Sintaxa:
ArrayList<String> list = new ArrayList<>();
LinkedList<String> list = new LinkedList<>();
Collections-Exceptions-Working with files-Multithreading-Unit tests-VCS
Este best practice sa ne referim la o colectie folosind referinte de tip abstract.
ArrayList si LinkedList implementeaza List deci putem rescrie astfel:
List<String> list = new ArrayList<>();
List<String> list = new LinkedList<>();
Collections-Exceptions-Working with files-Multithreading-Unit tests-VCS
ArrayList vs LinkedList
Elementele ambelor colectii sunt accesibile folosindu-ne de un index.
Ambele sunt implementari ale lui List, pastreaza ordinea inserarii, permit duplicate si null.
LinkedList implementeaza si interfata Deque care ii adauga functionalitati extra fata de ArrayList.
Adaugarea si stergerea in LinkedList sunt mai rapide decat pe ArrayList insa cautarea este mai putin
performanta.
Deci folosim ArrayList cand avem mai multe cautari in colectie si LinkedList cand avem adaugari si
stergeri mai frecvente.
Collections-Exceptions-Working with files-Multithreading-Unit tests-VCS
Cum utilizam o colectie de tip List?
Pentru a adauga intr-o colectie de tip List folosim metoda add(Object object).
Pentru a citi un element folosim metoda get(index);
Pentru a citi toate elementele putem folosi blocurile loop, precum for, for-Each sau while pentru a
parcurge colectia la fel cum parcurgem cand folosim Array.
Collections-Exceptions-Working with files-Multithreading-Unit tests-VCS
Queue
Collections-Exceptions-Working with files-Multithreading-Unit tests-VCS
Principalele particularitati ale interfetei Queue:
→ similar lui List, este o lista ordonata de elemente, se pastreaza ordinea inserarii
→ este creata pentru ca elementele sa se adauge la coada si sa se stearga/proceseze
de la capat
→ folosita atunci cand vrei sa procesezi elemente in ordinea in care le-ai inserat
→ exista si o subinterfata a lui Queue numita Deque care suporta procesarea de la
ambele capete
Collections-Exceptions-Working with files-Multithreading-Unit tests-VCS
Cele mai importante implementari ale interfetei Queue sunt
LinkedList, PriorityQueue, ArrayDeque.
Sintaxa:
Queue<String> pq = new PriorityQueue<>();
Queue<String> ll = new LinkedList<>();
Queue<String> ad = new ArrayDeque<>();
Collections-Exceptions-Working with files-Multithreading-Unit tests-VCS
Cum utilizam o colectie de tipul Queue?
Pentru a adauga intr-o colectie de tip Queue folosim metoda add(Object object).
Pentru a citi putem folosi blocul for-Each sau un iterator pentru a parcurge colectia.
Elementele interfetei Queue nu sunt accesibile folosindu-ne de un index, dar sunt accesibile folosindu-
ne de metode precum peek() care returneaza primul element din colectie sau poll() care retureaza
primul element din colectie pe care apoi il sterge.
Collections-Exceptions-Working with files-Multithreading-Unit tests-VCS
Set
Collections-Exceptions-Working with files-Multithreading-Unit tests-VCS
Principalele particularitati ale interfetei Set:
→ contine doar elemente unice, daca adaugi acelasi element de doua ori, este introdus
doar o data
→ nu garanteaza ordinea elementelor, nu pastreaza ordinea inserarii
→ exista o subinterfata a lui Set, numita SortedSet in care elementele sunt sortate
(foloseste un o implementare a interfetei Comparator, pentru a ordona elementele)
→ exista si o subinterfata a lui SortedSet numita NavigableSet cu metode de navigare
prin colectie
Collections-Exceptions-Working with files-Multithreading-Unit tests-VCS
Cele mai importante implementari ale interfetei Set sunt:
→ HashSet (super rapid, nu mentine ordinea adaugarii, nu sunt sortate, sunt adaugate in
functie de valoare hashcode-ului fiecarui element)
→ LinkedHashSet (mentine ordinea inserarii, nu sunt sortate, foloseste hashcode)
→ TreeSet (sortat, implementeaza NavigableSet, deci are metode de navigare in colectie)
Sintaxa:
Set<String> set1 = new HashSet<>();
Set<String> set2 = new LinkedHashSet<>();
Set<String> set3 = new TreeSet<>();
Collections-Exceptions-Working with files-Multithreading-Unit tests-VCS
List vs Set
Implementarile interfetei List au elementele ordonate, permit elemente duplicat si elementele
sunt accesibile la un index.
Implementarile lui Set au elementele neordonate, insa sunt unice, nu permit duplicat.
Collections-Exceptions-Working with files-Multithreading-Unit tests-VCS
Cum utilizam o colectie de tipul Set?
Pentru a adauga intr-o colectie de tip Set folosim metoda add(Object object).
Pentru a citi putem folosi blocul for-Each sau un iterator pentru a parcurge colectia.
Elementele interfetei Set nu sunt accesibile folosindu-ne de un index.
Collections-Exceptions-Working with files-Multithreading-Unit tests-VCS
Map
Collections-Exceptions-Working with files-Multithreading-Unit tests-VCS
Interfata Map nu este o subinterfata a interfetei Collection dar cand ne referim la
Colectii, de obicei includem si interfata Map cu implementarile ei.
Collections-Exceptions-Working with files-Multithreading-Unit tests-VCS
Principalele particularitati ale interfetei Map:
→ Map este o lista de cheie/valoare unde cheia este unica
→ exista o subinterfata a lui Map, numita SortedMap in care elementele sunt sortate
dupa cheie (foloseste Comparator)
→ exista si o subinterfata a lui SortedMap numita NavigableMap cu metode de
navigare prin colectie
Collections-Exceptions-Working with files-Multithreading-Unit tests-VCS
Ce insemna o lista de cheie / valoare?
Map - [ (cheie : valoare), (cheie : valoare), (cheie : valoare), (cheie : valoare), (cheie : valoare) ]
ArrayList - [element, element, element, element], fiecare element fiind accesibil la un index
0 1 2 3
Daca in cazul ArrayList elementele sunt acceasibile la un index numeric 0,1,2,3...n in cazul Map
elementele sunt accesibile printr-o cheie definita de utilizator care poate avea orice tip de date,
String, Integer, tipuri de date custom definite de utilizator precum Employee, User, CustomClass,
etc.
Un map poate avea ca si cheie un Employee si valoare Job
Map - [(Employee : Job), (Employee : Job)]
sau un String ca si cheie si valoare un alt String
Map - [(String : String), (String : String)]
etc.
Collections-Exceptions-Working with files-Multithreading-Unit tests-VCS
Cele mai importante implementari ale interfetei Map sunt:
→ HashMap (foarte eficient, nu are elementele ordonate sau sortate)
→ TreeMap (sortat in ordine naturala dupa cheie, implementeaza NavigableMap cu metode
de navigare prin colectie, este mai putin performant decat HashMap)
→ LinkedHashMap(ordinea inserarii mentinuta, accesarea elementelor rapida,
stergere/adaugare neperformanta)
Sintaxa:
Map<String, String> map1 = new HashMap<>();
Map<Employee, Integer> map2 = new LinkedHashMap<>();
Map<Employee, Integer> map3 = new TreeMap<>();
Collections-Exceptions-Working with files-Multithreading-Unit tests-VCS
Cum utilizam o colectie de tipul Map?
Pentru a adauga elemente intr-un map folosim metoda .put(cheie, valoare).
Pentru a accesa un element folosim metoda get(cheie);
Pentru a citi toate elementele folosim un bloc for pentru a itera pe lista de chei obtinute din map.
Apoi pentru fiecare cheie putem accesa valoarea ei.
Collections-Exceptions-Working with files-Multithreading-Unit tests-VCS
Pentru a stoca perechi cheie/valoare intr-un HashMap, cheia trece printr-un algoritm de
hashing din care rezulta o valoare numerica in functie de care se va stabili locul perechii
in HashMap.
De aceea fiecare tip de date folosit ca si cheie in HashMap trebuie sa implementeze
metodele equals si hashcode si este best practice ca aceste obiecte sa fie imutabile.
Trebuie sa fie imutabile pentru ca daca se modifica obiectul cheie nu mai poate fi gasita
apoi perechea in HashMap, hashCode-ul generat fiind altul.
Collections-Exceptions-Working with files-Multithreading-Unit tests-VCS
Recapitulare
Collections-Exceptions-Working with files-Multithreading-Unit tests-VCS
Ce sunt structurile de date?
Collections-Exceptions-Working with files-Multithreading-Unit tests-VCS
Ce sunt structurile de date?
Structurile de date reprezinta o modalitate
de a stoca si organiza informatia astfel
incat sa fie utilizata in mod eficient.
Collections-Exceptions-Working with files-Multithreading-Unit tests-VCS
De cate tipuri sunt structurile de date non-
primitive?
Collections-Exceptions-Working with files-Multithreading-Unit tests-VCS
De cate tipuri sunt structurile de date non-
primitive?
- lineare: datele sunt stocate intr-o maniera
secventiala (Arrays, Linked list, Stacks,
Queues)
- non-lineare (Trees)
Collections-Exceptions-Working with files-Multithreading-Unit tests-VCS
Care sunt cele mai cunoscute operatii pe care le
putem realiza pe structurile de date?
Collections-Exceptions-Working with files-Multithreading-Unit tests-VCS
Care sunt cele mai cunoscute operatii pe care le
putem realiza pe structurile de date?
- cautarea unui element
- sortarea structurii de date in ordine
ascendenta/descendenta
- inserarea unui element
- modificarea unui element
- stergerea unui element
Collections-Exceptions-Working with files-Multithreading-Unit tests-VCS
Ce este Collections Framework?
Collections-Exceptions-Working with files-Multithreading-Unit tests-VCS
Ce este Collections Framework?
Collections framework este un set de
interfete, implementari si algoritmi (metode
pentru sortare, cautare, etc.).
Collections framework implementeaza cele
mai importante structuri de date abstracte.
Collections-Exceptions-Working with files-Multithreading-Unit tests-VCS
Ce sunt colectiile?
Collections-Exceptions-Working with files-Multithreading-Unit tests-VCS
Ce sunt colectiile?
Colectiile sunt grupuri de obiecte tratate ca
o entitate. Unele dintre ele pot sa
inlocuiasca Array.
Collections-Exceptions-Working with files-Multithreading-Unit tests-VCS
Putem avea o colectie de primitive?
Collections-Exceptions-Working with files-Multithreading-Unit tests-VCS
Putem avea o colectie de primitive?
Nu, colectiile pot contine doar obiecte.
Collections-Exceptions-Working with files-Multithreading-Unit tests-VCS
Care sunt cele mai importante implementari ale
interfetei List?
Collections-Exceptions-Working with files-Multithreading-Unit tests-VCS
Care sunt cele mai importante implementari ale
interfetei List?
Cele mai importante implementari ale
interfetei List sunt ArrayList si LinkedList.
Collections-Exceptions-Working with files-Multithreading-Unit tests-VCS
Care sunt cele mai importante subinterfete ale
Collection?
Collections-Exceptions-Working with files-Multithreading-Unit tests-VCS
Care sunt cele mai importante subinterfete ale
Collection?
List, Queue, Set
Collections-Exceptions-Working with files-Multithreading-Unit tests-VCS
Implementarile interfetei Map sunt structuri de
date?
Collections-Exceptions-Working with files-Multithreading-Unit tests-VCS
Implementarile interfetei Map sunt structuri de
date?
Da, Map nu este o subinterfata a lui
Collection.
Collections-Exceptions-Working with files-Multithreading-Unit tests-VCS
Care sunt particularitatile interfetei List?
Collections-Exceptions-Working with files-Multithreading-Unit tests-VCS
Care sunt particularitatile interfetei List?
→ elemente sunt ordonate si sunt
accesibile folosindu-ne de un index
→ se pastreaza ordinea inserarii
→ poti adauga la o pozitie specificata, doar
daca pe aceasta pozitie exista deja un
element sau null
→ daca pozitia nu e specificata, elementul
va fi adaugat la coada
Collections-Exceptions-Working with files-Multithreading-Unit tests-VCS
Cum este stabilit locul unei perechi cheie/valoare
intr-un HashMap?
Collections-Exceptions-Working with files-Multithreading-Unit tests-VCS
Cum este stabilit locul unei perechi cheie/valoare
intr-un HashMap?
Cheia trece printr-un algoritm de hashing si
pe baza numarului rezultat se va stabili
locul perechii in Map.
Collections-Exceptions-Working with files-Multithreading-Unit tests-VCS
Cand folosim ArrayList si cand alegem LinkedList?
Collections-Exceptions-Working with files-Multithreading-Unit tests-VCS
Cand folosim ArrayList si cand alegem LinkedList?
Folosim ArrayList cand avem mai multe
cautari in colectie si LinkedList cand avem
adaugari si stergeri mai frecvente.
Collections-Exceptions-Working with files-Multithreading-Unit tests-VCS
Care sunt particularitatile interfetei Queue?
Collections-Exceptions-Working with files-Multithreading-Unit tests-VCS
Care sunt particularitatile interfetei Queue?
→ similar lui List, este o lista ordonata de
elemente, se pastreaza ordinea inserarii
→ este creata pentru ca elementele sa se
adauge la coada si sa se
stearga/proceseze de la capat
→ folosita atunci cand vrei sa procesezi
elemente in ordinea in care le-ai inserat
→ exista si o subinterfata a lui Queue
numita Deque care suporta procesarea de
la ambele capete
Collections-Exceptions-Working with files-Multithreading-Unit tests-VCS
Care sunt cele mai importante implementari ale
interfetei Queue?
Collections-Exceptions-Working with files-Multithreading-Unit tests-VCS
Care sunt cele mai importante implementari ale
interfetei Queue?
Cele mai importante implementari ale
interfetei Queue sunt LinkedList,
PriorityQueue, ArrayDeque.
Collections-Exceptions-Working with files-Multithreading-Unit tests-VCS
Care sunt particularitatile interfetei Set?
Collections-Exceptions-Working with files-Multithreading-Unit tests-VCS
Care sunt particularitatile interfetei Set? → contine doar elemente unice, daca
adaugi acelasi element de doua ori, este
introdus doar o data
→ nu garanteaza ordinea elementelor, nu
pastreaza ordinea inserarii
→ exista o subinterfata a lui Set, numita
SortedSet in care elementele sunt sortate
(foloseste un o implementare a interfetei
Comparator, pentru a ordona elementele)
→ exista si o subinterfata a lui SortedSet
numita NavigableSet cu metode de
navigare prin colectie
Collections-Exceptions-Working with files-Multithreading-Unit tests-VCS
Care sunt cele mai importante implementari ale
interfetei Set?
Collections-Exceptions-Working with files-Multithreading-Unit tests-VCS
Care sunt cele mai importante implementari ale
interfetei Set?
Cele mai importante implementari ale
interfetei Set sunt: HashSet,
LinkedHashSet, TreeSet.
Collections-Exceptions-Working with files-Multithreading-Unit tests-VCS
Ce se intampla daca cheia unei perechi
cheie/valoare dintr-un Map se modifica?
Collections-Exceptions-Working with files-Multithreading-Unit tests-VCS
Ce se intampla daca cheia unei perechi
cheie/valoare dintr-un HashMap se modifica?
Nu mai putem gasi valoarea in Map
folosind acea cheie, operatia
map.get(cheie); va returna null. De aceea
obiectele care vor fi folosite ca cheie in
HashMap trebuie sa fie imutabile.
Collections-Exceptions-Working with files-Multithreading-Unit tests-VCS
Care sunt particularitatile interfetelor Set si List?
Collections-Exceptions-Working with files-Multithreading-Unit tests-VCS
Care sunt particularitatile interfetelor Set si List?
Implementarile interfetei List au elementele
ordonate, permit elemente duplicat si
elementele sunt accesibile la un index.
Implementarile lui Set au elementele
neordonate, insa sunt unice, nu permit
duplicat.
Collections-Exceptions-Working with files-Multithreading-Unit tests-VCS
Care cele 4 interfete Map, Set, List, Queue, nu
este subinterfata a lui Collection?
Collections-Exceptions-Working with files-Multithreading-Unit tests-VCS
Care cele 4 interfete Map, Set, List, Queue, nu
este subinterfata a lui Collection?
Map
Collections-Exceptions-Working with files-Multithreading-Unit tests-VCS
Cu ce implementare a Collections putem inlocui
un Array fara a schimba functionalitatea?
Collections-Exceptions-Working with files-Multithreading-Unit tests-VCS
Cu ce implementare a Collections putem inlocui
un Array fara a schimba functionalitatea?
Cu orice implementare a interfetei List.
Collections-Exceptions-Working with files-Multithreading-Unit tests-VCS
Care sunt particularitatile interfetei Map?
Collections-Exceptions-Working with files-Multithreading-Unit tests-VCS
Care sunt particularitatile interfetei Map?
→ Map este o lista de cheie/valoare unde
cheia este unica
→ exista o subinterfata a lui Map, numita
SortedMap in care elementele sunt sortate
dupa cheie (foloseste Comparator)
→ exista si o subinterfata a lui SortedMap
numita NavigableMap cu metode de
navigare prin colectie
Collections-Exceptions-Working with files-Multithreading-Unit tests-VCS
Cum accesam o pereche cheie/valoare dintr-un
Map?
Collections-Exceptions-Working with files-Multithreading-Unit tests-VCS
Cum accesam o pereche cheie/valoare dintr-un
Map?
Folosim cheia pentru a aduce valoarea:
T valoare = map.get(cheie);
Collections-Exceptions-Working with files-Multithreading-Unit tests-VCS
Care sunt cele mai importante implementari ale
interfetei Map?
Collections-Exceptions-Working with files-Multithreading-Unit tests-VCS
Care sunt cele mai importante implementari ale
interfetei Map?
Cele mai importante implementari ale
interfetei Map sunt: HashMap,
LinkedHashMap, TreeMap.
Collections-Exceptions-Working with files-Multithreading-Unit tests-VCS
Cum este best practice sa fie obiectul care este
folosit ca si cheie intr-un map?
Collections-Exceptions-Working with files-Multithreading-Unit tests-VCS
Cum este best practice sa fie obiectul care este
folosit ca si cheie intr-un map?
Imutabil.
Collections-Exceptions-Working with files-Multithreading-Unit tests-VCS
Cand vrem sa eliminam elemente duplicat dintr-o
structura de date, in ce structura de date le
putem adauga ca sa ramana doar elemente
unice?
Collections-Exceptions-Working with files-Multithreading-Unit tests-VCS
Cand vrem sa eliminam elemente duplicat dintr-o
structura de date, in ce structura de date le
putem adauga ca sa ramana doar elemente
unice?
Daca adaugam elementele intr-o structura
de date de tip Set vom elimina elementele
duplicat.
Exceptions
Collections-Exceptions-Working with files-Multithreading-Unit tests-VCS
Exceptiile sunt evenimente sau probleme care au loc in timpul executiei unui program.
Cand apare o exceptie, fluxul normal al programului este alterat, iar programul se
termina anormal.
Collections-Exceptions-Working with files-Multithreading-Unit tests-VCS
Superclasa acestor tipuri de evenimente se numeste Throwable care la randul ei
mosteneste clasa Object (clasa parinte a tuturor obiectelor din Java).
Collections-Exceptions-Working with files-Multithreading-Unit tests-VCS
O exceptie poate avea loc din diferite motive:
- programul incearca citirea dintr-un fisier care nu exista;
- utilizatorul a transmis aplicatiei date invalide;
- - etc.
Collections-Exceptions-Working with files-Multithreading-Unit tests-VCS
Throwable objects se impart in 3 categorii:
- Checked exceptions
- Unchecked exceptions
- Errors
Collections-Exceptions-Working with files-Multithreading-Unit tests-VCS
Checked exceptions
Collections-Exceptions-Working with files-Multithreading-Unit tests-VCS
O exceptie checked este o exceptie notificata de compilator la compilare, de aceea se
mai numeste si exceptie la compile time.
Exceptiile checked nu pot fi ignorate de catre programator, ele trebuie tratate.
Java are o regula pentru aceste exceptii numita “handle or declare”.
Collections-Exceptions-Working with files-Multithreading-Unit tests-VCS
“Handle” sau tratatea exceptiei se face cu ajutorul blocului try-catch.
Codul din interiorul unui bloc try-catch se numeste cod protejat.
Sintaxa:
try {
//the try block = protected code
} catch(exception_type identifier) {
//exception handler
} finally {
//finally block
}
Collections-Exceptions-Working with files-Multithreading-Unit tests-VCS
Reguli de folosire try-catch:
- blocurile catch si finally sunt optionale, dar cel putin unul dintre ele
trebuie adaugat daca avem un bloc try
try {
//protected code
} //NU COMPILEAZA
Collections-Exceptions-Working with files-Multithreading-Unit tests-VCS
- putem avea mai multe ramuri catch, insa pe fiecare ramura trebuie
sa declaram alt tip de exceptie
try {
//protected code
} catch(ExceptionTypeOne ex) {
//catch block for the first type of exception
} catch (ExceptionTypeTwo ex) {
//catch block for the second type of exception
}
Collections-Exceptions-Working with files-Multithreading-Unit tests-VCS
- ordinea in care declaram blocurile catch este importanta, nu putem declara
mai intai o exceptie mai mare (mai ampla, parinte) si pe urmatorul bloc catch
sa tratam o exceptie mai mica (mai restrictiva, copil) deoarece compilatorul ne
atentioneaza ca avem “unreachable code”
try {
//protected code
} catch(ExceptionSuperclass ex) {
} catch (ExceptionSubclass ex) { // NU COMPILEAZA
}
Collections-Exceptions-Working with files-Multithreading-Unit tests-VCS
- putem prinde mai multe tipuri de exceptii intr-un singur bloc catch
try {
//protected code
} catch(ExceptionTypeOne | ExceptionTypeTwo ex) {
//catch block
}
Collections-Exceptions-Working with files-Multithreading-Unit tests-VCS
- nu putem prinde aceeasi exceptie pe mai multe ramuri catch
try {
//protected code
} catch(ExceptionTypeOne | ExceptionTypeTwo ex) {
//catch block
} catch (ExceptionTypeTwo ex) { //NU COMPILEAZA
}
Collections-Exceptions-Working with files-Multithreading-Unit tests-VCS
- codul din blocul finally este executat indiferent daca codul protejat arunca
sau nu exceptie
try {
//protected code
} catch (Exception ex) {
//catch block
} finally {
//executed whether or not the protected code throws exception
}
Collections-Exceptions-Working with files-Multithreading-Unit tests-VCS
Dintre exceptiile checked amintim:
- FileNotFoundException: este aruncata programatic atunci cand codul refera
un fisier care nu exista
- IOException: este aruncata programatic atunci cand are loc o problema in
timpul citirii dintr-un fisier sau in timpul scrierii intr-un fisier.
- SQLException
- ClassNotFoundException
Collections-Exceptions-Working with files-Multithreading-Unit tests-VCS
Daca nu tratam cu un bloc try/catch exceptiile Checked aruncate de o metoda
trebuie sa le aruncam mai departe metodelor de mai jos din stack pentru ca
una din ele sa le trateze sau sa le arunce catre JVM.
Pentru a specifica ca nu am tratat exceptia si trebuie sa o trateze o alta
metoda trebuie sa adaugam la declararea metodei specificatorul throws si
numele Exceptiei.
Collections-Exceptions-Working with files-Multithreading-Unit tests-VCS
public class AnotherClass {
public void anotherProcess() throws FileNotFoundException {
//This code throws java.io.FileNotFoundException
FileReader fr = new FileReader("D:\\testout.txt");
}
}
public class OtherClass {
public void otherProcess() throws FileNotFoundException {
AnotherClass anotherClass = new AnotherClass();
anotherClass.anotherProcess();
}
}
public class Main {
public static void main(String[] args) {
OtherClass otherClass = new OtherClass();
try {
otherClass.otherProcess();
} catch (FileNotFoundException e) {
e.printStackTrace();
}
}
}
Collections-Exceptions-Working with files-Multithreading-Unit tests-VCS
Unchecked exceptions
Collections-Exceptions-Working with files-Multithreading-Unit tests-VCS
O exceptie unchecked este o exceptie ce are loc la momentul executiei
programului, de aceea se mai numeste si exceptie la runtime.
Exceptiile unchecked reprezinta buguri cum ar fi erori de logica si utilizarea
gresita a API-ului.
Pentru exceptiile unchecked nu se aplica regula “handle or declare”, ele fiind
ignorate la compile time.
Cu toate acestea programatorul poate proteja codul folosind constructia try-
catch.
Collections-Exceptions-Working with files-Multithreading-Unit tests-VCS
Exceptiile unchecked sunt apartin claselor care extind clasa RuntimeException.
Collections-Exceptions-Working with files-Multithreading-Unit tests-VCS
Exemple de exceptii unchecked
ArithmeticException - este aruncata de JVM atunci cand in cod se incearca impartirea la zero.
ClassCastException - este aruncata de JVM atunci cand se incearca cast-ul unei clase la o alta clasa,
conversia facandu-se la o subclasa fara insa ca referinta sa fie instanta a subclasei.
ArrayIndexOutOfBoundsException - este aruncata de JVM atunci cand se incearca accesarea unui
index care nu exista in array-ul respectiv.
IllegalArgumentsException – este o exceptie unchecked aruncata de programator pentru a indica
faptul ca o metoda a fost apelata cu un argument ilegal.
NullPointerException – este o exceptie unchecked aruncata de JVM atunci cand in cod exista o
referinta nula desi ar fi trebuit sa existe un obiect.
NumberFormatException – aruncata atunci cand se vrea conversia de la String la un tip numeric desi
stringul respectiv nu are formatul corespunzator.
Collections-Exceptions-Working with files-Multithreading-Unit tests-VCS
Errors
Collections-Exceptions-Working with files-Multithreading-Unit tests-VCS
A treia categorie este reprezentata de clasa Error care extinde clasa Throwable,
dar difera de exceptii prin faptul ca programatorul nu ar trebui sa le trateze sau
sa le declare.
Erorile reprezinta conditii anormale din care un program nu isi poate reveni.
Collections-Exceptions-Working with files-Multithreading-Unit tests-VCS
Exemple de erori din Java:
ExceptionInInitializerError,
IllegalAccessError,
InternalError,
OutOfMemoryError.
Collections-Exceptions-Working with files-Multithreading-Unit tests-VCS
StackOverflowError.
Collections-Exceptions-Working with files-Multithreading-Unit tests-VCS
public class ErrorExample {
public static void main(String[] args) {
boolean flag = true;
printHello(flag);
}
public static void printHello(boolean flag) {
while (flag) {
printHello(flag);
}
}
}
Uitam sa mai facem flag-ul false. Rezultatul rularii programului va fi:
Exception in thread "main" java.lang.StackOverflowError at
CompanyJava/ro.company.exceptions.erorr.ErrorExample.printHello(ErrorExample.java:11)
Collections-Exceptions-Working with files-Multithreading-Unit tests-VCS
Exceptii Custom
Collections-Exceptions-Working with files-Multithreading-Unit tests-VCS
Programatorii pot defini propriile Exceptii care nu sunt in limbajul Java sau care
nu sunt incluse intr-o librarie externa.
Exceptiile custom sunt folosite pentru a fi aruncate atunci cand vrem sa trimitem
utilizatorilor un mesaj de eroare personalizat atunci cand in logica aplicatiei se
intampla un eveniment nedorit dar anticipat de programator.
Collections-Exceptions-Working with files-Multithreading-Unit tests-VCS
Exceptiile sunt de doua tipuri:
- checked (OurOwnException extends Exception)
- unchecked (AnotherCustomException extends RuntimeException)
Exceptiile checked trebuie tratate sau aruncate iar cele unchecked pot fi tratate
cu try/catch doar daca programatorul considera ca este necesar.
Collections-Exceptions-Working with files-Multithreading-Unit tests-VCS
In cele mai multe cazuri exceptiile definite de programatori sunt de tipul
Unchecked.
Sintaxa:
public class EmployeeAlreadyExistsException extends RuntimeException {
…
}
Collections-Exceptions-Working with files-Multithreading-Unit tests-VCS
Pentru a arunca o exceptie, checked sau unchecked, definita de programator
sau existenta in limbaj folosim specificatorul throw:
private void verifyIfEmployeeAlreadyExists(Employee employee) {
for(Employee oldEmployee : DatabaseSimulation.EMPLOYEES){
if(oldEmployee.equals(employee)){
throw new EmployeeAlreadyExistsException("Angajatul exista deja in baza de date!");
}
}
}
Recapitulare
Collections-Exceptions-Working with files-Multithreading-Unit tests-VCS
Ce sunt exceptiile?
Collections-Exceptions-Working with files-Multithreading-Unit tests-VCS
Ce sunt exceptiile?
Exceptiile sunt evenimente sau probleme
care au loc in timpul executiei unui
program.
Cand apare o exceptie, fluxul normal al
programului este alterat, iar programul se
termina anormal.
Collections-Exceptions-Working with files-Multithreading-Unit tests-VCS
Care este superclasa tuturor exceptiilor?
Collections-Exceptions-Working with files-Multithreading-Unit tests-VCS
Care este superclasa tuturor exceptiilor?
Throwable.
Collections-Exceptions-Working with files-Multithreading-Unit tests-VCS
Ce superclasa extind exceptiile checked?
Collections-Exceptions-Working with files-Multithreading-Unit tests-VCS
Ce superclasa extind exceptiile checked?
Exception.
Collections-Exceptions-Working with files-Multithreading-Unit tests-VCS
Ce superclasa extind exceptiile unchecked?
Collections-Exceptions-Working with files-Multithreading-Unit tests-VCS
Ce superclasa extind exceptiile unchecked?
RuntimeException.
Collections-Exceptions-Working with files-Multithreading-Unit tests-VCS
Ce superclasa extinde Error?
Collections-Exceptions-Working with files-Multithreading-Unit tests-VCS
Ce superclasa extinde Error?
Throwable
Collections-Exceptions-Working with files-Multithreading-Unit tests-VCS
Cum putem trata exceptiile?
Collections-Exceptions-Working with files-Multithreading-Unit tests-VCS
Cum putem trata exceptiile?
Folosind blocuri de cod try/catch.
Collections-Exceptions-Working with files-Multithreading-Unit tests-VCS
Cum se numeste blocul de cod care va fi
executat indiferent daca este aruncata o
exceptie sau nu?
Collections-Exceptions-Working with files-Multithreading-Unit tests-VCS
Cum se numeste blocul de cod care va fi
executat indiferent daca este aruncata o
exceptie sau nu?
Finally (try/catch/finally)
Collections-Exceptions-Working with files-Multithreading-Unit tests-VCS
Care dintre cele doua tipuri de exceptii trebuie
tratate cu try/catch sau aruncate cu throws
obligatoriu?
Collections-Exceptions-Working with files-Multithreading-Unit tests-VCS
Care dintre cele doua tipuri de exceptii trebuie
tratate cu try/catch sau aruncate cu throws
obligatoriu?
Checked (cele care extind Exception)
Collections-Exceptions-Working with files-Multithreading-Unit tests-VCS
Exista blocuri de cod try fara catch sau finally?
Collections-Exceptions-Working with files-Multithreading-Unit tests-VCS
Exista blocuri de cod try fara catch sau finally?
Da, este obigatoriu sa avem cel putin un
catch sau finally. Dar putem aveam atat
catch cat si finally in acelasi timp.
Collections-Exceptions-Working with files-Multithreading-Unit tests-VCS
Putem specifica pe ramura catch mai multe
exceptii?
Collections-Exceptions-Working with files-Multithreading-Unit tests-VCS
Putem specifica pe ramura catch mai multe
exceptii?
Da, folosim operatorul pipe | pentru a
specifica mai multe tipuri de exceptii.
} catch(ExceptionTypeOne | ExceptionTypeTwo ex) {
Collections-Exceptions-Working with files-Multithreading-Unit tests-VCS
Daca avem mai multe blocuri catch. Care este
ordinea in care trebuie sa specificam exceptiile?
Collections-Exceptions-Working with files-Multithreading-Unit tests-VCS
Daca avem mai multe blocuri catch. Care este
ordinea in care trebuie sa specificam exceptiile?
Trebuie sa le specificam in functie de
specificitatea lor. De la cea mai specifica la
cea mai generica.
SuperSuperException -> SuperException -> Exception
Collections-Exceptions-Working with files-Multithreading-Unit tests-VCS
Puteti da cateva exemple de exceptii Checked
prezente in limbaj?
Collections-Exceptions-Working with files-Multithreading-Unit tests-VCS
Puteti da cateva exemple de exceptii Checked
prezente in limbaj?
FileNotFoundException, IOException,
SQLException, ClassNotFoundException
Collections-Exceptions-Working with files-Multithreading-Unit tests-VCS
Puteti da cateva exemple de exceptii
Unchecked prezente in limbaj?
Collections-Exceptions-Working with files-Multithreading-Unit tests-VCS
Puteti da cateva exemple de exceptii
Unchecked prezente in limbaj?
ArithmeticException, ClassCastException,
ArrayIndexOutOfBoundsException
Collections-Exceptions-Working with files-Multithreading-Unit tests-VCS
Care este cea mai intalnita exceptie din limbajul
Java?
Collections-Exceptions-Working with files-Multithreading-Unit tests-VCS
Care este cea mai intalnita exceptie din limbajul
Java?
NullPointerException
Collections-Exceptions-Working with files-Multithreading-Unit tests-VCS
Exemple de Error prezente in limbaj?
Collections-Exceptions-Working with files-Multithreading-Unit tests-VCS
Exemple de Error prezente in limbaj?
OutOfMemoryError, StackOverflowError
Collections-Exceptions-Working with files-Multithreading-Unit tests-VCS
Cum putem crea o exceptie checked?
Collections-Exceptions-Working with files-Multithreading-Unit tests-VCS
Cum putem crea o exceptie checked?
Scriem o clasa care extinde Exception.
Collections-Exceptions-Working with files-Multithreading-Unit tests-VCS
Dar o exceptie unchecked?
Collections-Exceptions-Working with files-Multithreading-Unit tests-VCS
Dar o exceptie unchecked?
Scriem o clasa care extinde
RuntimeException
Collections-Exceptions-Working with files-Multithreading-Unit tests-VCS
Cum aruncam o exceptie?
Collections-Exceptions-Working with files-Multithreading-Unit tests-VCS
Cum aruncam o exceptie?
Folosim instructiunea
throw new ExceptionHere();
Collections-Exceptions-Working with files-Multithreading-Unit tests-VCS
Cum declaram ca o metoda arunca o exceptie
checked?
Collections-Exceptions-Working with files-Multithreading-Unit tests-VCS
Cum declaram ca o metoda arunca o exceptie
checked?
Folosim la declararea sa specificatorul
throws urmat de denumirea exceptiei.
Collections-Exceptions-Working with files-Multithreading-Unit tests-VCS
Daca o metoda declara ca arunca o exceptie
checked, mai trebuie sa trateze exceptia sau
trebuie sa o trateze metoda care o apeleaza?
Collections-Exceptions-Working with files-Multithreading-Unit tests-VCS
Daca o metoda declara ca arunca o exceptie
checked, mai trebuie sa trateze exceptia sau o
trebuie sa o trateze metoda care o apeleaza?
Metoda care o apeleaza trebuie sa trateze
exceptia.
Working with Files
Collections-Exceptions-Working with files-Multithreading-Unit tests-VCS
Input/Output streams (intrare/iesire sau citire/scriere)
Java efectueaza operatiunile de intrare/iesire
(denumite I/O de la Input/Output)
prin fluxuri (streams).
Un stream este legat de un strat fizic de catre sistemul I/O din Java pentru a efectua
operatiuni de intrare si de iesire. In general, un stream inseamna un flux continuu de date.
Un stream I/O reprezinta o sursa de intrare sau o destinatie de iesire.
Collections-Exceptions-Working with files-Multithreading-Unit tests-VCS
In functie de directia transferului de date, stream-urile pot fi:
- de iesire: care transfera datele dintr-o aplicatie catre exterior.
- de intrare: care transfera datele din exterior catre apliactie.
- bidirectionale: care transmit datele in ambele directii.
Collections-Exceptions-Working with files-Multithreading-Unit tests-VCS
Un stream poate reprezenta mai multe tipuri de surse si destinatii:
fisiere pe disc, dispozitive, alte programe, memoria RAM, consola, sockets.
Collections-Exceptions-Working with files-Multithreading-Unit tests-VCS
Ce este un socket?
Un socket este un punct final al unei legaturi de comunicatie bidirectionala intre doua
programe care ruleaza in retea.
Clasele socket sunt utilizate pentru a reprezenta conexiunea dintre un program client si un
program server.
Packetul java.net ofera doua clase - Socket si ServerSocket - care implementeaza partea
de client a conexiunii, respectiv partea de server a conexiunii.
Collections-Exceptions-Working with files-Multithreading-Unit tests-VCS
Exista doua tipuri de streamuri:
- Byte stream (flux de octeti): ofera un mijloc convenabil de gestionare a intrarii si iesirii de
octeti.
- Character stream (flux de caractere): ofera un mijloc convenabil de gestionare a intrarii si
iesirii de caractere. Fluxul de caractere utilizeaza Unicode si, prin urmare, poate fi
internationalizat.
Collections-Exceptions-Working with files-Multithreading-Unit tests-VCS
Byte Stream (flux de octeti)
Fluxul de octeti este definit prin utilizarea a doua clase abstracte in partea de sus a
ierarhiei, acestea fiind InputStream si OutputStream.
Collections-Exceptions-Working with files-Multithreading-Unit tests-VCS
Character Stream
Fluxul de caractere este, de asemenea, definit prin utilizarea a doua clase abstracte in
partea de sus a ierarhiei, acestea fiind Reader si Writer.
Collections-Exceptions-Working with files-Multithreading-Unit tests-VCS
Clasa File
Inainte de a ne focusa pe aceste clase in detaliu, trebuie sa aducem in discutie clasa File
care face parte din pachetul java.io si care ne ajuta sa lucram cu fisierele si folderele de pe
disc.
Clasa File nu se ocupa cu scrierea si citirea din/in fisiere, ci contine informatii despre
fisierele si structura directoarelor de pe disc.
Atunci cand cream un obiect al clasei File, nu inseamna ca am creat un fisier pe disc.
Clasa File contine mai multe metode pentru crearea, stergerea si redenumirea fisierelor,
crearea de directoare noi, listarea continutului unui director si determinarea mai multor
atribute comune ale fisierelor si directoarelor.
Collections-Exceptions-Working with files-Multithreading-Unit tests-VCS
Clasa File este o reprezentare abstracta a cailor de acces ale fisierului sau folderului.
Instanta clasei File este imutabila; adica, odata creata, calea abstracta reprezentata de un
obiect File nu se va schimba niciodata.
Pentru a folosi clasa File, trebuie sa o importam:
import java.io.File;
Pentru a vedea ce constructori si metode sunt disponibile in clasa File, putem consulta
documentatia oficiala: https://docs.oracle.com/javase/8/docs/api/java/io/File.html
Collections-Exceptions-Working with files-Multithreading-Unit tests-VCS
Byte Streams – clasele FileInputStream si FileOutputStream
FileInputStream si FileOutputStream sunt doua clase folosite pentru a citi si scrie informatie
octet cu octet. Sunt folosite in special pentru fisiere care contin octeti, precum imaginile.
Collections-Exceptions-Working with files-Multithreading-Unit tests-VCS
ByteArrayInputStream si ByteArrayOutputStream
ByteArrayInputStream este o clasa cu ajutorul careia putem citi un sir de octeti ca flux de
intrare, dupa cum sugereaza si numele.
ByteArrayOutputStream este o clasa cu ajutorul careia putem scrie un sir de octeti ca flux
de iesire.
Collections-Exceptions-Working with files-Multithreading-Unit tests-VCS
ObjectInputStream si ObjectOutputStream
Clasa ObjectOutputStream din pachetul java.io poate fi utilizata pentru a scrie obiecte care
pot fi citite de clasa ObjectInputStream.
Clasa ObjectOutputStream extinde OutputStream.
ObjectOutputStream codifica obiecte Java folosind numele clasei si starea obiectului,
generand fluxuri de date corespunzatoare. Acest proces este cunoscut sub numele de
serializare.
Aceste fluxuri convertite pot fi stocate in fisiere sau tranferate intre retele de calculatoare.
ObjectOutputStream/ObjectInputStream pot lucra doar cu clase care implementeaza
interfata Serializable.
Collections-Exceptions-Working with files-Multithreading-Unit tests-VCS
Interfata Serializable
Interfata Serializable face parte din pachetul java.io si este o interfata marker, in sensul ca
marcheaza clasele care o implementeaza ca fiind clase (obiecte) ce pot fi
serializate/deserializate.
Serializarea (scrierea) obiectelor in Java se face cu ObjectOutputStream, iar deserializarea
(citirea) se face cu ObjectInputStream.
Pentru ca Serializable este o interfata marker inseamna ca nu are membri, nu contine nici o
metoda, prin urmare clasa care implementeaza interfata Serializable nu trebuie sa
implementeze metode specifice.
Collections-Exceptions-Working with files-Multithreading-Unit tests-VCS
ObjectInputStream
Clasa ObjectInputStream a pachetului java.io poate fi utilizata pentru a citi obiecte care au
fost scrise anterior de ObjectOutputStream.
Clasa ObjectInputStream extinde InputStream.
Clasa ObjectOutputStream mai intai converteste obiectele ce pot fi serializate in fluxuri de
date, le stocheaza in fisiere sau le transmite in retea, apoi aceste fluxuri de date pot fi citite
de catre ObjectInputStream si convertite inapoi in obiecte Java. Acest proces este cunoscut
ca deserializare.
Collections-Exceptions-Working with files-Multithreading-Unit tests-VCS
BufferedInputStream si BufferedOutputStream
BufferedInputStream si BufferedOutputStream utilizeaza un array intern de octeti, cunoscut
si sub numele de buffer, pentru a stoca date in timpul citirii, respectiv scrierii. Buffered
streams sunt de obicei mai eficiente decat non-buffered streams.
Collections-Exceptions-Working with files-Multithreading-Unit tests-VCS
Character streams
Platforma Java stocheaza valorile caracterelor folosind conventiile Unicode. Fluxul de
caractere I/O traduce automat acest format intern in si din setul de caractere local.
Pentru majoritatea aplicatiilor, operatiile de I/O realizate cu ajutorul fluxurilor de caractere,
nu sunt mai complicate decat cele realizate cu fluxurile de octeti. Intrarea si iesirea realizate
cu clasele specifice fluxurilor de caractere, se traduc automat in si din setul de caractere
locale. Un program care foloseste fluxuri de caractere in locul fluxurilor de octeti se
adapteaza automat la setul de caractere locale.
Collections-Exceptions-Working with files-Multithreading-Unit tests-VCS
Platforma Java stocheaza valorile caracterelor folosind conventiile Unicode. Fluxul de
caractere I/O traduce automat acest format intern in si din setul de caractere local.
Pentru majoritatea aplicatiilor, operatiile de I/O realizate cu ajutorul fluxurilor de caractere,
nu sunt mai complicate decat cele realizate cu fluxurile de octeti. Intrarea si iesirea realizate
cu clasele specifice fluxurilor de caractere, se traduc automat in si din setul de caractere
locale. Un program care foloseste fluxuri de caractere in locul fluxurilor de octeti se
adapteaza automat la setul de caractere locale.
Collections-Exceptions-Working with files-Multithreading-Unit tests-VCS
Principalul avantaj al fluxurilor de caractere este ca faciliteaza scrierea de programe care
nu depind de o anumita encodare (codificare a caracterelor) => sunt usor de
internationalizat.
Java stocheaza sirurile de caractere in Unicode care este un standard international de
codificare a caracterelor. Cu ajutorul Unicode pot fi reprezentate majoritatea caracterelor
din limbile scrise.
Fisierele text tipice care pot fi citite de catre utilizatori, pot folosi codificari ca nu sunt
neaparat legate de Unicode, exista multe alte tipuri de codificari de caractere.
La finalul acestei pagini exista o lista cu cele mai comune codificari de caractere si
subseturile lor: https://en.wikipedia.org/wiki/Character_encoding#:~:text=Common
%20examples%20of%20character%20encoding,Interchange%20(ASCII)%20and
%20Unicode.
Collections-Exceptions-Working with files-Multithreading-Unit tests-VCS
Fluxurile de caractere ascund complexitatea gestionarii acestor codificari oferind doua
clase care servesc drept punte intre fluxurile de octeti si fluxurile de caractere.
Un alt avantaj al fluxurilor de caractere este ca au potentialul de a fi mult mai eficiente decat
fluxurile de octeti.
Maven
(short introduction)
Collections-Exceptions-Working with files-Multithreading-Unit tests-VCS
Maven este o unealta folosita pentru a crea un proiect si pentru a-i manageria dependintele.
Este un build tool, compileaza codul folosind compilatorul, executa unit tests etc.
Acesta standardizeaza si structura folderelor intr-o aplicatie.
Collections-Exceptions-Working with files-Multithreading-Unit tests-VCS
Aplicatiile Java pot folosi diferite librarii open source, gratuite.
Acestea introduc functionalitati noi aplicatiei pe care o dezvoltam.
Unul dintre scopurile Maven este sa managerieze aceste dependinte.
Acesta le descarca de pe diferite servere si le adauga proiectului nostru.
Fisierul de configurare Maven este numit pom.xml (Project Object Model).
Collections-Exceptions-Working with files-Multithreading-Unit tests-VCS
Pe langa managementul dependintelor, Maven, poate crea si o
arhiva a aplicatiei noastre de tip JAR (Java Archive), WAR (Web
Application Archive), etc. care poate fi distribuita.
Collections-Exceptions-Working with files-Multithreading-Unit tests-VCS
Pentru a crea o aplicatie care foloseste Maven cu Intellij urmam urmatorii pasi:
File -> New -> Project -> Selectam Maven - > Dam un nume proiectului si locatia pe
HDD
Collections-Exceptions-Working with files-Multithreading-Unit tests-VCS
Structura proiectului generat este similara cu cea din exemplul urmator:
Folderul main/java va contine fisierele .java cu cod organizat in pachete si main/resources
fisiere de configurare, fisiere statice precum .html .js, .xml, etc.
Folderul test/java va avea aceeasi structura a pachetelor precum cea a folderului main/java
insa clasele din acest folder vor contine teste pentru clasele din pachetul main.
Collections-Exceptions-Working with files-Multithreading-Unit tests-VCS
Pentru a adauga dependente proiectului nostru accesam fisierul pom.xml si adugam
dependente intre tag-urile:
<dependencies>
…
</dependencies>
Collections-Exceptions-Working with files-Multithreading-Unit tests-VCS
De unde putem lua dependente Maven?
Cel mai cunoscut repository cu
dependente este Maven Central si
este accesibil la
https://mvnrepository.com/repos/central
Fiecare companie poate avea un repository intern cu dependinte specifice acelei companii,
pe care le putem accesa si le putem adauga proiectului nostru.
Collections-Exceptions-Working with files-Multithreading-Unit tests-VCS
In acest repository putem cauta dependente precum, JUnit (JUnit Jupiter Engine), folosita
pentru a crea teste unitare codului nostru.
<dependency>
<groupId>org.junit.jupiter</groupId>
<artifactId>junit-jupiter-engine</artifactId>
<version>5.7.0</version>
<scope>test</scope>
</dependency>
Dupa adaugarea dependintei in pom.xml aceasta va fi descarcata si clasele ei vor fi
disponibile in proiectul nostru.
Collections-Exceptions-Working with files-Multithreading-Unit tests-VCS
Aceleasi dependinte adaugate folosind Maven pot fi adaugate si unui proiect clasic Java,
precum cele pe care le-am vazut pana acum.
Insa folosind Maven, acesta le descarca si le adauga pentru noi in proiect.
Exista si tooluri mai noi si mai performante decat Maven, precum Gradle, insa Maven inca
este solutia cea mai folosita in proiecte.
Unit tests
Collections-Exceptions-Working with files-Multithreading-Unit tests-VCS
Testele unitare sunt teste scrise de programatori si verifica
daca o unitate de cod se comporta asa cum a fost proiectata.
Collections-Exceptions-Working with files-Multithreading-Unit tests-VCS
Aceste teste pot fi executate de fiecare data cand dorim sa ne
asiguram ca modificarile facute in cod nu afecteaza alte zone testate.
Collections-Exceptions-Working with files-Multithreading-Unit tests-VCS
O clasa de test este o clasa Java in care avem metode adnotate cu @Test.
Collections-Exceptions-Working with files-Multithreading-Unit tests-VCS
Sintaxa:
class TestClass {
@Test
public void should_returnResult_when_parametersArePassed() {
MyClass myClass = new MyClass();
assertEquals(7, myClass.sum(2,5))
};
}
Collections-Exceptions-Working with files-Multithreading-Unit tests-VCS
Printr-o unitate de cod intelegem testarea metodelor, acestea fiind cea mai
mica unitate de cod care poate fi testata.
Collections-Exceptions-Working with files-Multithreading-Unit tests-VCS
Testarea unitara a codului este importanta pentru ca putem testa toate
conditiile unei metode si astfel vom stii ca, codul nostru se comporta asa
cum am planuit atunci cand l-am scris.
Collections-Exceptions-Working with files-Multithreading-Unit tests-VCS
Testele ne ofera siguranta ca o data modificata o parte a aplicatiei nu am
afectat alta zona a sa.
Collections-Exceptions-Working with files-Multithreading-Unit tests-VCS
In programare pe masura ce aplicatiile devin din ce in ce mai mari, fara
teste unitare va fi foarte dificil sa modificam, sa adaugam sau sa
imbunatatim functionalitati existente.
Collections-Exceptions-Working with files-Multithreading-Unit tests-VCS
Testele unitare sunt grupate in pachete si clase similar codului de productie.
Collections-Exceptions-Working with files-Multithreading-Unit tests-VCS
JUnit este cel mai cunoscut framework de testare unitara pentru
aplicatii Java.
Collections-Exceptions-Working with files-Multithreading-Unit tests-VCS
Cand scriem un test verificam daca o metoda returneaza ceea ce ne asteptam sa
returneze.
Metodele statice de tip assert din clasa Assertions se folosesc pentru a verifica daca
rezultatul returnat de o metoda este ceea ce asteptam.
Fara o metoda de assert testele noastre nu au niciun scop real.
Exemplu de metoda de assert:
assertEquals(7, myClass.sum(2,5));
Pe langa metoda assertEquals() care este supraincarcata de multe ori cu diferite tipuri de
date, in clasa Assertions gasim si alte metode de assert: assertArrayEquals(..),
assertNotEquals(...), assertTrue(...), assertFalse(...), assertNull(...), assertNotNull(...)
Collections-Exceptions-Working with files-Multithreading-Unit tests-VCS
Reguli de denumire a testelor
Sunt mai multe reguli de denumire a testelor, printre cele mai populare sunt formele:
Should_ExpectedBehavior_When_StateUnderTest:
Should_ThrowException_When_AgeLessThan18,
Should_FailToWithdrawMoney_ForInvalidAccount,
Should_FailToAdmit_IfMandatoryFieldsAreMissing
test[Feature being tested]:
testIsNotAnAdultIfAgeLessThan18,
testFailToWithdrawMoneyIfAccountIsInvalid,
testStudentIsNotAdmittedIfMandatoryFieldsAreMissing
Collections-Exceptions-Working with files-Multithreading-Unit tests-VCS
Cum testam unitar metode care apeleaza alte
metode?
Pentru a testa unitar o metoda, trebuie sa o izolam de
restul metodelor pe care ea le apeleaza.
Collections-Exceptions-Working with files-Multithreading-Unit tests-VCS
Ce este Mokito?
Mockito este un framework de mocking, cu ajutorul
caruia poti inlocui obiecte concrete cu alte obiecte
virtuale (mocks) si poti simula raspunsuri venite de la
metodele acestor obiecte.
Collections-Exceptions-Working with files-Multithreading-Unit tests-VCS
Cum putem izola o metoda pentru a o putea testa unitar?
Pentru a putea izola o metoda care apeleaza alte metode
putem folosi un framework de mock-ing precum Mockito.
Collections-Exceptions-Working with files-Multithreading-Unit tests-VCS
In exemplul de mai jos, metoda saveOrUpdate() apeleaza la randul sau 2 metode,
employeeRepository.update(employee); si employeeRepository.save(employee);
pe care nu vrem sa le testam. Pentru izolarea metodei saveOrUpdate() trebuie sa inlocuim implementarea
employeeRepository cu o clasa fictiva si apoi sa inlocuim rezultatul returnat de metodele save si update.
Metoda ce trebuie testata: saveOrUpdate() class EmployeeServiceImplTest {
//Mock the repository
class EmployeeServiceImpl implements EmployeeService { EmployeeRepository employeeRepository = Mockito.mock(EmployeeRepositoryImpl.class);
private EmployeeRepository employeeRepository; //Create the class under test
EmployeeService employeeService = new EmployeeServiceImpl(employeeRepository);
public EmployeeServiceImpl(EmployeeRepository employeeRepository) {
this.employeeRepository = employeeRepository;
@Test
} public void should_saveEmployee_when_newEmployeeIsPassed(){
//create a new employee
@Override Address address = new Address("Str1", "85b");
public void saveOrUpdate(Employee employee) { Employee employee = new Employee(1, "John Doe", 10000, address);
//check if employee is already in the database
Employee dbEmployee = employeeRepository.getById(employee.getId());
//mock get employee
if(dbEmployee != null){
when(employeeRepository.getById(1)).thenReturn(null);
//if it exists, update
employeeRepository.update(employee);
} else { //save employee
//else save it employeeService.saveOrUpdate(employee);
employeeRepository.save(employee);
} verify(employeeRepository, times(1)).save(employee);
} verify(employeeRepository, times(0)).update(employee);
}
}
Collections-Exceptions-Working with files-Multithreading-Unit tests-VCS
Cum testam metode private?
Putem testa metode private prin intermediul metodelor publice care le apeleaza.
Collections-Exceptions-Working with files-Multithreading-Unit tests-VCS
Cum testam metode care nu returneaza nimic?
Ca sa testam metode care nu returneaza nimic putem fie sa testam daca au
modificat starea unui obiect sau putem verifica daca in interiorul lor s-a apelat o
anumita metoda cu un anumit parametru asteptat.
@Test
public void should_deleteAllEmployees(){
//create an employee, save him
Address address = new Address("Str1", "85b");
Employee employee = new Employee(1, "John Doe", 10000, address);
employeeRepository.save(employee);
//create an employee, save him
Employee employee2 = new Employee(2, "Mary Doe", 12000, address);
employeeRepository.save(employee2);
//delete all employees
employeeRepository.deleteAll();
assertEquals(0, employeeRepository.getAll().size());
}
Collections-Exceptions-Working with files-Multithreading-Unit tests-VCS
Ce este code coverage?
Code coverage reprezinta procentul de cod de productie acoperit de teste unitare. Putem rula testele
unitare dintr-o aplicatie si putem vedea ce zone de cod au fost testate si care nu au fost testate.
Collections-Exceptions-Working with files-Multithreading-Unit tests-VCS
Ce alte tipuri de testare mai exista?
Mai exista si testare de integrare, care testeaza mai multe componente ale
aplicatiei in acelasi timp dar si testarea functionala sau e2e care testeaza
aplicatia simuland interactiunea unui utilizator cu interfata aplicatiei.
Multithreading
Collections-Exceptions-Working with files-Multithreading-Unit tests-VCS
Ce este un procesor?
Din ce este format un procesor?
Ce este un Thread? Ce este Hyperthreading?
Procesorul este componenta care executa
instructiunile transmise de programe. Un
procesor este format din unul sau mai multe
core-uri, fiecare core are un thread fizic dar cu
tehnologia Hyperthreading acesta poate avea
doua thread-uri logice cu ajutorul carora poate
procesa informatia in paralel pana o transmite
threadului fizic pentru a continua procesarea.
Fiecare aplicatie are un proces, fiecare proces
poate fi format din unul sau mai multe
threaduri si in general este bine in programe
sa ai atatea thread-uri cate core-uri/threaduri
ai, bineinteles, daca ai ce sa faci pe ele, pentru
ca in unele cazuri procesul de imparire a
taskului pe threaduri, procesarea in paralel si In cazul procesoarelor cu Hyperthreading daca cele doua threaduri logice
termina procesarea in acelasi timp unul dintre ele trebuie sa astepte pe
apoi de unire a rezultatelor este mai ineficient
celalalt sa dea informatia mai departe threadului fizic, deci va fi un fel de
decat procesarea directa pe un singur thread. ambuteiaj. Cresterea in performanta este doar atunci cand unul dintre
Exista mai multe tipuri de procesoare: Single threaduri termina mai repede decat celalalt.
Core, Multi Core si Multi Core cu Diferenta de performanta intre un procesor cu Hyperthreading si altul fara
Hyperthreading. este de aproximativ 25%.
Collections-Exceptions-Working with files-Multithreading-Unit tests-VCS
Platforma Java a fost proiectata astfel incat sa suporte programarea concurenta.
Concurenta (Concomitenta) reprezinta capacitatea sistemelor de a executa mai
multe operatii simultan, eventual interactionand unele cu altele.
In programarea concurenta, exista doua unitati de baza: procesul si firul de executie.
Collections-Exceptions-Working with files-Multithreading-Unit tests-VCS
Un proces reprezinta un set de activitati care interactioneaza pentru a produce un
rezultat, este un program in executie.
De multe ori procesele sunt considerate sinonime cu programele/aplicatiile, insa o
aplicatie poate avea mai multe procese.
Un proces are un mediu de executie autonom. Fiecare proces are propriul spatiu de
memorie si are in general un set de resurse de baza in timpul rularii.
Collections-Exceptions-Working with files-Multithreading-Unit tests-VCS
Firele de executie mai sunt numite si procese lightweight.
Un proces are cel putin un fir de executie. In cazul in care un proces are
mai multe fire de executie (threads) acestea pot sa proceseze in paralel.
Firele de executie impartasesc resursele din cadrul unui proces.
Acest lucru sporeste performanta, dar poate duce si la diverse probleme.
Concomitenta promite executarea anumitor task-uri mai rapid, acestea
fiind impartite in subtask-uri, iar subtask-urile executandu-se in paralel.
Performanta posibila teoretica obtinuta se calculeaza cu Legea Amdahl.
Daca taskurile nu sunt mari, de exemplu procesarea unui fisier mare,
concomitenta poate incetini procesul deoarece impartirea taskurilor in
subdiviziuni de lucru dureaza.
Collections-Exceptions-Working with files-Multithreading-Unit tests-VCS
Posibile probleme ale concurentei sunt:
Vizibilitatea (daca thread-ul A citeste informatii share-uite de thread B,
apoi thread B modifica informatiile, atunci thread A nu va sti de aceasta
modificare)
Accesul (se intampla atunci cand mai multe thread-uri vor sa acceseze si
sa modifice informatiile in acelasi timp). Aceste probleme cauzeaza
deadlock-uri (programul nu mai reactioneaza) sau programul furnizeaza
informatii incorecte.
Collections-Exceptions-Working with files-Multithreading-Unit tests-VCS
Fiecare fir de executie este asociat cu o instanta a clasei Thread.
Exista doua strategii de baza de utilizare a firelor de executie in vederea
crearii unei aplicatii concurente.
Collections-Exceptions-Working with files-Multithreading-Unit tests-VCS
Prima strategie se refera la controlarea in mod direct a crearii si a
gestionarii firelor de executie.
De fiecare data cand aplicatia trebuie sa initieze o activitate asincrona,
vom instantia clasa Thread.
Collections-Exceptions-Working with files-Multithreading-Unit tests-VCS
A doua strategie se refera la abstractizarea gestionarii firelor de executie,
trasmitand sarcinile aplicatiei unui executor.
Executorii definesc un API de nivel inalt pentru lansarea si gestionarea
firelor. Implementarile executorilor furnizate de java.util.concurrent
asigura gestionarea pool-ului de thread-uri adecvat pentru aplicatii pe
scara larga.
Collections-Exceptions-Working with files-Multithreading-Unit tests-VCS
Exista doua modalitati de a crea un fir de executie utilizand prima strategie.
1. Prin extinderea clasei Thread din pachetul java.lang si suprascrierea metodei run()
din clasa Thread.
public class MyThread extends Thread {
public void run() {
System.out.println("Thread started...");
}
}
Ca sa pornim firul de executie:
public class Main {
public static void main(String[] args) {
(new MyThread()) } .start();
}
Collections-Exceptions-Working with files-Multithreading-Unit tests-VCS
2. Prin implementarea interfetei Runnable care este o interfata functionala si care
contine o metoda abstracta run(). Clasa Thread implementeaza la randul ei aceasta
interfata.
public class MyThread implements Runnable {
public void run() {
System.out.println("Thread started...");
}
}
Ca sa pornim firul de executie:
public class Main {
public static void main(String[] args) {
(new Thread(new MyThread())).start();
}
}
Collections-Exceptions-Working with files-Multithreading-Unit tests-VCS
In ambele situatii, pentru a porni thread-ul, apelam metoda start() existenta in clasa Thread.
Este de preferat sa folosim cea de-a doua varianta (implementarea interfetei Runnable)
deoarece obiectul nostru Runnable poate fi clasa-copil a oricarei alte clase, nu neaparat a
clasei Thread. Asadar folosind aceasta optiune avem mai multa flexibilitate.
Collections-Exceptions-Working with files-Multithreading-Unit tests-VCS
Ciclul de viata al firelor de executie
1. New – orice fir de executie isi incepe ciclul de viata in starea new si ramane in aceasta
stare pana cand aplicatia porneste firul.
2. Runnable – dupa ce aplicatia a pornit firul, acesta trece in starea runnable si se
considera ca firul este in executie.
3. Waiting – un fir poate fi in asteptare pana ce alt fir isi termina executia. Atunci cand firul in
cauza se termina de executat, firul care este in asteptare trece in executie, adica devine
runnable.
4. Timed Waiting – un fir poate trece in starea de asteptare pentru un anumita perioada de
timp, ca apoi la finalul scurgerii timpului sa treaca in executie.
5. Terminated (Dead) – la finalul executiei unui fir, acesta trece in starea terminated,
insemnand ca a terminat de executat task-ul.
Collections-Exceptions-Working with files-Multithreading-Unit tests-VCS
Metode disponibile in clasa Thread
Clasa Thread defineste o serie de metode utile pentru gestionarea firelor de executie.
API-ul complet poate fi consultat aici:
https://docs.oracle.com/javase/8/docs/api/java/lang/Thread.html
Collections-Exceptions-Working with files-Multithreading-Unit tests-VCS
Metoda start porneste executarea firului, JVM apeleaza metoda run() al firului de executie.
De asemenea cu ajutorul metodei sleep putem pune pe pauza executia firului. La apelul
acestei metode, firul isi va suspenda executia pentru o anumita perioada de timp.
Exista doua variante ale metodei sleep. Una care primeste ca parametru un numar de
milisecunde reprezentand numarul de milisecunde pentru care firul sa-si intrerupa executia.
A doua varianta asteapta doua argumente: numarul de milisecunde si numarul de
nanosecunde care reprezinta perioada (nr. milisecunde + nr. nanosecunde) pentru care firul
sa-si suspende executia.
Un fir de executie poate fi intrerupt cu ajutorul metodei interrupt. Prin intrerupere se intelege
in general ca firul isi termina executia.
Metoda join permite unui fir sa astepte alt fir sa-si termine executia.
Metoda setName ne permite sa dam un anumit nume firului de executie.
Cu ajutorul metodei setPriority putem specifica o prioritate (MIN_PRIORITY = 1 si
MAX_PRIORITY = 10). By default, fiecare fir are prioritatea NORM_PRIORITY = 5.
Collections-Exceptions-Working with files-Multithreading-Unit tests-VCS
Asincronicitatea
Intr-un model de programare sincrona, task-urile se executa pe rand.
Cand este apelata o functie care efectueaza o actiune de lunga durata, aceasta intoarce
rezultatul cand actiunea s-a incheiat, iar in timpul acesta programul asteapta dupa rezultat.
De abia cand se primeste rezultatul, se trece mai departe la urmatorul task.
Un model asincron permite ca mai multe task-uri sa se intample in acelasi timp.
Collections-Exceptions-Working with files-Multithreading-Unit tests-VCS
Lucrul cu mai multe fire de executie introduce un comportament asincron.
Dezavantajul ar fi ca pot aparea inconsistente. De exemplu, daca un thread citeste niste
informatii (dintr-un fisier, din baza de date, din alta clasa) si alt thread modifica informatiile
respective, acest lucru se poate intampla in acelasi timp, fapt ce duce la date inconsistente.
Cand doua sau mai multe fire de executie trebuie sa acceseze aceleasi resurse este nevoie
sa facem astfel incat firele de executie sa acceseze resursele respective pe rand pentru a
elimina inconsistentele. Acest lucru este posibil cu ajutorul sincronizarii.
Pentru a crea zone mutex (sincronizate) putem folosi specificatorul syncronized insa nu
este singurul mod prin care putem realiza sincronizarea, putem folosi si Semaphores sau
Lock API.
Collections-Exceptions-Working with files-Multithreading-Unit tests-VCS
Ce este Mutual Exclusion (Mutex)?
Mutual Exclusion este modul prin care protejam blocuri de cod sa nu poata fi accesate de
doua sau mai multe threaduri in acelasi timp. Este un mod de a proteja un “critical section”.
In Java specificatorul syncronized, Lock API sau Semaphores sunt folosite pentru a proteja
un “critical section”.
Collections-Exceptions-Working with files-Multithreading-Unit tests-VCS
Semaphores sunt un alt mod prin care putem realiza sincronizarea unei zone a codului
nostru.
Clasa Semaphore din Java controleaza accesul firelor de executie la o resursa partajata
prin intermediul unui contor.
Daca contorul este mai mare ca zero, atunci accesul la resursa este permis.
Daca contorul ajunge la zero, atunci accesul este refuzat.
Exemple:
https://www.baeldung.com/java-semaphore
https://www.geeksforgeeks.org/semaphore-in-java/
Collections-Exceptions-Working with files-Multithreading-Unit tests-VCS
Ce inseamna Thread-Safe?
Un obiect thread safe este un obiect ce poate fi accesat de mai multe threaduri fara sa
apara probleme/anomalii.
Unele obiecte thread safe au accesul la resurse este limitat la un thread per moment, ceea
ce insemna ca threadurile trebuie sa le acceseze pe rand in serie, unu cate unu.
Alte obiecte thread safe sunt cele imutabile, deci threadurile pot doar sa citeasca informatia
fara sa o modifice. Folosind obiecte imutabile, 2 sau mai multe threaduri pot accesa
obiectul in acelasi timp fara a avea anomalii de citire sau scriere.
Collections-Exceptions-Working with files-Multithreading-Unit tests-VCS
Ce este un Deadlock?
Cand doua threaduri se asteapta unul pe
celalalt la nesfarsit atunci se considera ca avem
deadlock. Threadul 1 este oprit pana termina
Threadul 2, Threadul 2 este oprit pana termina
Threadul 1.
Exemplu: T1 apeleaza metoda syncronized1 |
T2 vrea sa apeleze si el syncronized1 | T2 a
apelat si el o metoda syncronized2 | T1 vrea sa
apeleze si el syncronized2
Collections-Exceptions-Working with files-Multithreading-Unit tests-VCS
Cum poate fi evitat un Deadlock?
Deadlocks pot fi evitate/rezolvate prin mai multe
moduri:
→ evitarea apelarii zonelor mutex (aka
locked/mutex) din doua threaduri diferite
→ evitarea lockurilor circulare; toate threadurile
trebuie sa acceseze zonele mutex, in aceeasi
ordine, deci sa obtina lock-urile in aceeasi
ordine
→ reducerea numarului de mutex-uri, prin
unirea lor
etc.
Collections-Exceptions-Working with files-Multithreading-Unit tests-VCS
Executors
ExecutorService este o interfata aparuta in Java 5 cu care poti executa taskuri asincron.
Folosind un ExecutorService poti crea si manageria un thread sau un pool de threaduri si ai
mai mult control asupra lor, in sensul ca stii cate sunt executate in acelasi timp sau la ce
interval de timp se vor executa.
Folosind ExecutorService este unicul mod prin care poti face un thread sa returneze ceva.
Folosesti obiecte care implementeaza Callable in loc de Runnable pentru a putea returna
rezultatul acelui thread intr-un obiect generic de tip Future. Future expune metode pentru a
monitoriza task-ul, poate verifica statusul si poate returna rezultatul.
Collections-Exceptions-Working with files-Multithreading-Unit tests-VCS
→ un ExecutorService cu un thread –
ExecutorService ex = Executors.newSingleThreadExecutor();
→ un ExecutorService cu un pool de threaduri cu numar fix de threaduri ce sunt executate simultan
ExecutorService ex = Executors.newFixedThreadPool(10);
→ un ExecutorService cu un pool de threaduri care pot fi executate periodic sau cu intarziere
ExecutorService ex = Executors.newScheduleThreadPool(10);
VCS
Collections-Exceptions-Working with files-Multithreading-Unit tests-VCS
Ce este Version Control?
Este un sistem care monitorizeaza schimbarile documentelor, programelor etc. De obicei
fiecare schimbare se numeste versiune. De fiecare data cand se face o schimbare
sistemele Version Control fac un “snapshot” al proiectului si il salveaza astfel incat daca
exista o problema sa putem reveni la versiunea anterioara.
Collections-Exceptions-Working with files-Multithreading-Unit tests-VCS
Motivele folosirii ar fi:
– posibilitatea de a reveni la o versiune anterioara;
– posibilitatea de a unifica codul mai multor dezvoltatori care lucreaza pe acelasi proiect;
– posibilitatea de a vedea ce, cand si cine a modificat proiectul;
– vei avea mereu un backup al proiectului pe serverul VCS
– vei avea acces remote la cod
Collections-Exceptions-Working with files-Multithreading-Unit tests-VCS
Exemple de VCS:
Git (distributed VC, dezvoltatorii au o copie locala a repository);
SVN (centralized VC, dezvoltatorii nu au o copie a repository locala, toti lucreaza direct pe repository central),
Mercurial (distributed VC, dezvoltatorii au o copie locala a repository),
CVS (centralized VC, dezvoltatorii nu au o copie a repository locala, toti lucreaza direct pe repository central).
Collections-Exceptions-Working with files-Multithreading-Unit tests-VCS
Git != GitHub
Git este o tehnologie de versionare, lansata de creatorul Linux, Linus Torvalds
GitHub este un provider (host) Git.
Exista si alte platforme care ofera servere Git, precum Bitbucket, Gitlab etc.
Companiile de obicei isi instaleaza apropriile servere de versionare, Git, SVN, private si nu
se bazeaza pe servere publice precum GitHub.
Invatam Git pentru a putea lucra cu toti providerii, precum GitHub, BitBucket, servere
private, etc.
Collections-Exceptions-Working with files-Multithreading-Unit tests-VCS
Ce este si cum se foloseste Git?
Este un sistem Version Control distribuit, adica fiecare dezvoltator
are pe sistemul sau o copie a repository-ului.
In Git, repository-urile sunt de doua tipuri, local (este un folder .git
in proiect si numai utilizatorul acelui sistem il poate utiliza) si central
(folderul .git este remote si este folosit de intreaga echipa).
Collections-Exceptions-Working with files-Multithreading-Unit tests-VCS
STARILE FISIERELOR
In Git fișierele pot fi în următoarele stadii:
– untracked (fișiere noi, care nu au fost niciodată commited in repository, nici macar staged)
– unmodified
– modified
– staged (a fost modificat și adăugat în lista de fișiere ce vor fi commited in repository)
(după commit fișierele trec în stare unmodified) (fișierele unmodified pot fi trecute și in
untracked) (doar fișierele staged for fi commited când aplicam comanda: git commit)
Putem vedea statusul fișierelor cu: git status
Pentru a trece fișierele untracked sau modified in stare staged folosim: git add -all
Comanda: git commit va commita doar fișierele staged
Collections-Exceptions-Working with files-Multithreading-Unit tests-VCS
Comenzi GIT (CMD LINE)
1.Pentru a initailiza un repository intr-un proiect local folosim: git init
2.Daca proiectul este deja remote intr-un server Git folosim pentru a-l downloada: git clone
<link>
3.Daca proiectul a fost initializat local (pasul1) pentru a-l lega de un repository nou existent
remote folosim:git add –all apoi git commit -m „first commit” apoi git remote add origin <link-
catre-repo> apoi git push -u origin master
4.Pentru a prelua apoi fiserele modificate remote folosesti: git pull sau git pull –rebase
5.Comanda git status pentru a vedea ce modificari au fost facute la repository local
6.Pentru a pune fisierele modificate in starea stage apoi in reporsitory local si apoi in cel
remote, folosesti git add . (pentru a adauga fisierele modificate in stage) apoi git commit –m
“mesaj” (pentru a adauga fisierele modificate in repo local) si apoi git push origin
branch_name_here (pentru a actualiza repository remote), numai dupa git push fisierele vor
ajunge in reporitory remote
7.Comanda git log, pentru a vedea history
8.Comanda git fetch va prelua history si noile branchuri de pe remote fara a downloada
continutul branch-urilor
9.Comanda git checkout branch_name, va schimba de pe un branch pe altul
Collections-Exceptions-Working with files-Multithreading-Unit tests-VCS
Learn more:
https://www.youtube.com/watch?v=8JJ101D3knE
Collections-Exceptions-Working with files-Multithreading-Unit tests-VCS
→ Interfetele pot avea metode default cu implementare si metode statice cu implementare;
→ Referinte la o metoda User::isRealUser;
→ Clasa Optional;
→ Interfete functionale,
→ Expresii lambda;
→ Stream-uri,
→ String.join() function
Lambda Expressions & Functional
Interfaces
Collections-Exceptions-Working with files-Multithreading-Unit tests-VCS
Expresiile lambda fac parte din programarea functionala si sunt
un fel de metode anonime, au parametrii si corp dar nu au nume.
Sunt implementari ale metodei abstracte unice declarate intr-o
interfata functionala. Inlocuiesc clasele anonime.
Collections-Exceptions-Working with files-Multithreading-Unit tests-VCS
O interfata functionala este o interfata adnotata optional cu
@FunctionalInterface ce are o singura metoda abstracta.
Adnotarea @FunctionalInterface ne asigura ca interfata nu are
decat o singura metoda abstracta.
Collections-Exceptions-Working with files-Multithreading-Unit tests-VCS
JDK 8+ vine in pachetul java.util.function cu multe interfete
functionale deja disponibile pentru noi sa le implementam
folosind expresii lambda.
@FunctionalInterface
public interface BiConsumer<T, U> {
void accept(T t, U u);
}
@FunctionalInterface
public interface Predicate<T> {
boolean test(T t);
}
@FunctionalInterface
public interface Function<T, R> {
R apply(T t);
}
Putem scrie si propriile interfete functionale.
Streams
Collections-Exceptions-Working with files-Multithreading-Unit tests-VCS
Colectiile sunt grupuri de obiecte tratate ca o entitate.
Streamurile sunt folosite pentru a procesa aceste colectii.
A nu se confunda cu Streamurile de citire si scriere.
Collections-Exceptions-Working with files-Multithreading-Unit tests-VCS
Un stream este secventa de obiecte de la o sursa care suporta operatii agregate
folosit pentru a transforma date. Este o structura abstracta, nu poate fi instantiata.
In Streams nu se modifica starea (state) la fiecare pas deci pot fi folosite cu
success in aplicatii multithread.
Pe streamurile generate putem aplica operatii n intermediare si doar o singura
operatie finala.
Collections-Exceptions-Working with files-Multithreading-Unit tests-VCS
Metode de generare a Streamurilor
.stream()
.parallelStream()
Exemplu:
List<Integer> list = Arrays.asList(1, 4, 6, 2, 7);
list.stream() //operatie de generare
.filter(i -> i > 3); // operatie intermediara , returneaza un stream modificat
.map(i -> i+3); //operatie intermediara, returneaza un stream modificat
.forEach(System.out::println); //operatie finala
Collections-Exceptions-Working with files-Multithreading-Unit tests-VCS
Metode intermediare
Operatiile intermediare primesc un stream si rezulta alt stream.
.map() – mapeaza o valoare in alta valoare
.flatmap()
.filter() – elimina elementele care nu trec conditia
.sorted() – sorteaza elementele din stream
.limit() – limiteaza nr de elemente din stream
.distinct() – elimina elementele duplicat din stream
.peek()
.skip()
Collections-Exceptions-Working with files-Multithreading-Unit tests-VCS
Metode terminale
Operatiile terminale consuma un stream si returneaza un rezultat
.reduce(inital_value, accumulator)
.collect();
.forEach(); – iterate each element
.forEachOrdered();
.toArray();
.min();
.max();
.count();
.anyMatch();
.allMatch();
.noneMatch();
.findFirst();
.findAny();
Subiecte de invatat pe viitor:
Spring
Design patterns
Principiile SOLID
Structuri de date
Algoritmi de sortare, cautare