Apèndix B — Classes útils: dates, números i cadenes
Objectius
- Treballar amb dates i hores (
LocalDate,LocalTime,LocalDateTime,Period,Duration,DateTimeFormatter) i saber per què les classes antiguesDateiCalendarno es fan servir. - Fer càlculs numèrics precisos amb
MathiBigDecimal. - Formatar i convertir números i monedes amb
NumberFormat,CurrencyiDecimalFormat. - Construir i manipular cadenes de text de manera eficient amb
String,StringBuilderiStringJoiner. - Generar valors aleatoris i identificadors únics amb
Random,ThreadLocalRandomiUUID.
Aquest annex aplega classes de la JDK que no formen part del nucli del curs però que necessitaràs constantment en les pràctiques: dates a les factures i registres, monedes als pagaments, cadenes de text a les interfícies… No és una llista exhaustiva: és la caixa d’eines que faràs servir quan toqui.
B.1 Dates i hores: la nova API java.time
B.1.1 Explicació
Durant anys Java va gestionar les dates amb java.util.Date i java.util.Calendar, classes plenes de problemes de disseny. Des de Java 8 hi ha l’API java.time, que és la que s’ha de fer servir avui dia.
Les quatre classes fonamentals són:
| Classe | Representa | Exemple |
|---|---|---|
LocalDate |
Una data (dia, mes, any) | 2026-08-16 |
LocalTime |
Una hora (hora, minut, segon) | 21:30:15 |
LocalDateTime |
Data i hora juntes | 2026-08-16T21:30:15 |
Duration / Period |
Un lapse de temps | 3 dies / 2 hores |
El calendari de la cuina (la data) i el rellotge del microones (l’hora) són dues coses diferents. LocalDate és el calendari; LocalTime, el rellotge; i LocalDateTime és la foto dels dos junts. Separar-los evita confusions: què vol dir “sumar 1 dia a les 15:30”?
B.1.2 Crear dates: now() i of()
import java.time.LocalDate;
import java.time.LocalTime;
import java.time.LocalDateTime;
LocalDate avui = LocalDate.now(); // data actual del sistema
LocalTime ara = LocalTime.now(); // hora actual
LocalDateTime araMateix = LocalDateTime.now();
LocalDate aniversari = LocalDate.of(2005, 3, 14); // any, mes, dia
LocalTime classe = LocalTime.of(9, 0); // 9:00
LocalDateTime festa = LocalDateTime.of(2026, 12, 31, 23, 59);B.1.3 Llegir i modificar parts d’una data
Les classes tenen mètodes per consultar parts i per obtenir còpies modificades (les dates són immutables: cap mètode les canvia, sempre retorna una de nova).
LocalDate avui = LocalDate.now();
System.out.println(avui.getDayOfMonth()); // 16
System.out.println(avui.getMonthValue()); // 8
System.out.println(avui.getYear()); // 2026
System.out.println(avui.getDayOfWeek()); // SUNDAY
LocalDate dema = avui.plusDays(1); // NO modifica avui: en retorna una de nova
LocalDate faUnMes = avui.minusMonths(1);
LocalDate primerDelMes = avui.withDayOfMonth(1);avui.plusDays(1) no canvia avui. Les classes de java.time són immutables: el resultat s’ha de guardar en una variable nova. Si no, la data “sembla que no canvia mai”.
B.1.4 Comparar dates i calcular diferències
LocalDate avui = LocalDate.now();
LocalDate aniversari = LocalDate.of(2005, 3, 14);
System.out.println(aniversari.isBefore(avui)); // true
System.out.println(avui.isAfter(aniversari)); // true
System.out.println(aniversari.equals(avui)); // false
// Diferència en dies (amb Period, que serveix per a dates)
import java.time.Period;
Period p = Period.between(aniversari, avui);
System.out.println(p.getYears() + " anys"); // 21 anys
System.out.println(p.getMonths() + " mesos i " + p.getDays() + " dies");
// Diferència en hores/minuts (amb Duration, que serveix per a temps)
import java.time.Duration;
LocalTime inici = LocalTime.of(9, 0);
LocalTime fi = LocalTime.of(11, 30);
Duration d = Duration.between(inici, fi);
System.out.println(d.toMinutes() + " minuts"); // 150 minutsMini-repte. Quants dies falten per al teu proper aniversari? Calcula-ho amb LocalDate.now(), LocalDate.of(...) i Period.between(...).
B.1.5 Formatat: DateTimeFormatter
Per mostrar dates de manera llegible (i per llegir dates d’un text) es fa servir DateTimeFormatter.
import java.time.LocalDate;
import java.time.format.DateTimeFormatter;
import java.util.Locale;
LocalDate avui = LocalDate.now();
DateTimeFormatter f1 = DateTimeFormatter.ofPattern("dd/MM/yyyy");
System.out.println(avui.format(f1)); // 16/08/2026
DateTimeFormatter f2 = DateTimeFormatter.ofPattern("EEEE, d 'de' MMMM 'de' yyyy", new Locale("ca"));
System.out.println(avui.format(f2)); // diumenge, 16 de agost de 2026
// Llegir una data des d'un text
LocalDate data = LocalDate.parse("14/03/2005", f1);
System.out.println(data.getYear()); // 2005Els patrons més habituals són:
| Patró | Significat | Exemple |
|---|---|---|
d / dd |
Dia (1-2 dígits) | 6 / 06 |
M / MM |
Mes (1-2 dígits) | 3 / 03 |
MMM |
Mes abreujat | gen. |
MMMM |
Mes complet | gener |
yy / yyyy |
Any (2 / 4 dígits) | 26 / 2026 |
H / HH |
Hora (0-23) | 9 / 09 |
mm |
Minuts | 05 |
ss |
Segons | 30 |
EEEE |
Dia de la setmana | diumenge |
'text' |
Text literal | de |
B.1.6 Per què no fer servir Date i Calendar
java.util.Date (mutable, amb el comptatge de mesos començant a 0, sense dates només-hora…) i Calendar (complexa i poc intuïtiva) estan desaconsellades. L’API java.time les substitueix. Fes servir les noves sempre que puguis.
B.2 Números: Math i BigDecimal
B.2.1 Explicació
La classe Math aporta operacions matemàtiques sobre double. Tots els seus mètodes són estàtics, per això es criden amb el nom de la classe.
double x = 7.4;
System.out.println(Math.round(x)); // 7 (arrodoneix a l'enter més proper)
System.out.println(Math.floor(x)); // 7.0 (cap avall)
System.out.println(Math.ceil(x)); // 8.0 (cap amunt)
System.out.println(Math.abs(-5)); // 5
System.out.println(Math.max(3, 9)); // 9
System.out.println(Math.pow(2, 10)); // 1024.0
System.out.println(Math.sqrt(144)); // 12.0
System.out.println(Math.PI); // 3.14159...
System.out.println(Math.random()); // un double entre 0 (inclòs) i 1 (exclòs)B.2.2 BigDecimal: el diner no s’arrodoneix
Els double no representen bé els decimals exactes: 0.1 + 0.2 no és 0.3. Per al diners (i qualsevol càlcul que hagi de ser exacte) s’usa BigDecimal.
import java.math.BigDecimal;
import java.math.RoundingMode;
double a = 0.1;
double b = 0.2;
System.out.println(a + b); // 0.30000000000000004 (ERROR!)
BigDecimal c = new BigDecimal("0.1");
BigDecimal d = new BigDecimal("0.2");
System.out.println(c.add(d)); // 0.3 (exacte)
// Preu amb IVA i 2 decimals
BigDecimal preu = new BigDecimal("19.99");
BigDecimal iva = preu.multiply(new BigDecimal("0.21"));
BigDecimal total = preu.add(iva).setScale(2, RoundingMode.HALF_UP);
System.out.println(total); // 24.19BigDecimal a partir d’un double
new BigDecimal(0.1) guarda l’error del double dins. Sempre crea’l a partir d’un text: new BigDecimal("0.1").
Mini-repte. Un article costa 35.50 € i s’aplica un descompte del 15 %. Calcula el preu final amb BigDecimal i 2 decimals.
B.3 Monedes i percentatges: NumberFormat i Currency
B.3.1 Explicació
Formatar un número depèn de la llengua (català: coma decimal i punt dels milers; estatunidenc: a l’inrevés). NumberFormat ho fa automàticament a partir d’un Locale.
import java.text.NumberFormat;
import java.util.Currency;
import java.util.Locale;
double preu = 1234.5;
NumberFormat en = NumberFormat.getNumberInstance(Locale.US); // 1,234.5
NumberFormat ca = NumberFormat.getNumberInstance(new Locale("ca")); // 1.234,5
System.out.println(en.format(preu));
System.out.println(ca.format(preu));
// Moneda: símbol i 2 decimals segons la llengua
NumberFormat euros = NumberFormat.getCurrencyInstance(new Locale("ca"));
euros.setCurrency(Currency.getInstance("EUR"));
System.out.println(euros.format(preu)); // 1.234,50 €
// Percentatge
NumberFormat pct = NumberFormat.getPercentInstance(new Locale("ca"));
System.out.println(pct.format(0.21)); // 21 %DecimalFormat?
DecimalFormat permet patrons manualment ("#,##0.00", "00000") sense dependre de la llengua. Va bé quan vols un format fix, però NumberFormat amb un Locale és la manera “correcta” quan l’aplicació pot canviar d’idioma.
B.4 Cadenes de text: String, StringBuilder i StringJoiner
B.4.1 Explicació
String és immutable: cada operació que “modifica” una cadena crea una de nova. Per a concatenacions en bucle això és car. StringBuilder és la classe mutable per construir text de manera eficient. StringJoiner agrupa elements amb un separador.
import java.util.StringJoiner;
// String: immutable (cada + crea una cadena nova)
String nom = "Oriol";
String salutacio = "Hola, " + nom + "!";
// StringBuilder: eficient per a concatenacions en bucle
StringBuilder sb = new StringBuilder();
for (int i = 1; i <= 5; i++) {
sb.append(i).append(", ");
}
sb.delete(sb.length() - 2, sb.length()); // treu l'últim ", "
System.out.println(sb); // 1, 2, 3, 4, 5
// StringJoiner: separador automàtic
StringJoiner sj = new StringJoiner(", ");
sj.add("Anna").add("Biel").add("Carla");
System.out.println(sj); // Anna, Biel, Carla
// String.format: plantilles (com printf però retorna una cadena)
String missatge = String.format("Benvingut/da, %s! Tens %d missatges.", nom, 3);
System.out.println(missatge);String— per a text que no canvia, o que canvia poques vegades.StringBuilder— per a concatenacions en bucles o text que es construeix a poc a poc.StringJoiner— per ajuntar una llista d’elements amb un separador.String.format— per a missatges amb plantilla (comprintf).
Mini-repte. Converteix la llista ["Anna", "Biel", "Carla"] en el text "Anna · Biel · Carla" fent servir StringJoiner.
B.5 Aleatorietat: Random, ThreadLocalRandom i UUID
B.5.1 Explicació
Per generar valors aleatoris es fa servir java.util.Random (o ThreadLocalRandom en programes concurrents). Per a identificadors únics (un codi de comanda, un id de client) s’usa UUID, que genera un valor pràcticament irrepetible.
import java.util.Random;
import java.util.UUID;
Random r = new Random();
System.out.println(r.nextInt(100)); // un int entre 0 i 99
System.out.println(r.nextInt(10) + 1); // un int entre 1 i 10
System.out.println(r.nextDouble()); // un double entre 0 i 1
System.out.println(r.nextBoolean()); // true o false
// Llavor: mateixa llavor → mateixa seqüència
Random r1 = new Random(42);
Random r2 = new Random(42);
System.out.println(r1.nextInt(100) == r2.nextInt(100)); // true
// Identificador únic
String id = UUID.randomUUID().toString();
System.out.println(id); // per exemple 9f3c...-...-...-...-...B.6 Resum
- Les dates i hores es treballen amb l’API
java.time:LocalDate,LocalTime,LocalDateTime,Period(dates),Duration(temps) iDateTimeFormatter(formatar/analitzar). Són classes immutables. Mathdóna operacions matemàtiques; per a càlculs exactes (diners) s’usaBigDecimalcreat a partir d’un text.NumberFormat+Localeformata números, monedes i percentatges segons la llengua;DecimalFormatserveix per a patrons fixos.Stringés immutable;StringBuilderconstrueix text eficientment en bucles;StringJoinerajunta elements amb un separador;String.formatfa plantilles.Random(amb llavor o no) iUUIDgeneren valors aleatoris i identificadors únics.
B.7 Per practicar
Quants dies has viscut? Calcula els dies entre la teva data de naixement i avui amb
Period.between(...).getDays()(ajusta amb anys i mesos).Format de factura. Formata
1234567.891com a moneda en català i en estatunidenc. Què canvia?Llista amb separador. Amb
StringJoiner, mostra els teus 5 llibres preferits separats per" · ".Percentatge exacte. Calcula amb
BigDecimalel15 %de99.99 €i arrodoneix a 2 decimals ambHALF_UP.Data des d’un text. Analitza
"05/07/2003"amb unDateTimeFormatteri mostra el dia de la setmana en català.