Differences

This shows you the differences between two versions of the page.

Link to this comparison view

poo-ca-cd:laboratoare:programare-functionala-lambda-si-streamuri [2025/12/15 03:07]
florian_luis.micu [Interfețe funcționale și Lambdas]
poo-ca-cd:laboratoare:programare-functionala-lambda-si-streamuri [2025/12/15 11:44] (current)
florian_luis.micu [Obiective]
Line 4: Line 4:
   * Data publicării:​ 15.12.2025   * Data publicării:​ 15.12.2025
   * Data ultimei modificări:​ 15.12.2025   * Data ultimei modificări:​ 15.12.2025
 +    * adăugare secțiune despre operații short-circuit.
 +    * adăugare secțiune [Nice to know] despre Optional.
 +    * adăugare secțiune despre primitive streams.
 +    * menționarea boolean chaining când folosim interfețe funcționale de tip Predicate.
  
 ======Obiective====== ======Obiective======
Line 16: Line 20:
   * diferențe dintre stilul imperativ și stilul funcțional de programare.   * diferențe dintre stilul imperativ și stilul funcțional de programare.
   * identificarea avantajelor,​ limitărilor și capcanelor ale abordării funcționale în Java.   * identificarea avantajelor,​ limitărilor și capcanelor ale abordării funcționale în Java.
 +
 +Aspectele **bonus** urmărite sunt:
 +  * definirea și folosirea Optional în programarea în stil funcțional.
 +  * paralelizarea codului folosind parallel streams.
  
 <note warning> <note warning>
Line 22: Line 30:
 </​note>​ </​note>​
  
