Estructures de Dades Dinàmiques: Col·leccions i Fluxos
Quan el volum de dades varia en temps d'execució, els arrays es queden curts. Java ofereix un conjunt extens de col·leccions dinàmiques a java.util optimitzades per a diferents escenaris d'accés, cerca i transformació.
3. El Marc de Col·leccions de Java (Collections Framework)
Els arrays tenen un desavantatge fonamental: la seva mida és fixa un cop creats. Per a col·leccions dinàmiques que creixen o es redueixen segons les necessitats, utilitzem el Marc de Col·leccions:
List i ArrayList
Llista ordenada que permet duplicats i redimensionament automàtic:
import java.util.ArrayList;
import java.util.List;
List<String> llista = new ArrayList<>();
llista.add("Poma");
llista.add("Plàtan");
llista.add("Taronja");
println("Nombre d'elements: " + llista.size());
println("Primer element: " + llista.get(0));
Set i HashSet
Col·lecció d'elements únics (sense duplicats) ideal per comprovar pertinència:
import java.util.HashSet;
import java.util.Set;
Set<Integer> codis = new HashSet<>();
codis.add(101);
codis.add(102);
codis.add(101); // No s'afegirà duplicat
println("Total codis únics: " + codis.size()); // 2
Map i HashMap
Estructura de parells clau-valor que permet buscar dades de forma immediata:
import java.util.HashMap;
import java.util.Map;
Map<String, Double> preus = new HashMap<>();
preus.put("Cafè", 1.50);
preus.put("Croissant", 1.80);
println("Preu del Cafè: " + preus.get("Cafè") + " €");
4. Col·leccions Seqüenciades i Streams
En versions modernes de Java disposem de les interfícies de col·lecció seqüenciada (SequencedCollection) amb mètodes còmodes com getFirst(), getLast() i reversed().
A més, l'API de Streams permet processar col·leccions de dades de forma elegant mitjançant operacions de canonada (filter, map, reduce, collect):
List<Integer> nombres = List.of(1, 2, 3, 4, 5, 6, 7, 8, 9, 10);
List<Integer> quadratsParells = nombres.stream()
.filter(n -> n % 2 == 0) // Filtra només els parells
.map(n -> n * n) // Eleva cada nombre al quadrat
.toList();
println(quadratsParells); // [4, 16, 36, 64, 100]
3. Classes i Mètodes Genèrics (<T>)
La genericitat permet definir classes, interfícies i mètodes amb paràmetres de tipus, garantint la comprovació de tipus en temps de compilació i eliminant la necessitat de càstings manuals:
// Classe genèrica que pot guardar qualsevol tipus de dada:
public class Caixa<T> {
private T contingut;
public void guardar(T element) {
this.contingut = element;
}
public T obtenir() {
return this.contingut;
}
}
// Ús:
Caixa<String> caixaText = new Caixa<>();
caixaText.guardar("Document important");
String text = caixaText.obtenir(); // Sense necessitat de càsting!
4. Expressions Regulars en Java (Regex)
Les expressions regulars són patrons de caràcters que permeten validar formats (com correus electrònics, DNIs o dates) i cercar o substituir fragments de text de forma altament eficient:
void main() {
String text = "Pots contactar a info@iesbenigaslo.com o support@oracle.com";
// Comprovació ràpida amb matches():
String cp = "12530";
boolean esCodiPostalValid = cp.matches("\d{5}"); // 5 dígits exactes
println("Codi postal vàlid? " + esCodiPostalValid); // true
// Cerca de patrons amb java.util.regex:
var pattern = java.util.regex.Pattern.compile("[\w.-]+@[\w.-]+\.[a-zA-Z]{2,}");
var matcher = pattern.matcher(text);
while (matcher.find()) {
println("Correu trobat: " + matcher.group());
}
}
Exercicis Pràctics i Qüestionaris
Posa a prova el que has après completant els exercicis de List, Set, Map, StringListUtils, Calendari d'Exàmens i reptes de Streams.
Exercicis