%%{init: {"themeCSS": ".cluster rect { fill: transparent; stroke: none; }"}}%%
flowchart LR
%% subgraph notes["array notes (5 elements)"]
%% direction LR
A["7<br/>índex 0"] --- B["4<br/>índex 1"] --- C["9<br/>índex 2"] --- D["6<br/>índex 3"] --- E["8<br/>índex 4"]
%% end
9 Arrays i Strings
Objectius
- Entendre què és un array i quan et cal.
- Declarar, crear i inicialitzar arrays d’una dimensió (1D).
- Recórrer arrays amb
fori amb el buclefor-each. - Fer cerques (lineal) i ordenacions senzilles.
- Treballar amb arrays de dues dimensions (2D), com una graella.
- Manipular text amb la classe
Stringi els seus mètodes. - Construir text de manera eficient amb
StringBuilder. - Fer una primera passa per les expressions regulars (regex).
Imagina que has de guardar les notes de 30 alumnes. ¿Declararàs 30 variables (nota1, nota2, …, nota30)? Seria una bogeria: no podries recórrer-les amb un bucle ni fer-hi càlculs còmodament. La solució són els arrays: una manera de guardar moltes dades del mateix tipus sota un únic nom. I com que el text és un cas particular de col·lecció de caràcters, aprofitarem per dominar els Strings.
9.1 Què és un array
Un array (o vector) és un contenidor de mida fixa que guarda un conjunt de valors del mateix tipus, col·locats en posicions consecutives i numerades.
Un array és com el bloc de bústies de l’entrada d’un edifici: una fila de calaixos idèntics, tots del mateix tipus, cadascun amb un número. Per accedir al contingut d’un calaix, no necessites obrir-los tots: només has de saber el seu número. Aquest número és l’índex.
La característica més important —i la que més errors provoca al principi— és que els índexs comencen a 0.
Un array de 5 elements té els índexs 0, 1, 2, 3 i 4. No existeix la posició 5.
9.2 Arrays d’una dimensió
9.2.1 Declarar i crear
Hi ha dues maneres de posar en marxa un array:
// Manera 1: crear-lo buit amb una mida fixa (s'omple de zeros)
int[] notes = new int[5]; // 5 enters, tots valen 0 de moment
// Manera 2: crear-lo ja amb valors coneguts
int[] edats = {18, 20, 19, 22, 21};Quan crees un array amb new int[5], Java el reserva ple de valors per defecte: 0 per als enters, 0.0 per als decimals, false per als booleans i null per als objectes i String.
9.2.2 Accedir i modificar
S’accedeix a cada element amb el nom de l’array i l’índex entre claudàtors [ ]:
int[] notes = {7, 4, 9, 6, 8};
System.out.println(notes[0]); // 7 (primer element)
System.out.println(notes[2]); // 9 (tercer element)
notes[1] = 10; // canviem el segon element
System.out.println(notes[1]); // 10Tot array coneix la seva mida gràcies a .length (fixa’t: sense parèntesis, no és un mètode):
System.out.println("Té " + notes.length + " elements."); // 5Aquest és el clàssic. Un array de 5 elements té índexs de 0 a 4. Si intentes accedir a notes[5], Java llança una ArrayIndexOutOfBoundsException (recorda Capítol 8):
int[] notes = new int[5];
notes[5] = 100; // ERROR! l'últim índex vàlid és 4Regla d’or: l’últim índex vàlid sempre és length - 1.
9.2.3 Recórrer un array
Aquí és on els arrays brillen: combinats amb un bucle (Capítol 7), pots processar tots els elements amb poques línies. Fes servir .length com a límit:
int[] notes = {7, 4, 9, 6, 8};
for (int i = 0; i < notes.length; i++) {
System.out.println("Nota " + i + ": " + notes[i]);
}Quan només vols llegir els valors i no et cal l’índex, hi ha una forma més neta: el bucle for-each. Es llegeix “per a cada nota dins de notes”:
for (int nota : notes) {
System.out.println(nota);
}Compara les dues formes de recórrer:
| Situació | for clàssic |
for-each |
|---|---|---|
| Tens l’índex? | Sí (i) |
No |
| Pots modificar l’array? | Sí (notes[i] = ...) |
No (només llegeixes) |
| Recórrer al revés o saltant? | Sí | No |
| Llegibilitat quan només llegeixes | Bona | Excel·lent |
Donat un array de temperatures {22, 19, 25, 30, 18}, calcula i mostra la mitjana, la temperatura màxima i la mínima. Pista: recorre l’array amb un for i ves actualitzant tres variables.
9.3 Cerca i ordenació
Dues de les tasques més habituals amb arrays són buscar un element i ordenar-los.
9.3.1 Cerca lineal
La cerca més senzilla és la lineal: mirar element per element fins a trobar el que busques (o arribar al final).
int[] edats = {18, 20, 19, 22, 21};
int busca = 22;
int posicio = -1; // -1 vol dir "no trobat"
for (int i = 0; i < edats.length; i++) {
if (edats[i] == busca) {
posicio = i;
break; // ja l'hem trobat, no cal seguir (@sec-repeticio)
}
}
if (posicio != -1) {
System.out.println("Trobat a la posició " + posicio);
} else {
System.out.println("No hi és.");
}9.3.2 Ordenació
Ordenar a mà (amb algorismes com el bubble sort) és un exercici clàssic molt útil per entendre bucles niats. Però a la pràctica, Java ja et dona l’ordenació feta amb Arrays.sort:
import java.util.Arrays;
int[] numeros = {5, 2, 9, 1, 7};
Arrays.sort(numeros);
System.out.println(Arrays.toString(numeros)); // [1, 2, 5, 7, 9]Arrays.toString
Si escrius System.out.println(numeros) directament, veuràs una cosa lletja com [I@1b6d3586: la direcció de memòria, no el contingut. Per veure els valors, fes servir Arrays.toString(numeros).
Crea un array amb 6 nombres desordenats. Ordena’l amb Arrays.sort i després busca amb cerca lineal si hi ha el nombre 7.
9.4 Arrays de dues dimensions
Un array 1D és una fila. Un array 2D és una graella (files i columnes): perfecte per a taulers de joc, matrius, fulls de càlcul o mapes. És, en essència, “un array d’arrays”.
// 3 files, 4 columnes, tot a 0
int[] filaUnica; // 1D, per comparar
int[][] taula = new int[3][4]; // 2D
// Amb valors inicials
int[][] tauler = {
{1, 2, 3},
{4, 5, 6},
{7, 8, 9}
};S’accedeix amb dos índexs: tauler[fila][columna].
System.out.println(tauler[0][0]); // 1: cantonada superior esquerra
System.out.println(tauler[1][2]); // 6 : fila 1, columna 2
tauler[2][0] = 70; // Modifiquem la cantonada inferiorflowchart TD
subgraph G["tauler[fila][columna]"]
direction TB
R0["[0][0]=1 · [0][1]=2 · [0][2]=3"]
R1["[1][0]=4 · [1][1]=5 · [1][2]=6"]
R2["[2][0]=7 · [2][1]=8 · [2][2]=9"]
end
| tauler | 0 | 1 | 2 |
|---|---|---|---|
| 0 | 1 | 2 | 3 |
| 1 | 4 | 5 | 6 |
| 2 | 70 | 8 | 9 |
Per recórrer una graella necessites bucles aniuats: un per a les files i un altre per a les columnes.
for (int fila = 0; fila < tauler.length; fila++) { // nombre de files
for (int col = 0; col < tauler[fila].length; col++) { // columnes d'aquesta fila
System.out.print(tauler[fila][col] + " ");
}
System.out.println(); // salt de línia en acabar cada fila
}tauler.length et dona el nombre de files. Per saber les columnes d’una fila, has de mirar tauler[fila].length. Intercanviar els dos índexs (tauler[col][fila]) és un error molt freqüent que sovint provoca una ArrayIndexOutOfBoundsException.
Crea un tauler 3×3 de tres en ratlla amb caràcters (char[][]), omple’l de guions - i col·loca-hi una X al centre. Mostra’l per pantalla amb bucles niats.
9.5 La classe String
Un String és una cadena de text. Ja l’has fet servir des del primer programa, però ara veuràs que és un objecte ple de mètodes útils. Internament, un String és una seqüència de caràcters (gairebé un array de char), per això molts conceptes d’aquest capítol s’hi apliquen.
String nom = "Programació";
System.out.println(nom.length()); // 11 (nombre de caràcters)
System.out.println(nom.charAt(0)); // P (caràcter a la posició 0)
System.out.println(nom.toUpperCase()); // PROGRAMACIÓ
System.out.println(nom.toLowerCase()); // programació
System.out.println(nom.substring(0, 4)); // Prog (de 0 a 3)
System.out.println(nom.indexOf("gram")); // 3 (on comença)
System.out.println(nom.contains("gra")); // true
System.out.println(nom.replace("ó", "o")); // ProgramacioEls mètodes de String més útils:
| Mètode | Què fa |
|---|---|
length() |
Nombre de caràcters |
charAt(i) |
Caràcter a la posició i |
substring(inici, fi) |
Tros de text (fi no inclòs) |
indexOf(text) |
Posició on apareix (o -1) |
contains(text) |
Conté aquest text? |
toUpperCase() / toLowerCase() |
Majúscules / minúscules |
trim() |
Treu espais dels extrems |
replace(a, b) |
Substitueix a per b |
split(sep) |
Parteix el text en un array |
equals(altre) |
Compara continguts |
==
Per comparar el contingut de dos textos, has d’usar .equals(), mai ==:
String a = "hola";
String b = sc.nextLine(); // L'usuari escriu "hola"
if (a == b) { ... } // MALAMENT: compara si són el mateix objecte
if (a.equals(b)) { ... } // BÉ: compara el contingutAmb == compares si les dues variables apunten exactament al mateix lloc de memòria, no si diuen el mateix. Aquest error dona molts maldecaps. Per ignorar majúscules/minúscules, fes servir equalsIgnoreCase().
Un mètode especialment útil és split, que trosseja un text segons un separador i retorna un array de Strings.
String linia = "Anna;25;Girona";
String[] camps = linia.split(";");
System.out.println(camps[0]); // Anna
System.out.println(camps[1]); // 25
System.out.println(camps[2]); // GironaDemana el nom complet d’una persona i mostra les seves inicials. Pista: split(" ") per separar les paraules i charAt(0) per agafar la primera lletra de cadascuna.
9.6 StringBuilder: construir text eficientment
Els Strings a Java són immutables: un cop creats, no es poden canviar. Quan fas text = text + "x", en realitat Java crea un String nou cada vegada. Dins d’un bucle amb moltes voltes, això és molt ineficient.
Modificar un String sumant trossos és com, cada cop que vols afegir una paraula a una carta, escriure tota la carta de nou en un full net. Amb StringBuilder, en canvi, escrius amb llapis sobre el mateix full: afegeixes al final sense reescriure res.
StringBuilder és un text modificable, pensat per construir cadenes peça a peça:
StringBuilder sb = new StringBuilder();
for (int i = 1; i <= 5; i++) {
sb.append(i).append("-"); // afegeix al final
}
System.out.println(sb.toString()); // 1-2-3-4-5-| Mètode | Què fa |
|---|---|
append(x) |
Afegeix x al final |
insert(pos, x) |
Insereix x a la posició |
reverse() |
Inverteix el text |
toString() |
El converteix en String normal |
Per a text senzill o poques concatenacions, String va perfecte i és més llegible. Quan construeixes text dins d’un bucle amb moltes iteracions, fes servir StringBuilder.
9.7 Introducció a les expressions regulars
Una expressió regular (regex) és un patró que descriu la forma que ha de tenir un text. Serveixen per validar (això és un correu vàlid?), buscar i substituir amb regles complexes. Són molt potents, i aquí només en farem una primera ullada.
El mètode matches de String comprova si un text encaixa sencer amb un patró:
String codi = "A1234";
System.out.println(codi.matches("[A-Z][0-9]{4}")); // true: 1 lletra + 4 xifresEls símbols bàsics dels patrons:
| Símbol | Significa | Exemple |
|---|---|---|
[0-9] o \\d |
Una xifra | 5 |
[a-z] |
Una lletra minúscula | k |
[A-Z] |
Una lletra majúscula | M |
. |
Qualsevol caràcter | qualsevol |
+ |
Un o més cops l’anterior | \\d+ = un o més dígits |
* |
Zero o més cops | |
{n} |
Exactament n cops |
[0-9]{4} = 4 xifres |
? |
Opcional (0 o 1 cop) |
Exemple: validar un codi postal (5 xifres):
String cp = "17001";
if (cp.matches("\\d{5}")) {
System.out.println("Codi postal vàlid");
} else {
System.out.println("Format incorrecte");
}En una regex, \d significa “una xifra”. Però dins d’un String de Java, la barra invertida \ és especial, així que l’has d’escriure duplicada: "\\d".
És el mateix motiu que vam veure amb les rutes de fitxers.
Escriu un programa que demani un DNI i comprovi si té el format correcte: 8 xifres seguides d’una lletra majúscula. Pista: el patró és \\d{8}[A-Z].
9.8 Resum
- Un array guarda moltes dades del mateix tipus sota un nom; té mida fixa i els índexs comencen a 0.
- L’últim índex vàlid és
length - 1; sortir-se’n provoca unaArrayIndexOutOfBoundsException. - Es recorren amb
for(quan cal l’índex o modificar) o ambfor-each(quan només es llegeix). - La cerca lineal mira element per element;
Arrays.sortordena, iArrays.toStringmostra el contingut. - Els arrays 2D són graelles: dos índexs
[fila][columna]i bucles niats per recórrer-los. - La classe
Stringofereix molts mètodes (length,substring,split,replace…). Compara sempre ambequals(), mai amb==. StringBuilderconstrueix text de manera eficient dins de bucles, perquè els Strings són immutables.- Les expressions regulars descriuen patrons de text; recorda duplicar la barra (
\\d).
9.9 Per practicar
- Estadístiques. Demana 10 notes, guarda-les en un array i mostra mitjana, màxima, mínima i quantes són aprovats.
- Invertir. Recorre un array del final al principi per mostrar-lo a l’inrevés, i després crea un array nou amb l’ordre invertit.
- Comptar vots. Simula una votació amb un array 1D on cada posició és un candidat i mostra el guanyador.
- Tres en ratlla. Fes un tauler 3×3 amb
char[][], deixa que dos jugadors hi juguin per consola i detecta el guanyador. - Comptador de vocals. Demana una frase i compta quantes vegades apareix cada vocal (fes servir
charAten un bucle). - Palíndrom. Comprova si una paraula es llegeix igual del dret i del revés (pista:
StringBuilder.reverse()). - Validador de dades. Amb regex, valida un correu electrònic senzill, un telèfon de 9 xifres i una matrícula de cotxe (4 xifres + 3 lletres).
- Del fitxer a l’array. Llegeix un CSV de socis, separa cada línia amb
split(";")i guarda els noms en un array.