This shows you the differences between two versions of the page.
poo-ca-cd:laboratoare:clase-interne [2022/11/13 01:48] daniela.becheanu [Exerciții] |
poo-ca-cd:laboratoare:clase-interne [2024/12/15 14:12] (current) maria.enescu [Exerciții] |
||
---|---|---|---|
Line 1: | Line 1: | ||
- | ===== Laboratorul 6: Clase interne ===== | + | ===== Laboratorul 10: Clase interne. Lambda expresii. ===== |
**Video introductiv:** [[https://youtu.be/KIyaRwog3q8| link ]] | **Video introductiv:** [[https://youtu.be/KIyaRwog3q8| link ]] | ||
Line 140: | Line 140: | ||
- | <note important>Clasele interne anonime declarate în metode pot folosi variabilele declarate în metoda respectivă și parametrii metodei dacă aceștia sunt //final// sau **//effectively final//**. Dacă o variabilă nu e declarată final dar nu se modifică schimbă după inițializare, atunci este [[https://docs.oracle.com/javase/tutorial/java/javaOO/localclasses.html#accessing-members-of-an-enclosing-class|effectively final]]. | + | <note important>Clasele interne anonime declarate în metode pot folosi variabilele declarate în metoda respectivă și parametrii metodei dacă aceștia sunt //final// sau **//effectively final//**. Dacă o variabilă nu e declarată final dar nu se modifică după inițializare, atunci este [[https://docs.oracle.com/javase/tutorial/java/javaOO/localclasses.html#accessing-members-of-an-enclosing-class|effectively final]]. |
Variabilele si parametrii metodelor se află pe segmentul de stivă din memorie creat pentru metoda respectivă, ceea ce face ca ele să nu existe la fel de mult cât clasa internă. Dacă variabila este declarată ''final'', atunci la runtime se va stoca o copie a acesteia ca un câmp al clasei interne, în acest mod putând fi accesată și după execuția metodei. | Variabilele si parametrii metodelor se află pe segmentul de stivă din memorie creat pentru metoda respectivă, ceea ce face ca ele să nu existe la fel de mult cât clasa internă. Dacă variabila este declarată ''final'', atunci la runtime se va stoca o copie a acesteia ca un câmp al clasei interne, în acest mod putând fi accesată și după execuția metodei. | ||
Line 153: | Line 153: | ||
Când veți scrie o clasă anonimă într-un IDE cum e IntelliJ, veți primi un warning care vă recomandă să o transformați într-o lambda. Aceasta recomandare este valabilă doar pentru implementarea claselor/interfețelor cu o singură metoda. | Când veți scrie o clasă anonimă într-un IDE cum e IntelliJ, veți primi un warning care vă recomandă să o transformați într-o lambda. Aceasta recomandare este valabilă doar pentru implementarea claselor/interfețelor cu o singură metoda. | ||
- | Lambda este un concept din programarea funcțională (o să îl învățați în semestrul 2 la Paradigme de Programare) și reprezintă o funcție anonimă. Majoritatea limbajelor de nivel înalt au introdus suport pentru acest concept în ultimii 15 ani, inclusiv Java, din versiunea 8. | + | Lambda este un concept din **programarea funcțională** (o să îl învățați în semestrul 2 la Paradigme de Programare) și reprezintă o funcție anonimă. Majoritatea limbajelor de nivel înalt au introdus suport pentru acest concept în ultimii 15 ani, inclusiv Java, din versiunea 8. |
Line 166: | Line 166: | ||
</code> | </code> | ||
- | În codul de mai sus declararea clasei anonime și suprascrierea metodei din getFuelCapacity() a fost înlocuită cu o expresie lambda. O altă situație des intalnită de folosire a lambda-urilor este pentru transmiterea de funcții ca parametru iar api-uri precum cel de filtrare al colecțiilor le utilizează intens ([[https://www.baeldung.com/java-stream-filter-lambda|exemplu]]). | + | În codul de mai sus declararea clasei anonime și suprascrierea metodei din getFuelCapacity() a fost înlocuită cu o expresie lambda. O altă situație des intalnită de folosire a lambda-urilor este pentru **transmiterea de funcții ca parametru** iar api-uri precum cel de filtrare al colecțiilor le utilizează intens ([[https://www.baeldung.com/java-stream-filter-lambda|exemplu]]). |
În exemplul de mai jos aveți niște exemple simple de folosire lambda ca paremetru pentru metode. Parametrii primiți în lambda pot fi zero (//()// ca în exemplul cu fuelCapacity) sau mai mulți (param1, param2, ...). | În exemplul de mai jos aveți niște exemple simple de folosire lambda ca paremetru pentru metode. Parametrii primiți în lambda pot fi zero (//()// ca în exemplul cu fuelCapacity) sau mai mulți (param1, param2, ...). | ||
Line 182: | Line 183: | ||
</code> | </code> | ||
- | Operatorul [[https://www.geeksforgeeks.org/double-colon-operator-in-java/|::]] este folosit pentru referințierea metodelor. | + | **Operatorul [[https://www.geeksforgeeks.org/double-colon-operator-in-java/|::]]** este folosit pentru referințierea metodelor. |
+ | |||
+ | 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). | ||
- | O să mai oferim exemple și detalii despre lambdas și în laboratoarele următoare, de exemplu cel cu [[poo-ca-cd:laboratoare:colectii|Colecții]] sau cel pentru concepte din [[poo-ca-cd:laboratoare:java-features|Java 8]]. | + | 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> | ||
====Clase interne statice==== | ====Clase interne statice==== | ||
Line 357: | Line 383: | ||
} | } | ||
});</code> | });</code> | ||
- | ==== Exerciții ==== | + | ==== Exerciții ==== |
- | /***Task 1 - Meta** (4p) | + | |
- | Îndrumarul este o componentă importantă a laboratorului de POO, iar citirea și înțelegerea acestuia nu trebuie neglijate. În îndrumarul din acest laborator există mai multe căsuțe de tip **note**, de forma celei de mai jos: | + | Exercițiile din acest laborator au ca scop simularea obținerii prețului unei mașini de la un dealer. Construcția obiectelor necesare o veți face de la zero conform instrucțiunilor din taskuri. |
- | <note> Do stuff </note> | + | <note important> |
+ | Pentru a încărca soluția, va trebui să accesați link-ul https://code.devmind.ro/login, să intrați pe tab-ul Contests, unde veți găsi laboratorul grupei voastre. | ||
+ | </note> | ||
- | Identificați toate căsuțele de tip **note** din laborator și urmați instrucțiunile din acestea. Puteți folosi scheletul pus la dispoziție. Pentru a ușura procesul de evaluare, creați fișiere separate pentru fiecare task din **note**. | ||
- | */ | ||
- | Exercițiile din acest laborator au ca scop simularea obținerii prețului unei mașini de la un dealer. Construcția obiectelor necesare o veți face de la zero conform instrucțiunilor din taskuri. | + | ** Task 1 - Structura de bază ** (2p) |
- | |||
- | ** Task 1 - Structura de bază ** (2p) | ||
** Car ** | ** Car ** | ||
- | |||
Creați clasa ''Car'' cu următoarele proprietăți: prețul, tipul și anul fabricației. | Creați clasa ''Car'' cu următoarele proprietăți: prețul, tipul și anul fabricației. | ||
- | + | * ''Tipul'' este reprezentat printr-un enum [[https://www.w3schools.com/java/java_enums.asp|enum]] ''CarType'' declarat intern în Car. Acesta conține trei valori: Mercedes, Fiat și Skoda. | |
- | Tipul este reprezentat printr-un [[https://www.w3schools.com/java/java_enums.asp|enum]] ''CarType'' declarat intern în ''Car''. Acesta conține trei valori, fiind la latitudinea voastră ce mărci de mașini alegeți. | + | * ''Prețul'' și ''anul'' vor fi de tipul integers. |
- | + | Creați un constructor cu toti cei trei parametri, în ordinea din enunț și suprascrieți metoda toString() pentru afișare în felul următor: Car{price=20000, carType=SKODA, year=2019} | |
- | Prețul și anul pot fi integers. | + | |
Line 390: | Line 411: | ||
- | ** Task 2 - Ofertele** (2p) | + | ** Task 2 - Ofertele** (4p) |
În clasa ''Dealership'' creați trei **clase interne** private care implementează ''Offer''. | În clasa ''Dealership'' creați trei **clase interne** private care implementează ''Offer''. | ||
- | * ''BrandOffer'' - calculează un discount în funcție de tipul mașinii (e.g. pentru o dacie discount-ul este 5% din prețul ei) | + | * ''BrandOffer'' - calculează un discount în funcție de tipul mașinii: |
- | * ''DealerOffer'' - calculează un discount în funcție de vechimea mașinii (e.g. 100 pentru fiecare an de vechime) | + | - Mercedes: discount 5%; |
- | * ''SpecialOffer'' - calculează un discount random (e.g. random între 0 și 300) | + | - Fiat: discount 10%; |
+ | - Skoda: discount 15%; | ||
+ | * ''DealerOffer'' - calculează un discount în funcție de vechimea mașinii: | ||
+ | - Mercedes: discount 300 pentru fiecare an de vechime; | ||
+ | - Fiat: discount 100 pentru fiecare an de vechime; | ||
+ | - Skoda: discount 150 pentru fiecare an de vechime; | ||
+ | * ''SpecialOffer'' - calculează un discount random, cu seed 20. Generarea se va realiza în constructor utilizându-se o instanța globală a unui obiect de tip ''Random'' care a fost inițializat cu seed-ul **20** și cu limita superioară (bound) 1000 [[https://docs.oracle.com/javase/8/docs/api/java/util/Random.html#Random-long-|Random]]. | ||
Adăugați o metodă în clasa ''Dealership'' care oferă prețul mașinii după aplicarea discount-urilor din oferte: ''getFinalPrice(Car car)'' | Adăugați o metodă în clasa ''Dealership'' care oferă prețul mașinii după aplicarea discount-urilor din oferte: ''getFinalPrice(Car car)'' | ||
- | * aplicați pe obiectul ''car'' primit ca argument cele trei oferte | + | * aplicați pe obiectul ''car'' primit ca argument cele trei oferte in ordinea: ''BrandOffer'', ''DealerOffer'', ''SpecialOffer''. |
- | * metoda poate returna prețul final după aplicarea ofertelor sau void | + | * metoda va returna prețul final după aplicarea ofertelor |
- | ** Task 3 - Test ** (2p) | ||
- | Creați clasa ''Test'' cu o metodă ''main'' în care să testați funcționalitatea. | + | Testare oferte: |
- | * cel puțin un obiect ''Car'' pentru fiecare tip de mașină | + | Creati 2 obiecte Car pentru fiecare tip de mașină cu urmatoarele valori:. |
- | * un obiect de tip ''Dealership'' | + | -Mercedes: |
- | * obțineți și afișați prețul oferit de ''Dealership'' pentru fiecare obiect | + | -Pret: 20000, An: 2010; |
+ | -Pret: 35000, An: 2015; | ||
+ | -Fiat: | ||
+ | -Pret: 3500, An: 2008; | ||
+ | -Pret: 7000, An: 2010; | ||
+ | -Skoda: | ||
+ | -Pret: 12000, An: 2015; | ||
+ | -Pret: 25000, An: 2021; | ||
+ | |||
+ | * Creati un obiect de tip Dealership. | ||
+ | * Obțineți și afișați prețul oferit de Dealership(folosind metoda ''getFinalPrice'') pentru fiecare obiect. | ||
+ | * De fiecare data cand se aplica o oferta asupra unui obiect de tip Car se va afisa un mesaj de tipul: "Applying x discount: y euros", unde: | ||
+ | * x reprezinta oferta care a fost aplicata(Brand, Dealer, Special, Client) | ||
+ | * y reprezinta discount-ul ofertei. | ||
| | ||
- | ** Task 4 - Negocierea ** (2p) | + | ** Task 3 - Negocierea ** (2p) |
- | Aăugați în clasa ''Dealership'' metoda ''void negotiate(Car car, Offer offer)''. Aceasta permite clientului să propună un discount. Dealershipul aplică oferta primită de la client sau nu (dat random de un ''randInt(2)''). | + | Aăugați în clasa ''Dealership'' metoda ''void negotiate(Car car, Offer offer)''. Aceasta permite clientului să propună un discount. |
- | În metoda ''main'' din ''Test'' apelați ''negotiate'' dând ca parametru **oferta sub formă de clasă anonimă**. Implementarea ofertei clientului poate fi un simplu return de o valoare aleasă de voi. | + | În metoda ''main'' apelați ''negotiate'' dând ca parametru **oferta sub formă de clasă anonimă**. Implementarea ofertei clientului reprezinta returnarea unui discount de 5%. |
- | + | Pentru testare folositi urmatorul obiect Car: | |
- | + | -Pret: 20000 | |
- | **Exemplu output** - aceasta este sugestia noastră, voi puteți afișa și în alt fel, contează însă să evidențiați aplicarea ofertelor și prețurile. | + | -Tip: Mercedes |
- | + | -An: 2019 | |
- | <code> | + | |
- | Initial price: 10000 euros | + | |
- | Applying Brand discount: 1000 euros | + | |
- | Applying Dealer discount: 100 euros | + | |
- | Applying Special discount: 957 euros | + | |
- | Final price: 7943 | + | |
- | Applying Client discount: 600 euros | + | |
- | Final price after negotiation: 7343 euros | + | |
- | </code> | + | |
- | ** Task 5 - Lambda** (1p) | + | ** Task 4 - Lambda** (2p) |
- | Testați folosirea expresiilor lambda pe următorul caz: pe o listă de obiecte de tip Car cu prețuri variate, eliminați toate mașinile care au prețul peste o anumită sumă. Afișați lista înainte și după modificare. | + | Testați folosirea expresiilor lambda pe următorul caz: pe o listă de obiecte de tip Car cu prețuri variate, eliminați toate mașinile care au prețul peste 25000. Afișați lista înainte și după modificare. |
+ | Pentru lista folositi urmatoarele obiecte Car: | ||
+ | -Mercedes: | ||
+ | - Pret: 30000, An: 2019; | ||
+ | - Pret: 50000, An: 2021; | ||
+ | -Fiat: | ||
+ | - Pret: 10000, An: 2018; | ||
+ | -Skoda: | ||
+ | - Pret: 20000, An: 2019; | ||
* Hint: exemplul din secțiunea [[poo-ca-cd:laboratoare:clase-interne#expresii_lambda|Expresii Lambda]] | * Hint: exemplul din secțiunea [[poo-ca-cd:laboratoare:clase-interne#expresii_lambda|Expresii Lambda]] | ||