-======🏷️ Programare ​funcțională======+======🔧 Programarea ​funcțională======
  
 +Există mai multe **paradigme de programare**,​ fiecare definind un mod diferit de a structura și exprima logica unui program. Cele mai importante sunt **programarea imperativă**,​ care descrie execuția pas cu pas, **programarea orientată pe obiecte**, care modelează aplicația prin obiecte ce combină date și comportament,​ și **programarea funcțională**,​ care pune accent pe transformări de date, funcții pure și evitarea stării mutabile.
 +
 +Majoritatea limbajelor moderne sunt **multi-paradigmă**. Java, de exemplu, combină stilul imperativ și orientat pe obiecte cu elemente de programare funcțională (lambda expressions,​ Stream API), permițând alegerea paradigmei potrivite în funcție de problemă.
 +
 +<note tip>
 +Există mai multe tipuri de paradigme de programare:
 +  * programare imperativă (ex. C, Fortran)
 +  * programare orientată pe obiecte (ex. Java, C#, C++, Python)
 +  * programare funcțională (ex. Haskell, Lisp)
 +  * programare declarativă (ex. SQL, HTML)
 +  * programare logică (ex. Prolog)
 +  * programare bazată pe evenimente (ex. JavaScript)
 +</​note>​
 =====De ce am programa funcțional în Java?===== =====De ce am programa funcțional în Java?=====
  
Line 101: Line 122:
 </​note>​ </​note>​
  
-======λ Interfețe funcționale și Lambdas======+======📜 Interfețe funcționale și Lambdas======
  
 =====Interfețe funcționale – fundamentul lambda-urilor===== =====Interfețe funcționale – fundamentul lambda-urilor=====
Line 271: Line 292:
 ==Cum rezolvă interfețe funcționale și expresiile lambda limitările Java== ==Cum rezolvă interfețe funcționale și expresiile lambda limitările Java==
  
-Expresiile lambda funcționează doar cu interfețe funcționale pentru că compilatorul știe ce metodă implementează,​ deoarece există doar o metodă de definit.+Expresiile lambda funcționează doar cu interfețe funcționale pentru că compilatorul știe **ce metodă implementează**, deoarece există doar o metodă de definit
 + 
 +Interfața funcțională este un **contract**,​ iar lambda-ul este **implementarea** acestui contract.
  
 Deci când scriem: Deci când scriem:
Line 339: Line 362:
 isEven.test(10);​ // true isEven.test(10);​ // true
 </​code>​ </​code>​
 +
 +<note tip>
 +Predicate este util și pentru înlănțuirea condițiilor boolean prin folosirea metodelor ''​and(...)'',​ ''​or(...)'',​ ''​negate(...)''​.
 +<code java>
 +Predicate<​Integer>​ isPositive = x -> x > 0;
 +Predicate<​Integer>​ isEven = x -> x % 2 == 0;
 +
 +Predicate<​Integer>​ positiveAndEven =
 +    isPositive.and(isEven);​
 +
 +System.out.println(positiveAndEven.test(4)); ​ // true
 +System.out.println(positiveAndEven.test(3)); ​ // false
 +System.out.println(positiveAndEven.test(-2));​ // false
 +</​code>​
 +</​note>​
  
 ===Function<​T,​ R> – transformări=== ===Function<​T,​ R> – transformări===
Line 969: Line 1007:
  
 </​spoiler>​ </​spoiler>​
 +
 +====Operații short-circuit====
 +
 +Unele operații pot **opri execuția** înainte de final.
 +
 +Exemple:
 +  * ''​anyMatch''​ - Verifică dacă există cel puțin un element în stream care respectă o condiție (se oprește la prima potrivire).
 +  * ''​findFirst''​ - Returnează primul element din stream, respectând ordinea (rezultat: ''​Optional<​T>''​)
 +  * ''​findAny''​ – Returnează orice element din stream (fără garanție de ordine, optim pentru parallel streams).
 +  * ''​limit''​ – Restrânge stream-ul la primele N elemente, oprind procesarea după atingerea limitei.
 +
 +Exemplu:
 +<code java>
 +boolean hasEven =
 +    numbers.stream()
 +           ​.peek(x -> System.out.println(x))
 +           ​.anyMatch(x -> x % 2 == 0);
 +</​code>​
 +
 +În exemplul de mai sus, stream-ul printează elementele și se oprește **la primul element par**.
  
 =====Legătura dintre Stream API și Interfețele Funcționale===== =====Legătura dintre Stream API și Interfețele Funcționale=====
Line 1039: Line 1097:
 Fiecare element trece **complet** prin pipeline înainte de următorul. Fiecare element trece **complet** prin pipeline înainte de următorul.
 </​note>​ </​note>​
 +
 +=====Primitive Streams=====
 +
 +Stream-urile generice (''​Stream<​Integer>''​) folosesc:
 +  * boxing
 +  * unboxing
 +
 +Asta înseamnă că lucrul cu ele este **mai lent** și consumă mai multă memorie.
 +
 +Exemplu folosire boxing:
 +<code java>
 +int sum =
 +    numbers.stream()
 +           ​.map(x -> x)
 +           ​.reduce(0,​ Integer::​sum);​
 +</​code>​
 +
 +Exemplu folosire primitive streams:
 +<code java>
 +int sum =
 +    numbers.stream()
 +           ​.mapToInt(x -> x)
 +           ​.sum();​
 +</​code>​
 +
 +====Tipuri de Primitive Streams====
 +
 +^ Tip    ^ Clasă ​       ^
 +| int    | IntStream ​   |
 +| long   | LongStream ​  |
 +| double | DoubleStream |
 +
 +====Metode utile====
 +
 +^ Metodă ​         ^ Ce face                                       ^ Tip returnat ​    ^ Observații importante ​                      ^
 +| ''​mapToInt(...)''​ | Transformă un ''​Stream<​T>''​ într-un ''​IntStream''​ | ''​IntStream'' ​     | Evită autoboxing (''​Integer''​ → ''​int''​) ​       |
 +| ''​sum()'' ​        | Calculează suma elementelor din ''​IntStream'' ​  | ''​int'' ​           | Returnează ''​0''​ dacă stream-ul e gol         |
 +| ''​average()'' ​    | Calculează media aritmetică a elementelor ​    | ''​OptionalDouble''​ | Folosește ''​Optional''​ pentru a evita ''​0/​NaN''​ |
 +| ''​min()'' ​        | Găsește valoarea minimă din stream ​           | ''​OptionalInt'' ​   | Stream-ul poate fi gol                      |
 +| ''​max()'' ​        | Găsește valoarea maximă din stream ​           | ''​OptionalInt'' ​   | Stream-ul poate fi gol                      |
 +
 +
 +<note tip>
 +Pentru calcule numerice, este mai bine să **folosiți primitive streams**.
 +</​note>​
 +
 +=====[Nice to know] Optional<​T>​ – evitarea valorilor null=====
 +
 +====Ce este Optional<​T>?​====
 +
 +''​Optional<​T>''​ este un container care poate:
 +  * să conțină o valoare
 +  * sau să fie gol
 +
 +Scopul lui este să evite folosirea lui ''​null''​ și apariția erorilor de tip ''​NullPointerException''​.
 +
 +<code java>
 +Optional<​String>​ opt = Optional.of("​hello"​);​
 +Optional<​String>​ empty = Optional.empty();​
 +</​code>​
 +
 +====De ce avem nevoie de Optional?​====
 +
 +Fără ''​Optional''​ avem următoarea situație:
 +<code java>
 +String name = getName();
 +if (name != null) {
 +    System.out.println(name.length());​
 +}
 +</​code>​
 +
 +În schimb, cu ''​Optional''​ putem scrie codul de mai sus astfel:
 +<code java>
 +Optional<​String>​ name = getName();
 +name.ifPresent(n -> System.out.println(n.length()));​
 +</​code>​
 +
 +<note tip>
 +Prin folosirea ''​Optional'',​ codul:
 +  * este mai sigur
 +  * este mai expresiv
 +  * forțează tratarea cazului „lipsește valoarea”
 +</​note>​
 +
 +====Metode importante din Optional====
 +
 +**1. ''​isPresent()''​**
 +
 +<code java>
 +if (optional.isPresent()) {
 +    System.out.println(optional.get());​
 +}
 +</​code>​
 +
 +Ce face:
 +  * Verifică dacă ''​Optional''​ **conține o valoare**.
 +
 +Problema:
 +  * Duce ușor la **cod de tip null-check mascat**
 +  * Necesită apel ulterior la ''​get()'',​ care poate arunca excepție dacă greșim logica
 +
 +<note tip>
 +Această metodă **nu este recomandată** în stil funcțional modern.
 +</​note>​
 +
 +**2. ''​ifPresent(Consumer<​T>​)''​**
 +
 +<code java>
 +optional.ifPresent(value -> System.out.println(value));​
 +</​code>​
 +
 +Ce face:
 +  * Execută codul doar dacă valoarea există
 +  * Nu necesită ''​get()''​
 +  * Evită ''​NullPointerException''​
 +
 +Când se folosește:
 +  * pentru afișare
 +  * logging
 +  * efecte secundare controlate
 +
 +**3. ''​orElse(T other)''​**
 +
 +<code java>
 +String value = optional.orElse("​default"​);​
 +</​code>​
 +
 +Ce face:
 +  * Returnează valoarea din ''​Optional''​
 +  * Dacă este empty, returnează valoarea furnizată (''"​default"''​)
 +
 +Când se folosește:
 +  * când valoarea default este **constantă** sau foarte ieftină
 +
 +<note important>​
 +Argumentul este **evaluat întotdeauna**,​ chiar dacă ''​Optional''​ are valoare, deci este important să avem grijă la **apelurile de metodă** folosite ca valoare default:
 +<code java>
 +optional.orElse(computeDefault());​ // computeDefault() se execută oricum
 +</​code>​
 +</​note>​
 +
 +**4. orElseGet(...) (lazy)**
 +
 +<code java>
 +String value = optional.orElseGet(() -> computeDefault());​
 +</​code>​
 +
 +Ce face:
 +  * Returnează valoarea din ''​Optional''​
 +  * Dacă este empty, apelează ''​Supplier-ul''​
 +
 +Când se folosește:
 +  * când valoarea default:
 +    * este costisitoare
 +    * implică I/O
 +    * creează obiecte
 +
 +<note important>​
 +Față de metoda ''​orElse'',​ dacă includem ca valoare default un **apel de metodă**, aceasta este apelată **doar dacă este necesar**.
 +<code java>
 +// recomandat
 +optional.orElseGet(this::​computeDefault);​
 +</​code>​
 +</​note>​
 +
 +<note tip>
 +Această metodă este preferată față de ''​orElse(T other)''​.
 +</​note>​
 +
 +**5. orElseThrow()**
 +
 +<code java>
 +String value = optional.orElseThrow();​
 +</​code>​
 +
 +Ce face:
 +  * Returnează valoarea dacă există
 +  * Aruncă ''​NoSuchElementException''​ dacă este empty
 +
 +Când se folosește:
 +  * când lipsa valorii este **o eroare de logică**
 +  * când vrei să **forțezi tratarea cazului empty**
 +
 +Echivalent logic cu:
 +<code java>
 +if (optional.isEmpty()) {
 +    throw new NoSuchElementException();​
 +}
 +return optional.get();​
 +</​code>​
 +
 +Varianta cu excepție custom:
 +<code java>
 +String value = optional.orElseThrow(
 +    () -> new IllegalStateException("​Valoare lipsă"​)
 +);
 +</​code>​
 +
 +====Optional și Stream API====
 +
 +''​Optional''​ poate fi cuplat cu Stream API pentru a crea secvențe de cod avansate:
 +
 +<code java>
 +Optional<​Integer>​ firstEven =
 +    numbers.stream()
 +           ​.filter(x -> x % 2 == 0)
 +           ​.findFirst();​
 +</​code>​
 +
 +În exemplul de mai sus, ''​findFirst()''​ nu întoarce direct valoarea, ci un ''​Optional<​T>''​.
 +
 +==Good practices==
 +
 +Nu folosiți ''​get()''​ direct. Dacă sunteți tentați să folosiți ''​get()'',​ probabil metoda potrivită este:
 +  * ''​ifPresent''​
 +  * ''​orElseGet''​
 +  * ''​orElseThrow''​
 +
 +====Ce nu este Optional====
 +
 +''​Optional''​ se folosește **mai ales ca valoare de return**, dar este important să știm că nu este:
 +  * înlocuitor universal pentru toate valorile
 +  * destinat câmpurilor de clasă
 +  * destinat serializării
 +
 +====Optional<​T>​ vs. Optional Primitives====
 +
 +===Optional<​T>​===
 +
 +''​Optional<​T>''​ este varianta **generică**,​ care funcționează cu **orice tip obiect**.
 +
 +Caracteristici:​
 +  * folosește **tipuri obiect** (''​Integer'',​ ''​Double'',​ ''​String'',​ etc.)
 +  * implică **autoboxing** pentru tipurile primitive
 +  * este flexibil, dar **mai puțin eficient** pentru calcule numerice
 +
 +Exemplu:
 +<code java>
 +Optional<​Integer>​ max =
 +    numbers.stream()
 +           ​.max(Integer::​compareTo);​
 +
 +max.ifPresent(System.out::​println);​
 +</​code>​
 +
 +===OptionalInt/​OptionalLong/​OptionalDouble===
 +
 +''​OptionalInt''​ / ''​OptionalLong''​ și ''​OptionalDouble''​ sunt versiuni specializate pentru primitive.
 +
 +Caracteristici:​
 +  * lucrează direct cu ''​int''​
 +  * **nu folosește autoboxing**
 +  * mai **eficient** din punct de vedere al performanței
 +  * folosit în special împreună cu ''​IntStream''​
 +
 +Exemplu:
 +<code java>
 +OptionalInt max =
 +    numbers.stream()
 +           ​.mapToInt(x -> x)
 +           ​.max();​
 +
 +if (max.isPresent()) {
 +    System.out.println(max.getAsInt());​
 +}
 +</​code>​
 +
 +===Când folosim fiecare?===
 +
 +Folosește ''​Optional<​T>''​ când:
 +  * lucrezi cu **obiecte**
 +  * rezultatul vine dintr-un Stream<​T>​
 +  * tipul nu este numeric
 +
 +Folosește ''​OptionalInt''​ când:
 +  * lucrezi cu **valori numerice primitive**
 +  * folosești ''​mapToInt''​
 +  * vrei cod **mai eficient** și **mai clar**
  
 =====[Optional] Parallel Streams===== =====[Optional] Parallel Streams=====
Line 1124: Line 1460:
   * [[https://​docs.oracle.com/​javase/​8/​docs/​api/​java/​util/​stream/​package-summary.html|Stream API - Oracle Docs]] ​   * [[https://​docs.oracle.com/​javase/​8/​docs/​api/​java/​util/​stream/​package-summary.html|Stream API - Oracle Docs]] ​
   * [[https://​www.baeldung.com/​java-functional-programming|Java Functional Programming - Baeldung]]   * [[https://​www.baeldung.com/​java-functional-programming|Java Functional Programming - Baeldung]]
 +  * [[https://​www.baeldung.com/​java-optional|Guide to Java Optional - Baeldung]]
  
  
poo-ca-cd/laboratoare/programare-functionala-lambda-si-streamuri.1765760827.txt.gz · Last modified: 2025/12/15 03:07 by florian_luis.micu
CC Attribution-Share Alike 3.0 Unported
www.chimeric.de Valid CSS Driven by DokuWiki do yourself a favour and use a real browser - get firefox!! Recent changes RSS feed Valid XHTML 1.0