This shows you the differences between two versions of the page.
poo-ca-cd:laboratoare:colectii [2021/12/01 13:38] florin.mihalache [Exerciţii] |
poo-ca-cd:laboratoare:colectii [2024/12/10 20:41] (current) alexandru.chirac [Interfaţa Set] |
||
---|---|---|---|
Line 1: | Line 1: | ||
- | ===== Laboratorul 8: Colecții ===== | + | ===== Laboratorul 9: Colecții ===== |
**Video introductiv:** [[https://youtu.be/NrcJpB_XLp0| link ]] | **Video introductiv:** [[https://youtu.be/NrcJpB_XLp0| link ]] | ||
Line 98: | Line 98: | ||
</code> | </code> | ||
- | Mai multe detalii despre acest subiect găsiți in laboratorul următor: [[:poo-ca-cd:laboratoare:genericitate|Genericitate]] | + | Mai multe detalii despre acest subiect găsiți in laboratorul de [[:poo-ca-cd:laboratoare:genericitate|Genericitate]] |
====Interfaţa List==== | ====Interfaţa List==== | ||
O listă este o colecţie care poate fi **ordonată**. Listele **pot** conţine elemente **duplicate**. Pe lângă operaţiile moştenite de la ''Collection'', interfaţa [[https://docs.oracle.com/javase/8/docs/api/java/util/List.html|List]] conţine operaţii bazate pe poziţie (index), de exemplu: //set//, //get//, //add// la un index, //remove// de la un index. | O listă este o colecţie care poate fi **ordonată**. Listele **pot** conţine elemente **duplicate**. Pe lângă operaţiile moştenite de la ''Collection'', interfaţa [[https://docs.oracle.com/javase/8/docs/api/java/util/List.html|List]] conţine operaţii bazate pe poziţie (index), de exemplu: //set//, //get//, //add// la un index, //remove// de la un index. | ||
Line 118: | Line 118: | ||
Printre algoritmii implementaţi se numără: | Printre algoritmii implementaţi se numără: | ||
* ''sort'' - realizează sortarea unei liste | * ''sort'' - realizează sortarea unei liste | ||
- | * ''binarySearch'' - realizeaază o căutare binară a unei valori într-o listă sortată | + | * ''binarySearch'' - realizează o căutare binară a unei valori într-o listă sortată |
În general, algoritmii pe colecţii sunt implementaţi ca metode statice în clasa [[http://docs.oracle.com/javase/7/docs/api/java/util/Collections.html|Collections]]. | În general, algoritmii pe colecţii sunt implementaţi ca metode statice în clasa [[http://docs.oracle.com/javase/7/docs/api/java/util/Collections.html|Collections]]. | ||
<note important> | <note important> | ||
Line 232: | Line 232: | ||
| | **HashSet** | **LinkedHashSet** | **TreeSet** | | | | **HashSet** | **LinkedHashSet** | **TreeSet** | | ||
| **Funcționarea internă** | Elementele se memorează într-o tabelă de dispersie | Elementele sunt păstrate cu ajutorul unei liste înlănțuite | Elementele se memorează într-un arbore de căutare | | | **Funcționarea internă** | Elementele se memorează într-o tabelă de dispersie | Elementele sunt păstrate cu ajutorul unei liste înlănțuite | Elementele se memorează într-un arbore de căutare | | ||
- | | **Utilizarea** | Se folosește când dorești să stochezi o listă de perechi cheie-valoare fără a fi interesat de ordinea acestei memorări | Se folosește atunci când se dorește conservarea ordinii de la inserare | Se folosește când se dorește păstrarea elementelor într-o ordine stabilită cu ajutorul unui Comparator | | + | | **Utilizarea** | Se folosește când dorești să stochezi o listă de elemente fără a fi interesat de ordinea acestei memorări | Se folosește atunci când se dorește conservarea ordinii de la inserare | Se folosește când se dorește păstrarea elementelor într-o ordine stabilită cu ajutorul unui Comparator | |
| **Ordinea** | Ordinea elementelor este total aleatoare | Se conservă ordinea în care au fost introduse elementele | Se folosește ordinea stabilită cu ajutorul unui Comparator. Daca acesta nu este menționat, implicit elementele vor fi sortate crescător | | | **Ordinea** | Ordinea elementelor este total aleatoare | Se conservă ordinea în care au fost introduse elementele | Se folosește ordinea stabilită cu ajutorul unui Comparator. Daca acesta nu este menționat, implicit elementele vor fi sortate crescător | | ||
| **Complexitatea operațiilor**| O(1) pentru toate operațiile de bază (inserare, ștergere, căutare) | O(1) pentru toate operațiile de bază (inserare, ștergere, căutare) | Deoarece este folosit un arbore în spate, operațiile se execută in O(log(N)) | | | **Complexitatea operațiilor**| O(1) pentru toate operațiile de bază (inserare, ștergere, căutare) | O(1) pentru toate operațiile de bază (inserare, ștergere, căutare) | Deoarece este folosit un arbore în spate, operațiile se execută in O(log(N)) | | ||
Line 329: | Line 329: | ||
* ''Stack'' - acesta reprezintă implementarea de operații specifice pentru stivă și extinde clasa ''Vector'', despre care am vorbit anterior. Colecția recomandată în locul acesteia este ''ArrayDeque''. | * ''Stack'' - acesta reprezintă implementarea de operații specifice pentru stivă și extinde clasa ''Vector'', despre care am vorbit anterior. Colecția recomandată în locul acesteia este ''ArrayDeque''. | ||
</note> | </note> | ||
- | |||
- | ====Funcții lambda==== | ||
- | În cadrul laboratorului de clase interne, am vorbit despre funcții anonime (funcții lambda) și despre cum le putem folosi în Java. | ||
- | |||
- | Putem folosi funcții anonime pentru a executa diverse operații pe liste (de exemplu ''removeIf'', care filtrează elementele unei colecții pe baza unui predicat, și ''replaceAll'', care aplică o operație pe toate elementele unei colecții). | ||
- | |||
- | Exemple: | ||
- | <code java> | ||
- | List<Integer> list = new ArrayList<>(Arrays.asList(1, 2, 3, 4, 5, 6, 7, 8, 9, 10)); | ||
- | |||
- | // incrementează toate numerele din colecție cu 1 | ||
- | list.replaceAll((x) -> x + 1); | ||
- | |||
- | // șterge din colecție numerele impare | ||
- | list.removeIf((x) -> x % 2 == 1); | ||
- | </code> | ||
- | |||
- | O altă utilitate a funcțiilor anonime reprezintă în implementarea comparatorilor folosiți la sortare sau la crearea de colecții sortate (TreeSet, TreeMap). | ||
- | |||
- | Exemple: | ||
- | <code java> | ||
- | // o variantă | ||
- | Collections.sort(list, (o1, o2) -> o2 - o1); | ||
- | |||
- | // alta variantă, prin care se folosim de metoda sort() din interfața List | ||
- | list.sort((o1, o2) -> o2 - o1); | ||
- | |||
- | // colecții sortate | ||
- | TreeSet<Integer> sortedSet = new TreeSet<>((o1, o2) -> o1 - o2); | ||
- | TreeMap<Integer, Integer> sortedMap = new TreeMap<>((o1, o2) -> o1 - o2); | ||
- | </code> | ||
- | |||
- | ====Unit Testing==== | ||
- | |||
- | În procesul de dezvoltare software, o parte foarte importantă a acestuia este și verificarea dacă codul scris se comportă în modul așteptat sau nu. Tot ce presupune verificarea funcționalității codului se poate încadra sub umbrela termenului de “Testing”, dintre care există mai multe tipuri (unit testing, functional testing, integration testing, printre altele). | ||
- | |||
- | Elementul de bază în testare îl constituie “unit testing-ul”. Acesta presupune scrierea de teste care verifică funcționalitatea unei singure componente: o clasă cu anumite metode, o structură de date, etc. | ||
- | |||
- | Framework-ul de testare despre care vom vorbi este JUnit5. Pentru o analiză mai amânunțită a acestuia, consultați următoarea pagină: [[poo-ca-cd:alte-resurse:junit-java|JUnit5 Basics]]. Scopul prezentării în acest laborator este de a vă prezenta un punct de start în învățarea acestui framework. | ||
- | |||
- | ===Instalare JUnit5=== | ||
- | Pentru a folosi biblioteca JUnit într-un anumit proiect, urmează următorii pași: | ||
- | - într-un proiect, intrați pe File -> Project Structure -> Libraries | ||
- | - din meniul de Libraries, apăsați pe "+", după care pe "From Maven" | ||
- | - se va deschide un pop-up, în care va trebui să scrieți în fereastra de căutare "org.junit.jupiter:junit-jupiter:5.7.0", după care apăsați "Ok" | ||
- | - IntelliJ vă va întreba dacă vreți să adăugați biblioteca la proiectul curent, apăsați "Ok" | ||
- | - la final, în fereastra inițială apăsați "Apply" -> "Ok" | ||
- | |||
- | {{:poo-ca-cd:laboratoare:tutorial_junit.png?400|}} | ||
- | |||
- | Pentru a putea testa funcționalitatea bibliotecii “JUnit” puteți folosi codul exemplu de aici | ||
- | (https://ocw.cs.pub.ro/courses/poo-ca-cd/alte-resurse/junit-java). În cazul în care aveți | ||
- | erori, puteți să încercați să reactualizati cache-ul aplicației (File -> Invalidate Caches), | ||
- | timp în care JAR-urile și SDK-ul Java vi se vor reindexa (progresul operației se poate | ||
- | observa în colțul din dreapta jos sub formă de “loading bar”). | ||
- | |||
- | ===Utilizarea framework-ului=== | ||
- | Pentru a folosi JUnit5, este important de învățat două concepte: cel de adnotări și cel de assert-uri. | ||
- | Cel mai mare avantaj al JUnit este viteza rapidă de scriere a testelor, iar lucrul acesta este posibil datorită adnotărilor. Adnotările sunt termeni standardizați, prefațați de semnul “@”, plasați fix înaintea semnăturii unei funcții. Scopul acestora este că, în momentul compilării, compilatorul să știe să adauge funcționalitate în plus metodei căreia a fost adăugat. | ||
- | Printre adnotările de bază din JUnit5 se numără: | ||
- | * **@Test** - metoda va funcționa ca test, aceasta va trebui să întoarcă o valoare de True dacă funcționalitatea testată funcționează în modul dorit, False în mod contrar (lucru posibil prin assert-uri, despre care vom vorbi mai jos) | ||
- | * **@BeforeEach** - metoda va fi executată înaintea fiecărui test | ||
- | * **@AfterEach** - metoda va fi executată după fiecare test | ||
- | * **@DisplayName(“Some_String”)** - se folosește împreună cu @Test; când testul se rulează, la consolă va apărea la output cu numele “Some_String” | ||
- | Pentru a vedea toate adnotările disponibile în JUnit5, consultați următoarea pagină de documentație https://www.swtestacademy.com/junit-5-annotations/. | ||
- | |||
- | Așa cum am menționat mai sus, cel de-al doilea concept necesar scrierii testelor este cel de assert-uri. Acestea metode statice, care sunt găsite în clasa org.junit.jupiter.api.Assertions , afirmă valoarea de adevăr a diferite expresii. În continuare, vă vom prezenta câteva exemple de assert-uri des folosite: | ||
- | * **assertEquals(value_1, value_2)** - verifică dacă cele două valori sunt egale | ||
- | * **assertTrue(boolean value)**, respectiv **assertFalse(boolean value)** - verifică dacă value este True, respectiv False | ||
- | * **assertNull(obj)**, respectiv **assertNotNull(obj)** - verifică dacă obj este Null, respectiv dacă nu este | ||
- | Pentru mai multe detalii despre toate funcțiile de assert existente, consultați următoarea pagină de documentație: http://junit.sourceforge.net/javadoc/org/junit/Assert.html | ||
- | |||
- | Pentru a scrie teste corect și cu bună vizibilitate, aveți în minte următoarele lucruri: | ||
- | * puneți nume sugestive pentru fiecare metodă de test pe care o implementați | ||
- | * scrieți metode de test care să testeze doar o anumită funcționalitate, nu mai multe deodată | ||
- | * țineți minte că testele sunt făcute să verifice că implementările făcute de voi funcționează în modul dorit de voi | ||
- | |||
- | ===Exemplu de folosire JUnit5=== | ||
- | |||
- | **FloatCalculator class** | ||
- | <code java> | ||
- | package main; | ||
- | |||
- | public class FloatCalculator { | ||
- | |||
- | public float add(float first, float second) { | ||
- | return first + second; | ||
- | } | ||
- | |||
- | public float multiply(float first, float second) { | ||
- | return first * second; | ||
- | } | ||
- | |||
- | public float divide(float first, float second) { | ||
- | return first / second; | ||
- | } | ||
- | |||
- | public boolean isNegative(float num) { | ||
- | return num < 0; | ||
- | } | ||
- | } | ||
- | </code> | ||
- | |||
- | **FloatCalculatorTest class** | ||
- | <code java> | ||
- | package main; | ||
- | |||
- | import org.junit.jupiter.api.*; | ||
- | |||
- | public class FloatCalculatorTest { | ||
- | private FloatCalculator calculator; | ||
- | |||
- | @BeforeEach | ||
- | public void setUp() { | ||
- | this.calculator = new FloatCalculator(); | ||
- | } | ||
- | |||
- | @AfterEach | ||
- | public void clean() { | ||
- | this.calculator = null; | ||
- | } | ||
- | |||
- | @Test | ||
- | @DisplayName("Add test") | ||
- | public void testAdd() { | ||
- | Assertions.assertEquals(5, calculator.add(2, 3)); | ||
- | Assertions.assertNotEquals(5, calculator.add(2, 2)); | ||
- | } | ||
- | |||
- | @Test | ||
- | @DisplayName("Multiply test") | ||
- | public void testMultiply() { | ||
- | Assertions.assertEquals(6, calculator.multiply(2, 3)); | ||
- | Assertions.assertNotEquals(7.5f, calculator.multiply(2.5f, 4)); | ||
- | } | ||
- | |||
- | @Test | ||
- | @DisplayName("Divide test") | ||
- | public void testDivide() { | ||
- | Assertions.assertEquals(10, calculator.divide(100, 10)); | ||
- | Assertions.assertNotEquals(5.5f, calculator.divide(55, 12)); | ||
- | } | ||
- | |||
- | @Test | ||
- | @DisplayName("IsNegative test") | ||
- | public void testIsNegative() { | ||
- | Assertions.assertTrue(calculator.isNegative(-5)); | ||
- | Assertions.assertFalse(calculator.isNegative(10)); | ||
- | } | ||
- | } | ||
- | |||
- | </code> | ||
====TL;DR==== | ====TL;DR==== | ||
Line 493: | Line 341: | ||
====Exerciţii==== | ====Exerciţii==== | ||
- | - (**2p**) În cadrul acestui exercițiu, veți implementa o clasă numită Student, care are patru membri: | + | 1. În cadrul acestui exercițiu, veți implementa o clasă numită Student, care are patru membri: |
- name (String) | - name (String) | ||
- surname (String) | - surname (String) | ||
- id (long) | - id (long) | ||
- | - averageGrade (double) - media unui student. | + | - averageGrade (double) - media unui student. |
- | * Clasa Student va implementa interfața [[https://docs.oracle.com/en/java/javase/12/docs/api/java.base/java/lang/Comparable.html|Comparable]]<Student>, folosită la sortări, implementând metoda [[https://docs.oracle.com/en/java/javase/12/docs/api/java.base/java/lang/Comparable.html#compareTo(T)|compareTo]]. În metoda compareTo, studenții vor fi comparați mai întâi după medie, apoi după numele de familie, apoi dupa prenume (adică dacă doi studenți au aceeași medie, ei vor fi comparați după numele de familie și dacă au același nume de familie, atunci vor fi comparați după prenume). Recomandăm să suprascrieți metoda //toString//, pentru a putea afișa datele despre un student. | + | Clasa Student va implementa interfața Comparable<Student>, folosită la sortări, prin implementarea metodei compareTo. În metoda compareTo, studenții vor fi comparați mai întâi după medie, apoi după numele de familie, apoi după prenume. |
- | - (**1p**) Creați 5 obiecte de tip Student și adăugați-le într-un ArrayList, pe care să îl sortați (hint: [[https://docs.oracle.com/en/java/javase/12/docs/api/java.base/java/util/Collections.html#sort(java.util.List)|Collections.sort]]), apoi afisați conținutul din ArrayList. | + | După implementarea clasei, sortați elementele listei "students" din metoda main folosind metoda Collections.sort(). |
- | - (**1p**) Sortați ArrayList-ul de la punctul anterior cu metoda sort() din interfața List sau cu Collections.sort(), în care să folosiți o funcție lambda, în care se compară descrescător după medie. | + | |
- | - (**2p**) Adăugați ArrayList-ul definit la subpunctul anterior într-un PriorityQueue (hint: [[https://docs.oracle.com/en/java/javase/12/docs/api/java.base/java/util/Collection.html#addAll(java.util.Collection)|Collection.addAll]]), care folosește un [[https://docs.oracle.com/en/java/javase/14/docs/api/java.base/java/util/Comparator.html|Comparator]] (hint: [[https://docs.oracle.com/en/java/javase/14/docs/api/java.base/java/util/PriorityQueue.html#%3Cinit%3E(java.util.Comparator)|constructor PriorityQueue)]] sau o funcție anonimă, unde elementele sunt sortate crescător după id (aici puteti folosi Long.compare ca să comparați două numere de tip long). | + | 2. Adăugați lista "copyStudents" într-un PriorityQueue (cu ajutorul metodei Collection.addAll), care folosește un Comparator (utilizați constructorul PriorityQueue) sau o funcție anonimă. Elementele vor fi sortate crescător după id. |
- | - (**1p**) Suprascrieți metodele //equals// și //hashCode// în clasa Student (hint: puteți folosi generatorul de cod din IntelliJ). | + | |
- | - (**1p**) Folosiți un //[[https://docs.oracle.com/en/java/javase/14/docs/api/java.base/java/util/HashMap.html|HashMap]]<Student, LinkedList<String>>//, în care se vor adăuga perechi de tipul (Student, lista de materii pe care le are studentul respectiv), iar apoi afisați conținutul colecției (hint: Map.Entry și entrySet()). | + | 3. Suprascrieți metodele equals și hashCode în clasa Student (puteți folosi generatorul de cod din IntelliJ). După aceasta, adăugați în lista asociată studentilor din "studentMap" patru materii aleatorii. Pentru a obține materiile aleatorii, urmăriți indicațiile din codul din funcția main. |
- | - (**2p**) Extindeți clasa //LinkedHashSet<Integer>//, cu o clasă în care se vor putea adăuga doar numere pare. Va fi suprascrisă metoda //add//, în așa fel încât să nu fie permise adăugarea de numere impare în colecție. Pentru testare, adăugați numere pare și impare, iar după aceea iterați prin colecție, folosind [[https://docs.oracle.com/en/java/javase/12/docs/api/java.base/java/util/Iterator.html|Iterator]] (tipizat cu Integer) sau folosind forEach, afișând elementele din colecție. Înlocuiți LinkedHashSet cu HashSet - ce observați cu privire la ordinea de inserare a elementelor? Dar dacă ați înlocui cu TreeSet? | + | |
- | - (**1p**) Rezolvați [[https://lambdachecker.io/problem/80 | această problemă de pe LambdaChecker]], care conține teste. | + | 4. Extindeți clasa LinkedHashSet<Integer> cu o clasă în care se vor putea adăuga doar numere pare. Metoda add va fi suprascrisă astfel încât să nu permită adăugarea de numere impare în colecție. Efectuați aceeași operațiune și pentru clasele TreeSet și HashSet. Observați diferențele privind ordinea de inserare a elementelor între cele trei clase menționate. |
- | - (**1p**) Pe baza exemplelor din laborator, implementați o clasă numită StudentTest în care să adăugați metodele aferente realizării unor UnitTeste (folosind JUnit), pentru testarea a cel puțin una dintre urmatoarele metodele din clasa Student: | + | |
- | - Equals | + | Scheletul il puteți gasi pe [[https://github.com/oop-pub/oop-labs/blob/master/src/lab8/Main.java|github]]. Soluția trebuie încărcată pe [[https://code.devmind.ro|devmind]]. |
- | - CompareTo | + | |
- | - toString | + | |
==== Resurse ==== | ==== Resurse ==== | ||
* [[:poo-ca-cd:laboratoare:old-exercises#colectii|Exerciții din alți ani]] | * [[:poo-ca-cd:laboratoare:old-exercises#colectii|Exerciții din alți ani]] |