This shows you the differences between two versions of the page.
|
poo-ca-cd:laboratoare:programare-functionala-lambda-si-streamuri [2025/12/08 09:49] florian_luis.micu created |
poo-ca-cd:laboratoare:programare-functionala-lambda-si-streamuri [2025/12/10 01:04] (current) florian_luis.micu [Obiective] |
||
|---|---|---|---|
| Line 3: | Line 3: | ||
| * Autori: [[miculuis1@gmail.com | Florian-Luis Micu ]], [[sorinabuf@gmail.com | Sorina-Anamaria Buf ]], [[stefancocioran@gmail.com | Ștefan Cocioran ]] | * Autori: [[miculuis1@gmail.com | Florian-Luis Micu ]], [[sorinabuf@gmail.com | Sorina-Anamaria Buf ]], [[stefancocioran@gmail.com | Ștefan Cocioran ]] | ||
| * Data publicării: 08.12.2025 | * Data publicării: 08.12.2025 | ||
| - | * Data ultimei modificări: 08.12.2025 | + | * Data ultimei modificări: 10.12.2025 |
| + | * reordonare secțiuni. | ||
| + | * introducerea Generic Singleton Factory ca materie [Optional]. | ||
| + | * introducerea CRTP ca materie [Optional]. | ||
| ======Obiective====== | ======Obiective====== | ||
| Line 17: | Line 20: | ||
| * compilarea cu warning-uri pentru raw types și dangerous casts | * compilarea cu warning-uri pentru raw types și dangerous casts | ||
| * glosar pentru denumirea tipurilor generice. | * glosar pentru denumirea tipurilor generice. | ||
| + | * prezentarea pattern-ului avansat Generic Singleton Factory. | ||
| + | * prezentarea pattern-ului CRTP. | ||
| <note warning> | <note warning> | ||
| Line 23: | Line 28: | ||
| </note> | </note> | ||
| - | ======🏷️ Genericics====== | + | ======🏷️ Generics====== |
| Genericitatea este unul dintre cele mai elegante mecanisme introduse în Java pentru a ajuta la scrierea unui cod **general**, **sigur** și **reutilizabil**. | Genericitatea este unul dintre cele mai elegante mecanisme introduse în Java pentru a ajuta la scrierea unui cod **general**, **sigur** și **reutilizabil**. | ||
| Line 313: | Line 318: | ||
| Vom vedea mai jos ce face exact ''extends'' în cadrul generics. | Vom vedea mai jos ce face exact ''extends'' în cadrul generics. | ||
| </note> | </note> | ||
| - | =====Tipuri generice cu limitări===== | ||
| - | |||
| - | Există situații în care dorim ca un parametru generic să fie **restricționat** la un anumit tip (sau **subclase** ale acestuia). | ||
| - | |||
| - | <code java> | ||
| - | public class NumberBox<T extends Number> { | ||
| - | private T value; | ||
| - | } | ||
| - | </code> | ||
| - | |||
| - | Această constrângere oferă două avantaje: | ||
| - | * garantează că putem apela metodele definite în ''Number'', | ||
| - | * previne utilizarea unor tipuri incompatibile (ex. ''String''). | ||
| - | |||
| - | <note tip> | ||
| - | Vom vedea mai jos ce presupune exact construcția ''extends'' în cadrul generics. | ||
| - | </note> | ||
| - | |||
| - | De asemenea, Java permite **bounded type parameters multiple**: | ||
| - | |||
| - | <code java> | ||
| - | public <T extends Number & Comparable<T>> void process(T value) { ... } | ||
| - | </code> | ||
| - | |||
| - | Această combinație este utilă în **algoritmi de sortare** sau **agregare numerică**. | ||
| - | |||
| - | Un alt exemplu destul de des folosit cu limitări în tipuri generice este acesta: | ||
| - | |||
| - | <code java> | ||
| - | public static <T extends Comparable<T>> T max(T a, T b) { | ||
| - | return a.compareTo(b) > 0 ? a : b; | ||
| - | } | ||
| - | </code> | ||
| - | |||
| - | Practic, am făcut o metodă care întoarce maximul dintre două obiecte, doar dacă acel obiect **implementează interfața Comparable** pentru a putea folosi metoda ''compareTo''. | ||
| - | |||
| - | |||
| =====Wildcards – flexibilitate în genericitate===== | =====Wildcards – flexibilitate în genericitate===== | ||
| Line 357: | Line 325: | ||
| ====Wildcard neîngrădit (?)==== | ====Wildcard neîngrădit (?)==== | ||
| - | Folosim ? când tipul nu este relevant, ci doar existența lui: | + | Folosim ''?'' când tipul nu este relevant, ci doar existența lui: |
| <code java> | <code java> | ||
| Line 466: | Line 434: | ||
| - Metoda publică primește orice listă (''List<?>''). | - Metoda publică primește orice listă (''List<?>''). | ||
| - Metoda privată capturează wildcard-ul ca T și permite operații sigure. | - Metoda privată capturează wildcard-ul ca T și permite operații sigure. | ||
| + | |||
| + | =====Tipuri generice cu limitări===== | ||
| + | |||
| + | Există situații în care dorim ca un parametru generic să fie **restricționat** la un anumit tip (sau **subclase** ale acestuia). | ||
| + | |||
| + | Pentru a limita un tip putem folosi keyword-ul ''extends'', astfel doar o clasă moștenită de clasa extinsă poate fi folosită. În acest caz, această noțiune se cheamă **bounded generics**. | ||
| + | |||
| + | <code java> | ||
| + | public class NumberBox<T extends Number> { | ||
| + | private T value; | ||
| + | } | ||
| + | </code> | ||
| + | |||
| + | Această constrângere oferă două avantaje: | ||
| + | * garantează că putem apela metodele definite în ''Number'', | ||
| + | * previne utilizarea unor tipuri incompatibile: | ||
| + | * ''NumberBox<Integer>'' - valid | ||
| + | * ''NumberBox<Double>'' - valid | ||
| + | * ''NumberBox<String>'' - invalid | ||
| + | |||
| + | ====Limitări multiple==== | ||
| + | |||
| + | De asemenea, Java permite **multiple bounded type parameters**: | ||
| + | |||
| + | <code java> | ||
| + | public <T extends Number & Comparable<T>> void process(T value) { ... } | ||
| + | </code> | ||
| + | |||
| + | Ordinea este importantă: | ||
| + | - prima limitare trebuie să fie o clasă | ||
| + | - restul pot fi interfețe | ||
| + | |||
| + | Combinația de mai sus este utilă în **algoritmi de sortare** sau **agregare numerică**. | ||
| + | |||
| + | Un alt exemplu destul de des folosit cu limitări în tipuri generice este acesta: | ||
| + | |||
| + | <code java> | ||
| + | public static <T extends Comparable<T>> T max(T a, T b) { | ||
| + | return a.compareTo(b) > 0 ? a : b; | ||
| + | } | ||
| + | </code> | ||
| + | |||
| + | Practic, am făcut o metodă care întoarce maximul dintre două obiecte, doar dacă acel obiect **implementează interfața Comparable** pentru a putea folosi metoda ''compareTo''. | ||
| + | |||
| + | |||
| + | |||
| =====Type erasure – cum funcționează generics sub capotă===== | =====Type erasure – cum funcționează generics sub capotă===== | ||
| Line 552: | Line 566: | ||
| =====Invarianță, Covarianță și Contravarianță===== | =====Invarianță, Covarianță și Contravarianță===== | ||
| - | Java are trei moduri principale de a trata relațiile dintre tipurile generice. | + | Java are **trei moduri principale** de a trata relațiile dintre tipurile generice. |
| ====Invarianță (comportamentul implicit)==== | ====Invarianță (comportamentul implicit)==== | ||
| Line 582: | Line 596: | ||
| ====Contravarianță (? super T)==== | ====Contravarianță (? super T)==== | ||
| - | Pentru a defini un scenariu de moștenire ca în exemplul despre invarianță, putem folosi bounded wildcards, astfel listelor li se poate permite să accepte **tipuri părinte**. | + | Pentru a defini un scenariu de moștenire ca în exemplul despre invarianță, putem folosi **bounded wildcards**, astfel listelor li se poate permite să accepte **tipuri părinte**. |
| <code java> | <code java> | ||
| Line 590: | Line 604: | ||
| Aceasta permite scrierea în colecție (''add(Integer)''), dar **nu permite** citirea unui tip specific. | Aceasta permite scrierea în colecție (''add(Integer)''), dar **nu permite** citirea unui tip specific. | ||
| - | ====De ce List<String> nu este List<Object>==== | + | ====De ce List<String> nu este List<Object>?==== |
| În mod natural, ai putea crede că dacă ''String'' este un subtip al lui ''Object'', atunci și ''List<String>'' ar trebui să fie un subtip al lui ''List<Object>''. Dar nu este așa. | În mod natural, ai putea crede că dacă ''String'' este un subtip al lui ''Object'', atunci și ''List<String>'' ar trebui să fie un subtip al lui ''List<Object>''. Dar nu este așa. | ||
| Line 642: | Line 656: | ||
| <note tip> | <note tip> | ||
| - | Arrays verifică tipurile la runtime, în schimb generics nu o fac. | + | * **Reified** înseamnă că informația despre **tip** există și este păstrată la **runtime**. |
| + | * Arrays verifică tipurile la **runtime**, în schimb generics nu o fac. | ||
| </note> | </note> | ||
| + | |||
| + | =====[Nice to know] Glosar – Litere folosite în Generics===== | ||
| + | |||
| + | ^Literă ^ Semnificație^ | ||
| + | |T | Type| | ||
| + | |E | Element (în special în colecții)| | ||
| + | |K | Key| | ||
| + | |V | Value| | ||
| + | |R | Result| | ||
| + | |? | wildcard, tip necunoscut| | ||
| + | |||
| =====[Optional] Warning-uri de compilare===== | =====[Optional] Warning-uri de compilare===== | ||
| Line 658: | Line 684: | ||
| IntelliJ va rula automat această comandă pentru voi. | IntelliJ va rula automat această comandă pentru voi. | ||
| </note> | </note> | ||
| - | =====[Nice to know] Glosar – Litere folosite în Generics===== | ||
| - | ^Literă ^ Semnificație^ | + | =====[Optional] Generic Singleton Factory===== |
| - | |T | Type| | + | |
| - | |E | Element (în special în colecții)| | + | Acesta este un pattern foarte elegant, folosit intern în **JDK**, mai ales în ''Collections''. |
| - | |K | Key| | + | |
| - | |V | Value| | + | O singură instanță poate fi folosită pentru **toate tipurile**, iar generics asigură siguranța. |
| - | |R | Result| | + | |
| - | |? | wildcard, tip necunoscut| | + | <code java> |
| + | public class SingletonFactory { | ||
| + | private static final Box<Object> INSTANCE = new Box<>(); | ||
| + | |||
| + | @SuppressWarnings("unchecked") | ||
| + | public static <T> Box<T> getInstance() { | ||
| + | return (Box<T>) INSTANCE; | ||
| + | } | ||
| + | } | ||
| + | </code> | ||
| + | |||
| + | Utilizare: | ||
| + | |||
| + | <code java> | ||
| + | Box<String> a = SingletonFactory.getInstance(); | ||
| + | Box<Integer> b = SingletonFactory.getInstance(); | ||
| + | </code> | ||
| + | |||
| + | |||
| + | Observație: | ||
| + | * Instanța din spate e aceeași (''Box<Object>''). | ||
| + | * Dar fiecare apelant primește o versiune tipizată în siguranță. | ||
| + | |||
| + | <note important> | ||
| + | De ce funcționează codul de mai sus? | ||
| + | - instanța este imutabilă sau fără stare | ||
| + | - cast-ul este sigur | ||
| + | - comportamentul este identic pentru orice tip | ||
| + | </note> | ||
| + | |||
| + | <note tip> | ||
| + | Acest pattern apare în: | ||
| + | * ''Collections.emptyList()'' | ||
| + | * ''Collections.emptyMap()'' | ||
| + | * ''Optional.empty()'' | ||
| + | * ''Stream.empty()'' | ||
| + | </note> | ||
| + | |||
| + | =====[Optional] Self-bounded Generics (Curiously Recurring Template Pattern — CRTP)===== | ||
| + | |||
| + | Este un pattern avansat unde un **tip generic** se referă la el **însuși**. | ||
| + | |||
| + | <code java> | ||
| + | class ComparableSelf<T extends ComparableSelf<T>> { } | ||
| + | </code> | ||
| + | |||
| + | Scopul acestui pattern este de a asigura că **subclasele** folosesc un **tip compatibil cu ele însele**. | ||
| + | |||
| + | De exemplu: | ||
| + | <code java> | ||
| + | class Person extends ComparableSelf<Person> { } | ||
| + | </code> | ||
| + | |||
| + | Beneficiul major este că putem scrie algoritmi care impun **tipuri consistente**. | ||
| + | |||
| + | Exemplu tipic: | ||
| + | <code java> | ||
| + | interface SelfComparable<T extends SelfComparable<T>> { | ||
| + | int compareTo(T other); | ||
| + | } | ||
| + | </code> | ||
| + | |||
| + | Implementare corectă: | ||
| + | <code java> | ||
| + | class Car implements SelfComparable<Car> { | ||
| + | public int compareTo(Car other) { ... } | ||
| + | } | ||
| + | </code> | ||
| + | |||
| + | Implementare incorectă (interzisă de self-bounding): | ||
| + | <code java> | ||
| + | class Car implements SelfComparable<Object> { ... } | ||
| + | </code> | ||
| + | |||
| + | Self-bounded generics **împiedică** astfel de erori de design. | ||
| + | |||
| ======Exerciții====== | ======Exerciții====== | ||