Les sis lliçons anteriors t'han donat peces soltes: l'estructura d'un fitxer Java, les variables i els seus tipus, els operadors i l'entrada/sortida per consola. Aquesta lliçó les munta totes juntes en el primer programa real del curs: BiblioTechApp, l'aplicació que Nexus Software farà servir per registrar la devolució d'un llibre de la seva biblioteca tècnica i emetre el rebut amb la multa corresponent. No l'escriurem de cop: el construirem en quatre versions successives, cadascuna millorant l'anterior, que és exactament com es desenvolupa programari a la vida real. Al final analitzarem amb honestedat què no sap fer encara i quin mòdul del curs resoldrà cada mancança.
Contingut
- L'especificació del programa
- Versió 1: l'esquelet amb dades fixes
- Versió 2: demanar les dades a l'usuari
- Versió 3: càlculs correctes amb l'operador ternari
- Versió 4: la sortida formatada i el sostre de multa
- El codi complet final, comentat
- Compilar i executar
BiblioTechApp - Jocs de dades de prova i sortida esperada
- Les limitacions del programa i com es resoldran
- Errors Habituals i Consells
- Exercicis
- L'especificació del programa
Abans d'escriure una línia, convé fixar què ha de fer el programa. Això és el primer que es fa en qualsevol projecte professional, i estalvia moltíssima feina.
Nom: BiblioTechApp
Paquet: com.nexussoftware.bibliotech
Comportament esperat:
- Mostrar una capçalera de benvinguda amb el nom de l'empresa i de l'aplicació.
- Demanar per consola les dades de la devolució d'un préstec:
- Nom de l'empleat
- Títol del llibre
- ISBN
- Dies transcorreguts des que es va prestar
- Calcular:
- Els dies de retard, que mai no poden ser negatius.
- El retard expressat en setmanes completes i dies solts.
- La multa: dies de retard multiplicats per la tarifa diària.
- El sostre: la multa no pot superar mai el màxim establert.
- L'estat del préstec: en termini o amb retard.
- Mostrar un rebut formatat i llegible amb totes aquestes dades.
Regles de negoci de la biblioteca de Nexus Software:
| Regla | Valor | Constant |
|---|---|---|
| Durada estàndard del préstec | 15 dies | DIES_PRESTEC |
| Tarifa per dia de retard | 0,25 € | TARIFA_DIARIA |
| Multa màxima per préstec | 20,00 € | MULTA_MAXIMA |
| Llindar de retard lleu | 7 dies | LLINDAR_LLEU |
Restriccions tècniques d'aquesta versió: un únic mètode main, sense condicionals, sense bucles, sense classes pròpies. Tot el que necessites ja ho has après.
flowchart TD
A["Mostrar capçalera"] --> B["Demanar empleat, titol,<br/>ISBN i dies transcorreguts"]
B --> C["Calcular dies de retard<br/>(saturats a zero)"]
C --> D["Descompondre en<br/>setmanes i dies"]
D --> E["Calcular multa base<br/>= retard x tarifa"]
E --> F["Aplicar sostre<br/>MULTA_MAXIMA"]
F --> G["Determinar estat<br/>i gravetat"]
G --> H["Imprimir rebut<br/>formatat amb printf"]
- Versió 1: l'esquelet amb dades fixes
La primera versió no demana res: les dades estan escrites al codi. Serveix per validar l'estructura i els càlculs sense la complicació de l'entrada.
package com.nexussoftware.bibliotech;
public class BiblioTechApp {
public static void main(String[] args) {
final String NOM_EMPRESA = "Nexus Software";
final int DIES_PRESTEC = 15;
final double TARIFA_DIARIA = 0.25;
String empleat = "Marta Ruiz";
String titol = "Java Eficac";
String isbn = "978-0000000001";
int diesTranscorreguts = 27;
int diesRetard = diesTranscorreguts - DIES_PRESTEC;
double multa = diesRetard * TARIFA_DIARIA;
System.out.println("=== BiblioTech - " + NOM_EMPRESA + " ===");
System.out.println("Empleat: " + empleat);
System.out.println("Llibre: " + titol);
System.out.println("ISBN: " + isbn);
System.out.println("Dies de retard: " + diesRetard);
System.out.println("Multa: " + multa + " EUR");
}
}Sortida:
=== BiblioTech - Nexus Software === Empleat: Marta Ruiz Llibre: Java Eficac ISBN: 978-0000000001 Dies de retard: 12 Multa: 3.0 EUR
Funciona, però té tres defectes evidents que anirem corregint:
- Les dades són fixes. Per processar una altra devolució cal editar el codi i recompilar.
- Els càlculs són ingenus. Si el llibre es retorna als 9 dies,
diesRetardvaldria-6i la multa-1.5 EUR: la biblioteca pagant a l'empleat. - La sortida és pobra.
3.0 EURno és un import presentable, i les etiquetes no estan alineades.
- Versió 2: demanar les dades a l'usuari
Substituïm els valors fixos per lectura amb Scanner, aplicant la regla de la lliçó anterior: tot es llegeix amb nextLine() i es converteix amb Integer.parseInt quan cal.
package com.nexussoftware.bibliotech;
import java.util.Scanner;
public class BiblioTechApp {
public static void main(String[] args) {
Scanner entrada = new Scanner(System.in);
final String NOM_EMPRESA = "Nexus Software";
final int DIES_PRESTEC = 15;
final double TARIFA_DIARIA = 0.25;
System.out.println("=== BiblioTech - " + NOM_EMPRESA + " ===");
System.out.println("Registre de devolucio de prestec");
System.out.println();
System.out.print("Empleat : ");
String empleat = entrada.nextLine();
System.out.print("Titol del llibre : ");
String titol = entrada.nextLine();
System.out.print("ISBN : ");
String isbn = entrada.nextLine();
System.out.print("Dies transcorreguts: ");
int diesTranscorreguts = Integer.parseInt(entrada.nextLine());
int diesRetard = diesTranscorreguts - DIES_PRESTEC;
double multa = diesRetard * TARIFA_DIARIA;
System.out.println();
System.out.println("Empleat: " + empleat);
System.out.println("Llibre: " + titol);
System.out.println("ISBN: " + isbn);
System.out.println("Dies de retard: " + diesRetard);
System.out.println("Multa: " + multa + " EUR");
entrada.close();
}
}Ja és un programa útil: el mateix binari serveix per a qualsevol devolució. Però el defecte dels números negatius continua sent-hi. Prova-ho introduint 9 als dies transcorreguts i veuràs Multa: -1.5 EUR.
- Versió 3: càlculs correctes amb l'operador ternari
Aquí entra en joc l'operador ternari per saturar el retard a zero, i de passada hi afegim la descomposició en setmanes i l'estat del préstec. Aquest és el fragment que canvia:
// El retard no pot ser mai negatiu: si es retorna abans d'hora, es 0.
int diesRetard = diesTranscorreguts > DIES_PRESTEC
? diesTranscorreguts - DIES_PRESTEC
: 0;
// Descomposicio del retard: / dona les setmanes completes, % els dies sobrants.
int setmanesRetard = diesRetard / 7;
int diesSolts = diesRetard % 7;
// Dies que queden de termini (0 si ja ha vencut).
int diesRestants = diesTranscorreguts < DIES_PRESTEC
? DIES_PRESTEC - diesTranscorreguts
: 0;
double multaBase = diesRetard * TARIFA_DIARIA;
// Etiquetes de text triades amb ternaris.
String estat = diesRetard > 0 ? "AMB RETARD" : "EN TERMINI";
String gravetat = diesRetard == 0 ? "-"
: diesRetard <= LLINDAR_LLEU ? "LLEU"
: "GREU";Aquest bloc concentra bona part del que s'ha après a la lliçó d'operadors: comparació, resta, divisió entera, mòdul, multiplicació amb promoció automàtica d'int a double, ternari simple i ternari imbricat. Res d'això no requereix if.
- Versió 4: la sortida formatada i el sostre de multa
Falten dues coses: aplicar el sostre de multa i presentar el rebut com un document. Totes dues es resolen amb el que hem vist a la lliçó 01-06.
// Sostre: si la multa base supera el maxim, es cobra el maxim.
double multaFinal = multaBase > MULTA_MAXIMA ? MULTA_MAXIMA : multaBase;
String sostreAplicat = multaBase > MULTA_MAXIMA ? "SI" : "NO";
// Rebut formatat: etiquetes alineades a l'esquerra en amplada 22,
// imports alineats a la dreta amb exactament dos decimals.
System.out.println("=".repeat(AMPLADA));
System.out.printf("%-22s %s%n", "Empleat:", empleat);
System.out.printf("%-22s %8.2f EUR%n", "MULTA A PAGAR:", multaFinal);Amb això, 3.0 es converteix en 3,00 i les columnes queden alineades. Ja tenim el programa complet.
- El codi complet final, comentat
package com.nexussoftware.bibliotech;
import java.util.Scanner;
/**
* BiblioTechApp - Sistema de gestio de la biblioteca tecnica interna
* de Nexus Software.
*
* Versio 0.1 del modul 1: registre lineal de la devolucio d'un
* prestec, amb calcul de retard i multa, i emissio d'un rebut.
*
* @author Equip BiblioTech - Nexus Software
* @version 0.1
*/
public class BiblioTechApp {
public static void main(String[] args) {
// ---------------------------------------------------------------
// 1. RECURSOS
// ---------------------------------------------------------------
// Un unic Scanner per a tota l'aplicacio, connectat al teclat.
// Tancar un Scanner sobre System.in tanca System.in, aixi que
// mai no se'n crea mes d'un.
Scanner entrada = new Scanner(System.in);
// ---------------------------------------------------------------
// 2. REGLES DE NEGOCI
// ---------------------------------------------------------------
// Totes les constants van juntes i a dalt: canviar una tarifa
// es editar UNA linia, no buscar el numero per tot el programa.
// 'final' garanteix que ningu no les modifiqui per accident.
final String NOM_EMPRESA = "Nexus Software";
final String VERSIO = "0.1";
final int DIES_PRESTEC = 15; // durada estandard del prestec
final double TARIFA_DIARIA = 0.25; // euros per dia de retard
final double MULTA_MAXIMA = 20.0; // sostre absolut de la multa
final int LLINDAR_LLEU = 7; // fins a 7 dies, el retard es lleu
final int DIES_SETMANA = 7;
final int AMPLADA = 52; // amplada de les linies del rebut
// ---------------------------------------------------------------
// 3. CAPCALERA DE BENVINGUDA
// ---------------------------------------------------------------
// "=".repeat(AMPLADA) construeix la linia separadora sense teclejar
// 52 signes igual a ma. repeat() existeix des de Java 11.
System.out.println("=".repeat(AMPLADA));
System.out.printf(" BiblioTech v%s - %s%n", VERSIO, NOM_EMPRESA);
System.out.println(" Registre de devolucio de prestec");
System.out.println("=".repeat(AMPLADA));
System.out.println();
// ---------------------------------------------------------------
// 4. RECOLLIDA DE DADES
// ---------------------------------------------------------------
// Es fa servir print (sense ln) perque el cursor es quedi a la
// mateixa linia que la pregunta.
// TOTA la lectura es fa amb nextLine(): aixi mai no queda un
// salt de linia pendent al flux d'entrada, que es el que
// provoca el classic problema de nextInt() seguit de nextLine().
System.out.print("Empleat : ");
String empleat = entrada.nextLine();
System.out.print("Titol del llibre : ");
String titol = entrada.nextLine();
System.out.print("ISBN : ");
String isbn = entrada.nextLine();
System.out.print("Dies transcorreguts: ");
// El text llegit es converteix a numero amb parseInt.
// Si l'usuari escriu alguna cosa que no es un enter, el programa
// acaba amb NumberFormatException (es tractara al modul 6).
int diesTranscorreguts = Integer.parseInt(entrada.nextLine());
// ---------------------------------------------------------------
// 5. CALCULS
// ---------------------------------------------------------------
// Dies de retard saturats a zero. Sense el ternari, una devolucio
// anticipada donaria un retard negatiu i, per tant, una multa
// negativa: la biblioteca pagant a l'empleat.
int diesRetard = diesTranscorreguts > DIES_PRESTEC
? diesTranscorreguts - DIES_PRESTEC
: 0;
// Dies que queden de termini. Nomes te sentit si encara no ha vencut.
int diesRestants = diesTranscorreguts < DIES_PRESTEC
? DIES_PRESTEC - diesTranscorreguts
: 0;
// Descomposicio del retard: la divisio entera dona les setmanes
// completes i el modul dona els dies que sobren.
int setmanesRetard = diesRetard / DIES_SETMANA;
int diesSolts = diesRetard % DIES_SETMANA;
// Multa base. diesRetard es int i TARIFA_DIARIA es double:
// Java promociona l'int a double abans de multiplicar.
double multaBase = diesRetard * TARIFA_DIARIA;
// Sostre de la multa. L'import cobrat no supera mai MULTA_MAXIMA.
double multaFinal = multaBase > MULTA_MAXIMA ? MULTA_MAXIMA : multaBase;
String sostreAplicat = multaBase > MULTA_MAXIMA ? "SI" : "NO";
// Etiquetes de text derivades dels calculs.
String estat = diesRetard > 0 ? "AMB RETARD" : "EN TERMINI";
// Ternari imbricat, llegit com una escala de dalt a baix.
String gravetat = diesRetard == 0 ? "-"
: diesRetard <= LLINDAR_LLEU ? "LLEU"
: "GREU";
// Codi de referencia del rebut: inicial de l'empleat en
// majuscules + els quatre ultims digits de l'ISBN.
// charAt(0) pren el primer caracter; substring retalla des de la
// posicio indicada fins al final.
String referencia = String.format("%c%s-%s",
empleat.charAt(0),
titol.substring(0, 3).toUpperCase(),
isbn.substring(isbn.length() - 4));
// ---------------------------------------------------------------
// 6. REBUT
// ---------------------------------------------------------------
System.out.println();
System.out.println("=".repeat(AMPLADA));
System.out.println(" REBUT DE DEVOLUCIO");
System.out.println("=".repeat(AMPLADA));
// %-22s alinea l'etiqueta a l'ESQUERRA en amplada 22, creant
// una columna uniforme. %s enganxa el valor a continuacio.
System.out.printf("%-22s %s%n", "Referencia:", referencia);
System.out.printf("%-22s %s%n", "Empleat:", empleat);
System.out.printf("%-22s %s%n", "Llibre:", titol);
System.out.printf("%-22s %s%n", "ISBN:", isbn);
System.out.println("-".repeat(AMPLADA));
// %5d alinea els enters a la DRETA en amplada 5, de manera que
// les unitats queden a la mateixa columna i es comparen d'un cop d'ull.
System.out.printf("%-22s %5d dies%n", "Prestec estandard:", DIES_PRESTEC);
System.out.printf("%-22s %5d dies%n", "Transcorreguts:", diesTranscorreguts);
System.out.printf("%-22s %5d dies%n", "Restants de termini:", diesRestants);
System.out.printf("%-22s %5d dies (%d set. i %d dies)%n",
"Retard:", diesRetard, setmanesRetard, diesSolts);
System.out.println("-".repeat(AMPLADA));
// %8.2f: amplada total 8, exactament 2 decimals. Es el que
// converteix un 3.0 cru en un 3,00 presentable.
System.out.printf("%-22s %8.2f EUR%n", "Tarifa diaria:", TARIFA_DIARIA);
System.out.printf("%-22s %8.2f EUR%n", "Multa calculada:", multaBase);
System.out.printf("%-22s %8.2f EUR%n", "Multa maxima:", MULTA_MAXIMA);
System.out.printf("%-22s %8s%n", "Sostre aplicat:", sostreAplicat);
System.out.println("-".repeat(AMPLADA));
System.out.printf("%-22s %8.2f EUR%n", "TOTAL A PAGAR:", multaFinal);
System.out.printf("%-22s %s (%s)%n", "Estat:", estat, gravetat);
System.out.println("=".repeat(AMPLADA));
// Avis pel canal d'error: no forma part del rebut i es pot
// redirigir per separat en executar el programa.
System.err.println("[avis] Versio 0.1: el programa no valida les entrades.");
// ---------------------------------------------------------------
// 7. ALLIBERAMENT DE RECURSOS
// ---------------------------------------------------------------
entrada.close();
}
}
- Compilar i executar
BiblioTechApp
BiblioTechAppEl fitxer ha d'estar al camí que correspon al seu paquet:
bibliotech/
└── src/
└── main/
└── java/
└── com/
└── nexussoftware/
└── bibliotech/
└── BiblioTechApp.javaSituat a src/main/java:
# Compilar. S'indica el CAMI del fitxer, amb barres.
# -d envia els .class a una carpeta 'out' separada del codi font.
javac -d ../../../out com/nexussoftware/bibliotech/BiblioTechApp.java
# Executar. S'indica el NOM DE LA CLASSE qualificat, amb punts.
# -cp diu a l'ordre java on ha de buscar les classes compilades.
java -cp ../../../out com.nexussoftware.bibliotech.BiblioTechAppSi prefereixes treballar sense paquet per provar de pressa, elimina la primera línia (package ...;) i fes servir el mode de fitxer únic de Java 11+:
I si redirigir la sortida et resulta útil, recorda que el rebut i l'avís van per canals diferents:
# El rebut es desa en un fitxer; l'avis continua apareixent a pantalla
java -cp ../../../out com.nexussoftware.bibliotech.BiblioTechApp > rebut.txtA l'IDE n'hi ha prou de prémer el botó d'executar sobre la classe; IntelliJ i Eclipse fan per sota exactament aquestes dues ordres.
- Jocs de dades de prova i sortida esperada
Provar un programa vol dir executar-lo amb dades triades a propòsit per cobrir situacions diferents. Aquests són els dos casos que has de verificar:
| Dada | Joc A: préstec amb retard | Joc B: préstec en termini |
|---|---|---|
| Empleat | Marta Ruiz |
Diego Alonso |
| Títol | Java Eficac |
Refactoritzacio |
| ISBN | 978-0000000001 |
978-0000000003 |
| Dies transcorreguts | 27 |
9 |
| Dies de retard esperats | 12 | 0 |
| Dies restants esperats | 0 | 6 |
| Descomposició | 1 setmana i 5 dies | 0 setmanes i 0 dies |
| Multa calculada | 3,00 EUR | 0,00 EUR |
| Sostre aplicat | NO | NO |
| Total a pagar | 3,00 EUR | 0,00 EUR |
| Estat | AMB RETARD (GREU) | EN TERMINI (-) |
| Referència | MJAV-0001 | DREF-0003 |
Sortida completa del joc A
==================================================== BiblioTech v0.1 - Nexus Software Registre de devolucio de prestec ==================================================== Empleat : Marta Ruiz Titol del llibre : Java Eficac ISBN : 978-0000000001 Dies transcorreguts: 27 ==================================================== REBUT DE DEVOLUCIO ==================================================== Referencia: MJAV-0001 Empleat: Marta Ruiz Llibre: Java Eficac ISBN: 978-0000000001 ---------------------------------------------------- Prestec estandard: 15 dies Transcorreguts: 27 dies Restants de termini: 0 dies Retard: 12 dies (1 set. i 5 dies) ---------------------------------------------------- Tarifa diaria: 0,25 EUR Multa calculada: 3,00 EUR Multa maxima: 20,00 EUR Sostre aplicat: NO ---------------------------------------------------- TOTAL A PAGAR: 3,00 EUR Estat: AMB RETARD (GREU) ====================================================
Sortida completa del joc B
==================================================== BiblioTech v0.1 - Nexus Software Registre de devolucio de prestec ==================================================== Empleat : Diego Alonso Titol del llibre : Refactoritzacio ISBN : 978-0000000003 Dies transcorreguts: 9 ==================================================== REBUT DE DEVOLUCIO ==================================================== Referencia: DREF-0003 Empleat: Diego Alonso Llibre: Refactoritzacio ISBN: 978-0000000003 ---------------------------------------------------- Prestec estandard: 15 dies Transcorreguts: 9 dies Restants de termini: 6 dies Retard: 0 dies (0 set. i 0 dies) ---------------------------------------------------- Tarifa diaria: 0,25 EUR Multa calculada: 0,00 EUR Multa maxima: 20,00 EUR Sostre aplicat: NO ---------------------------------------------------- TOTAL A PAGAR: 0,00 EUR Estat: EN TERMINI (-) ====================================================
Observa el valor del joc B: el cas "en termini" és el que demostra que el ternari funciona. Sense ell, el retard seria -6 i la multa -1,50 EUR. Triar dades que exercitin els casos límit, i no només el cas normal, és el nucli de les proves de programari (mòdul 11).
Un tercer cas que val la pena provar pel teu compte: Nuria Vidal, Patrons de Disseny, ISBN 978-0000000002, 120 dies. El retard seria de 105 dies i la multa calculada de 26,25 EUR, per damunt del màxim: el programa ha de mostrar Sostre aplicat: SI i un total de 20,00 EUR.
- Les limitacions del programa i com es resoldran
BiblioTechApp funciona, però és un programa de joguina i convé ser explícit sobre el perquè. Reconèixer les mancances del teu propi codi és una de les habilitats més valuoses d'un desenvolupador.
| Limitació | Què passa avui | Quan es resol |
|---|---|---|
| No valida les entrades | Si escrius vint-i-set als dies, el programa peta amb NumberFormatException |
Mòdul 2 (comprovar amb hasNextInt) i mòdul 6 (capturar l'excepció i reaccionar) |
| No repeteix | Processa una devolució i acaba. Per a la següent cal tornar a executar-lo | Mòdul 2: bucles i menú interactiu (lliçó 02-06) |
| No pren decisions complexes | Tot es resol amb ternaris, que només trien valors, no executen accions diferents | Mòdul 2: if, switch |
| Les dades estan escampades | titol, autor, isbn i disponible són variables soltes sense relació entre elles |
Mòdul 3: la classe Llibre les agruparà en un tipus propi |
| Només manega un llibre i un empleat | No hi ha manera de gestionar un catàleg de centenars de títols | Mòdul 5: ArrayList i HashMap |
| No desa res | En tancar el programa, el rebut desapareix per sempre | Mòdul 7: escriptura de fitxers, CSV |
| No avisa ningú | Ningú no rep un recordatori abans que venci el termini | Mòdul 8: tasques en segon pla |
| Només funciona a la teva màquina | Un company no pot consultar el catàleg des del seu equip | Mòduls 9 i 12: xarxa i aplicació web |
Fa servir double per a diners |
Els imports poden acumular errors d'arrodoniment | Mòdul 10: BigDecimal |
| No hi ha proves | Verifiques la sortida a ull, executant a mà | Mòdul 11: JUnit |
Fixa't en la lògica del curs: cada mòdul posterior elimina una limitació concreta i visible del programa que acabes d'escriure. No aprendràs bucles perquè toqui, sinó perquè avui el teu programa només processa una devolució. No aprendràs classes perquè sí, sinó perquè avui titol i autor són dues variables sense res que les uneixi.
Errors Habituals i Consells
- Oblidar l'
entrada.nextLine()extra després d'unnextInt(). En aquest programa no passa perquè tota la lectura és ambnextLine(), però si barreges mètodes tornarà a aparèixer. - Escriure
0,25en comptes de0.25en introduir decimals.Double.parseDoubleespera el punt, encara queprintfmostri coma. - Que
substring(isbn.length() - 4)falli. Si l'ISBN té menys de 4 caràcters, llançaStringIndexOutOfBoundsException. En aquesta versió assumim entrades correctes. - Que
empleat.charAt(0)falli si l'usuari prem Enter sense escriure res: la cadena buida no té caràcter a la posició 0. - Fer servir
%damb undoublealprintfdel total. ProvocaIllegalFormatConversionException. - Oblidar
%nen algunprintf, cosa que enganxa dues línies del rebut. - Posar les constants disperses pel codi. Agrupa-les al principi: és la diferència entre canviar la tarifa en deu segons o buscar el
0.25per tot el fitxer. - Consell: quan un càlcul tingui diversos passos (multa base → sostre → total), crea una variable per pas amb nom descriptiu. Una sola expressió gegant és impossible de depurar.
- Consell: executa el programa amb els tres jocs de dades (retard normal, en termini, sostre superat) cada vegada que el modifiquis. És la teva primera bateria de proves manual, i al mòdul 11 la convertiràs en automàtica.
- Consell: desa aquesta versió de
BiblioTechApp.java. Al mòdul 2 en partiràs per afegir-hi el menú interactiu, i comparar totes dues versions et mostrarà el teu propi progrés.
Exercicis
Exercici 1: Ampliar el rebut amb la fiança i l'avís de venciment
Modifica BiblioTechApp per afegir al rebut:
- Una fiança del 10 % del preu del llibre (demana'l per consola com un
double), que es retorna íntegra si no hi ha retard i es redueix en l'import de la multa si n'hi ha. La fiança a retornar no pot ser mai negativa. - Un avís de venciment proper: un text que valgui
"VENCIMENT PROPER"si queden 3 dies o menys de termini (i encara no ha vençut),"EN CURS"si en queden més, i"VENCUT"si ja hi ha retard.
Fes servir només ternaris, sense if. Formata tots els imports amb dos decimals.
Exercici 2: Percentatges i estadístiques del préstec
Amplia el rebut amb tres indicadors calculats, tots amb dos decimals:
- El percentatge de termini consumit:
diesTranscorreguts / DIES_PRESTEC * 100. Compte amb la divisió entera. - El cost mitjà per dia transcorregut: la multa final dividida entre els dies transcorreguts.
- El percentatge de la multa màxima que representa la multa final.
Mostra els tres alineats en una secció "INDICADORS" del rebut.
Exercici 3: Rebut per a dos préstecs simultanis
Sense fer servir bucles ni arrays, amplia el programa perquè registri la devolució de dos llibres del mateix empleat i mostri un rebut conjunt amb:
- Les dades de tots dos llibres en una taula alineada amb
printf. - La multa individual de cadascun.
- El total acumulat, subjecte a un sostre conjunt de
MULTA_MAXIMA. - Quin dels dos llibres acumula més retard (amb l'operador ternari).
Reflexiona al final: què passaria si Nexus Software volgués processar deu llibres? Anota la teva resposta; la reprendrem al mòdul 5.
Solucions
Solució 1
Afegeix la lectura del preu i aquest bloc de càlculs i sortida (la resta del programa no canvia):
// --- Lectura addicional ---
System.out.print("Preu del llibre : ");
double preuLlibre = Double.parseDouble(entrada.nextLine());
// --- Calculs de fianca i avis ---
final double PERCENTATGE_FIANCA = 0.10; // 10 % del preu
final int LLINDAR_AVIS = 3; // dies per avisar del venciment
// La fianca es el 10 % del preu: double * double -> double.
double fianca = preuLlibre * PERCENTATGE_FIANCA;
// Se'n descompta la multa, pero mai no pot quedar en negatiu:
// el ternari satura el resultat a zero.
double fiancaRetornada = fianca - multaFinal > 0
? fianca - multaFinal
: 0.0;
// La retencio es la part de la fianca que es queda la biblioteca.
double fiancaRetinguda = fianca - fiancaRetornada;
// Avis de venciment: escala de ternaris.
// S'avalua de dalt a baix i s'atura a la primera condicio certa.
String avis = diesRetard > 0 ? "VENCUT"
: diesRestants <= LLINDAR_AVIS ? "VENCIMENT PROPER"
: "EN CURS";
// --- Sortida addicional ---
System.out.println("-".repeat(AMPLADA));
System.out.printf("%-22s %8.2f EUR%n", "Preu del llibre:", preuLlibre);
System.out.printf("%-22s %8.2f EUR%n", "Fianca dipositada:", fianca);
System.out.printf("%-22s %8.2f EUR%n", "Fianca retinguda:", fiancaRetinguda);
System.out.printf("%-22s %8.2f EUR%n", "FIANCA A RETORNAR:", fiancaRetornada);
System.out.printf("%-22s %s%n", "Avis:", avis);Comprovació amb els tres casos:
| Cas | Preu | Fiança (10 %) | Multa | Retinguda | A retornar | Avís |
|---|---|---|---|---|---|---|
| Marta, 27 dies | 45,90 | 4,59 | 3,00 | 3,00 | 1,59 | VENCUT |
| Diego, 9 dies | 38,75 | 3,88 | 0,00 | 0,00 | 3,88 | EN CURS |
| Diego, 13 dies | 38,75 | 3,88 | 0,00 | 0,00 | 3,88 | VENCIMENT PROPER |
El punt clau de l'exercici és l'ordre de l'escala de ternaris: la comprovació de diesRetard > 0 ha d'anar la primera. Si es posés després, un préstec vençut amb diesRestants igual a 0 entraria per la branca de "VENCIMENT PROPER", que és falsa.
Solució 2
// --- Indicadors ---
// Compte: diesTranscorreguts i DIES_PRESTEC son int, aixi que
// la divisio seria ENTERA. Cal forcar un double abans.
double percentatgeTermini = (double) diesTranscorreguts / DIES_PRESTEC * 100;
// Cost mitja per dia transcorregut. Aqui multaFinal ja es double,
// aixi que la promocio es automatica i no cal cap cast.
double costMitjaDiari = multaFinal / diesTranscorreguts;
// Quin percentatge del sostre representa el que es cobrara.
double percentatgeMaxim = multaFinal / MULTA_MAXIMA * 100;
System.out.println("-".repeat(AMPLADA));
System.out.println(" INDICADORS");
System.out.println("-".repeat(AMPLADA));
System.out.printf("%-22s %8.2f %%%n", "Termini consumit:", percentatgeTermini);
System.out.printf("%-22s %8.4f EUR/dia%n", "Cost mitja diari:", costMitjaDiari);
System.out.printf("%-22s %8.2f %%%n", "Sobre multa maxima:", percentatgeMaxim);Sortida per al joc A (Marta Ruiz, 27 dies, multa 3,00):
---------------------------------------------------- INDICADORS ---------------------------------------------------- Termini consumit: 180,00 % Cost mitja diari: 0,1111 EUR/dia Sobre multa maxima: 15,00 %
Tres detalls importants:
- El cast
(double)és obligatori al primer càlcul. Sense ell,27 / 15donaria1(divisió entera) i el percentatge seria100,00 %en comptes de180,00 %. És el parany de la lliçó 01-05 en un cas real. %%imprimeix un símbol de percentatge literal. Un%solt faria queprintfintentés interpretar-lo com l'inici d'un especificador i llancésUnknownFormatConversionException.%.4fal cost diari perquè amb dos decimals el valor0,1111s'arrodoniria a0,11i perdria significat. La precisió s'ha de triar segons la magnitud de la dada.
Solució 3
// ================= SEGON LLIBRE =================
System.out.println();
System.out.println("--- Segon llibre ---");
System.out.print("Titol del llibre 2 : ");
String titol2 = entrada.nextLine();
System.out.print("ISBN 2 : ");
String isbn2 = entrada.nextLine();
System.out.print("Dies transcorreguts 2: ");
int diesTranscorreguts2 = Integer.parseInt(entrada.nextLine());
// Els mateixos calculs que per al primer, duplicats.
// Aquesta duplicacio es precisament el que resoldran els METODES
// (modul 3) i els BUCLES sobre colleccions (modul 5).
int diesRetard2 = diesTranscorreguts2 > DIES_PRESTEC
? diesTranscorreguts2 - DIES_PRESTEC
: 0;
double multaBase2 = diesRetard2 * TARIFA_DIARIA;
// Total conjunt, subjecte a un unic sostre per a tota la devolucio.
double totalBrut = multaBase + multaBase2;
double totalFinal = totalBrut > MULTA_MAXIMA ? MULTA_MAXIMA : totalBrut;
// Quin acumula mes retard.
String llibreMesRetardat = diesRetard >= diesRetard2 ? titol : titol2;
int retardMesGran = diesRetard >= diesRetard2 ? diesRetard : diesRetard2;
// ================= REBUT CONJUNT =================
System.out.println();
System.out.println("=".repeat(AMPLADA));
System.out.println(" REBUT CONJUNT DE DEVOLUCIO");
System.out.println("=".repeat(AMPLADA));
System.out.printf("%-22s %s%n", "Empleat:", empleat);
System.out.println("-".repeat(AMPLADA));
// Capcalera de la taula i dues files amb el mateix format.
System.out.printf("%-24s %-16s %5s %9s%n", "LLIBRE", "ISBN", "RETR.", "MULTA");
System.out.printf("%-24s %-16s %5d %9.2f%n", titol, isbn, diesRetard, multaBase);
System.out.printf("%-24s %-16s %5d %9.2f%n", titol2, isbn2, diesRetard2, multaBase2);
System.out.println("-".repeat(AMPLADA));
System.out.printf("%-22s %8.2f EUR%n", "Suma de multes:", totalBrut);
System.out.printf("%-22s %8.2f EUR%n", "TOTAL A PAGAR:", totalFinal);
System.out.printf("%-22s %s (%d dies)%n", "Retard mes gran:", llibreMesRetardat, retardMesGran);
System.out.println("=".repeat(AMPLADA));Exemple de sortida amb Marta Ruiz, "Java Eficac" (27 dies) i "Patrons de Disseny" (40 dies):
==================================================== REBUT CONJUNT DE DEVOLUCIO ==================================================== Empleat: Marta Ruiz ---------------------------------------------------- LLIBRE ISBN RETR. MULTA Java Eficac 978-0000000001 12 3,00 Patrons de Disseny 978-0000000002 25 6,25 ---------------------------------------------------- Suma de multes: 9,25 EUR TOTAL A PAGAR: 9,25 EUR Retard mes gran: Patrons de Disseny (25 dies) ====================================================
La reflexió final de l'exercici és la més important de tot el mòdul. Per a deu llibres necessitaries titol1 … titol10, isbn1 … isbn10, diesRetard1 … diesRetard10: trenta variables, trenta blocs de lectura idèntics i trenta càlculs copiats. El codi seria tres vegades més llarg, impossible de mantenir, i n'hi hauria prou de teclejar diesRetard3 on volies diesRetard4 per produir un rebut erroni que ningú no detectaria.
Aquest dolor té tres solucions i les veuràs en aquest ordre: els bucles (mòdul 2) eliminen la repetició del procés; les classes (mòdul 3) agrupen titol, isbn i diesRetard en un únic objecte Llibre; i les col·leccions (mòdul 5) desen tants llibres com calgui en una sola variable. No és casualitat que el curs segueixi precisament aquest camí.
Conclusió
Has escrit el teu primer programa Java complet i funcional. BiblioTechApp dona la benvinguda a l'usuari, recull per consola les dades d'una devolució, calcula els dies de retard saturats a zero amb l'operador ternari, els descompon en setmanes i dies amb la divisió entera i el mòdul, obté la multa promocionant automàticament int a double, hi aplica un sostre, deriva etiquetes d'estat i gravetat amb ternaris imbricats, compon una referència amb mètodes de String i emet un rebut perfectament alineat amb printf. Tot això amb un únic main, constants final ben agrupades i un únic Scanner correctament tancat.
Amb aquesta lliçó tanques el mòdul 1. Saps què és Java i com s'executa, tens un entorn de desenvolupament funcionant, entens l'anatomia d'un fitxer font, manegues variables, tipus, literals i conversions, domines els operadors i els seus paranys, i saps comunicar-te amb l'usuari per consola en totes dues direccions. I, sobretot, saps exactament què li falta al teu programa: no repeteix, no decideix, no valida i no recorda res.
Al mòdul 2, Flux de control, començaràs a resoldre-ho: amb if i switch el teu programa prendrà decisions de debò, amb while i for processarà tantes devolucions com calgui, amb break i continue afinarà aquest control, aprendràs a depurar pas a pas per veure què passa dins del teu codi, i tot culminarà en el menú interactiu de BiblioTech, la versió que ja no acaba després d'un sol préstec.
Curs de Programació en Java
Mòdul 1: Introducció a Java
- Introducció a Java
- Configuració de l'entorn de desenvolupament
- Sintaxi i estructura bàsica
- Variables i tipus de dades
- Operadors
- Entrada i sortida per consola
- El teu primer programa complet: BiblioTech
Mòdul 2: Flux de control
- Sentències condicionals
- Bucles
- Sentències switch
- Break i continue
- Depuració i traces d'execució
- Projecte: menú interactiu de BiblioTech
Mòdul 3: Programació orientada a objectes
- Introducció a la POO
- Classes i objectes
- Mètodes
- Constructors
- Herència
- Polimorfisme
- Encapsulament
- Abstracció
- La classe Object: equals, hashCode i toString
Mòdul 4: Programació orientada a objectes avançada
- Interfícies
- Classes abstractes
- Classes internes
- Classes anònimes
- Expressions lambda
- Interfícies funcionals i referències a mètodes
- Enumeracions i registres
Mòdul 5: Estructures de dades i col·leccions
- Arrays
- El framework de col·leccions
- ArrayList
- LinkedList
- HashMap
- HashSet
- Cua i Deque
- Pila
- Ordenació i cerca en col·leccions
Mòdul 6: Gestió d'excepcions
- Introducció a les excepcions
- Bloc try-catch
- Throw i throws
- Excepcions personalitzades
- Bloc finally
- Try-with-resources i AutoCloseable
- Estratègies de gestió d'errors i logging
Mòdul 7: Entrada/sortida de fitxers
- Lectura de fitxers
- Escriptura de fitxers
- Fluxos de fitxers
- BufferedReader i BufferedWriter
- Serialització
- L'API NIO.2: Path i Files
- Formats d'intercanvi: CSV i Properties
Mòdul 8: Multifil i concurrència
- Introducció al multifil
- Creació de fils
- Cicle de vida d'un fil
- Sincronització
- Utilitats de concurrència
- Col·leccions concurrents i variables atòmiques
- Tasques asíncrones amb CompletableFuture
Mòdul 9: Xarxes
- Introducció a les xarxes
- Sockets
- ServerSocket
- DatagramSocket i DatagramPacket
- URL i HttpURLConnection
- El client HTTP modern
Mòdul 10: Temes avançats
- Genèrics
- Anotacions
- Reflexió
- Característiques de Java 8: Streams i Optional
- Dates i hores amb java.time
- Java 9 i més enllà
- Memòria, recol·lecció de brossa i rendiment
Mòdul 11: Frameworks i llibreries de Java
- Introducció als frameworks de Java
- Spring Framework
- Hibernate
- JUnit
- Maven
- Proves avançades amb Mockito
- Llibreries essencials de l'ecosistema
