Quando nel 2000 iniziai a scrivere la prima versione di Java Mattone dopo Mattone, non immaginavo che quel testo avrebbe continuato a circolare per tanto tempo. Lo misi gratuitamente in rete e, in pochi giorni, cominciò a passare da un programmatore all'altro. Non c'era un piano di distribuzione: c'erano persone che lo trovavano utile e lo consigliavano. Anni dopo ho continuato a riconoscerlo sulle scrivanie, spesso accanto a libri e strumenti arrivati molto più tardi. Per chi aveva iniziato mettendo insieme pagine per spiegare Java, era una sorpresa difficile da dimenticare.
Poi arrivò l'edizione Hoepli. Era il 2002 e il libro fu presentato allo SMAU. Le copie disponibili allo stand andarono esaurite in pochi giorni. Ricordo ancora l'emozione di vederlo nella vetrina di una libreria universitaria: un libro che fino a poco prima esisteva soltanto nei miei file era diventato un oggetto che qualcun altro poteva prendere in mano, leggere e magari usare per risolvere un problema. Quella vetrina non era soltanto un traguardo personale. Mi diceva che il metodo con cui avevo provato a costruire le spiegazioni, un mattone dopo l'altro, aveva raggiunto lettori che non conoscevo.

Devo molto a questo libro. Mi ha aperto porte professionali e mi ha permesso di conoscere persone da cui ho imparato. È un debito che non si esaurisce ringraziando i lettori: chiede anche di non lasciare loro fra le mani un'immagine ferma del linguaggio. Quando incontrai Java nel 1996 molte cose che ora diamo per normali non c'erano ancora. Nel frattempo il linguaggio, le librerie e la piattaforma sono cambiati; alcune idee iniziali sono diventate abitudini, altre sono state corrette o abbandonate. È cambiato anche il modo in cui scriviamo, distribuiamo e controlliamo il software.
Tornare sul libro significa quindi fare due lavori insieme. Il primo è aggiornare ciò che il lettore userà quando aprirà un JDK attuale. Il secondo, più delicato, è conservare il modo in cui queste pagine accompagnano chi legge: una domanda concreta, i passaggi che servono per rispondere, un esempio da seguire e le eccezioni che impediscono di imparare una regola sbagliata. Non voglio che l'aggiornamento cancelli i ricordi, le analogie o la pazienza delle spiegazioni. Se una parte va corretta, la riscriverò mostrando meglio il percorso, non riducendola a un elenco di novità.
Il riferimento tecnico di queste pagine è Java 25. La sigla LTS, associata a questa versione nella roadmap di supporto Oracle, riguarda il ciclo di supporto di una distribuzione: non significa che ogni programma debba aggiornarsi immediatamente, né che tutte le novità del linguaggio siano nate in Java 25. Quando un costrutto è stato introdotto in una versione precedente, lo dirò nel punto in cui l'informazione aiuta davvero a capirlo o a usarlo. Alcuni esempi potranno mostrare una soluzione storica, ma il percorso principale userà strumenti stabili e pertinenti alla versione di riferimento.
Versione Java – Che cosa insegnano le pagine principali. Una funzionalità stabile fa parte del linguaggio o delle API secondo la specifica della versione indicata. Una funzionalità preview è disponibile per la prova, ma può cambiare e richiede opzioni esplicite. Un'API incubator appartiene a moduli sperimentali. Gli ultimi due casi compariranno, quando utili, in approfondimenti separati: nessun lettore dovrà scambiare un esperimento per la sintassi ordinaria di Java 25. La documentazione ufficiale di Java 25 è il riferimento per questa distinzione.
Il libro che non esiste
Ricordo bene la sensazione di cercare una spiegazione precisa e di trovare, invece, frammenti sparsi: una pagina che dava per scontata la terminologia, un esempio che saltava il passaggio decisivo, un libro che ripartiva ogni volta da ciò che conoscevo già. Cercavo il libro che non c'era, quello che mi aiutasse a crescere senza obbligarmi a leggere tutto nello stesso modo. Con il tempo ho capito anche un'altra cosa: conoscere la sintassi di Java non basta, da sola, a scrivere software comprensibile e affidabile.
Chi ha già perso un pomeriggio per una sola informazione sa che cosa intendo. Il problema non è sempre la mancanza di documentazione: spesso è la sua frammentazione. Trovi la firma di un metodo, ma non il motivo per cui dovresti usarlo; trovi un esempio che funziona, ma non il caso in cui fallisce; trovi una spiegazione completa, ma se conosci già i primi passaggi devi attraversarla tutta per arrivare alla domanda che ti interessa. Il «libro che non esiste» era il desiderio di tenere insieme profondità e libertà di percorso, senza chiedere a ogni lettore di fingere di partire dallo stesso punto.
Questo libro prova a rispondere a entrambe le esigenze. Chi comincia può partire dai concetti più semplici, mettere alla prova un esempio e tornare sul punto che non è ancora chiaro. Chi programma già può raggiungere rapidamente gli argomenti che gli mancano o confrontare le proprie abitudini con strumenti più recenti. Le sezioni avanzate sono riconoscibili; rimandarle è una scelta normale, non una sconfitta. Sono i mattoni da aggiungere quando la struttura sottostante è pronta.
Non ho scritto due libri separati, uno per principianti e uno per esperti. Ho cercato un percorso in cui chi inizia non venga abbandonato al primo termine nuovo e chi ha esperienza possa saltare una base nota senza perdere il filo. Per questo un approfondimento può essere lasciato da parte e ripreso più tardi, ma la spiegazione principale non deve dipendere da ciò che vi è nascosto. Allo stesso modo, una novità di Java non sarà presentata come un trucco da copiare: vedremo quale problema risolve, come cambia un esempio che già comprendiamo e quali limiti restano.
Concetto chiave – Un mattone alla volta. Un nuovo termine viene spiegato quando serve, il codice viene introdotto prima di essere mostrato e poi letto insieme al risultato. Se un esempio usa un concetto che arriverà più avanti, il rinvio è esplicito. Il lettore non deve indovinare il passaggio mancante.
Il percorso inizia dal modo di pensare un programma e dagli strumenti necessari per eseguirlo. Prosegue con sintassi, oggetti, tipi, API e concorrenza; arriva poi a costruzione, verifica e manutenzione del codice. Le parti più avanzate richiedono qualche fondamento in più, ma non cambiano la promessa iniziale: ogni capitolo deve spiegare perché un problema conta, come affrontarlo e quali limiti ha la soluzione mostrata.
Il percorso si articola in tre parti. Nella prima costruiamo il linguaggio: partiamo dalle istruzioni e arriviamo a classi, oggetti e strumenti con cui Java esprime un modello. Non basta riconoscere una parola chiave; voglio che tu sappia leggere un programma e prevedere che cosa accade quando lo esegui. Per questo, quando una nuova forma sintattica compare, la useremo in un problema piccolo e ne seguiremo il risultato.
Nella seconda parte usiamo le API fondamentali e affrontiamo attività che chiedono più di una classe: raccolte di dati, file, comunicazione e lavoro concorrente. Qui le domande cambiano: che cosa promette un'API, chi possiede una risorsa, che cosa accade se due operazioni procedono insieme? Sono passaggi nei quali un programma può compilare ed essere ancora sbagliato. La parte finale guarda al codice nel tempo: qualità, verifiche, manutenzione, strumenti di progetto e analisi statica. Un esempio didattico che funziona oggi è soltanto il primo passo; vogliamo anche capire se un altro programmatore saprà modificarlo domani.
Il confine fra le parti non è un muro. Una buona abitudine di scrittura può comparire già nel primo programma, e una nozione del linguaggio tornerà quando parleremo di manutenzione. I rimandi servono a indicare dove un tema viene sviluppato per intero, non a lasciare incompleta la spiegazione nel punto in cui ne hai bisogno. Se un argomento richiede strumenti che ancora non conosci, lo segnalerò e torneremo a costruirlo quando avremo i mattoni necessari.
Tre modi di attraversarlo
Se Java è nuovo per te, leggi nell'ordine i capitoli iniziali e prova a riprodurre gli esempi prima di guardare le soluzioni. Fermati sui box Definizione e Nota bene: spesso contengono il dettaglio che evita un errore nelle pagine successive. Puoi lasciare gli Approfondimenti per una seconda lettura.
Se programmi già in Java, usa l'indice e le attività di autoverifica per trovare le sezioni che mettono alla prova ciò che sai. Una spiegazione apparentemente elementare può chiarire una distinzione importante, come quella fra classe e oggetto oppure fra compilazione ed esecuzione. Se un risultato ti sorprende, torna all'esempio e verifica il comportamento prima di proseguire.
Se conosci Java di qualche versione fa, cerca i box Versione Java. Indicano quando una possibilità è diventata stabile e, dove serve, perché il codice mostrato in un vecchio progetto può apparire diverso. L'obiettivo non è trasformare il libro in un elenco di release: è arrivare al modello del linguaggio che userai adesso.
I tre percorsi possono incrociarsi. Un programmatore esperto può aver bisogno di tornare alla distinzione fra riferimento e oggetto; un principiante può essere curioso di un box avanzato e leggerlo senza doverlo padroneggiare subito. La marcatura delle sezioni serve a rendere onesta questa libertà. Quando un capitolo richiama un concetto precedente, il rinvio deve indicare il punto giusto; quando una pagina anticipa qualcosa che verrà spiegato dopo, deve dirlo e offrire nel frattempo abbastanza contesto per proseguire. Saltare una sezione non deve significare accettare una lacuna invisibile.
Buona pratica – Leggere e provare. Gli esempi completi devono avere un file sorgente corrispondente nei materiali del libro. Se trascrivi un frammento, controlla nome del file, nome della classe, package e comando indicato. Un errore di battitura è normale; saper leggere il messaggio del compilatore fa parte dell'apprendimento.
Convenzioni
Le convenzioni non servono a decorare la pagina. Ti dicono che cosa stai guardando e quanto contesto occorre per comprenderlo. La figura seguente riunisce i richiami principali, rendendo riconoscibile la funzione di ogni simbolo.
La legenda affianca al simbolo il livello della sezione, così il significato rimane comprensibile anche in una copia in bianco e nero. Base vuol dire che stiamo costruendo un prerequisito e che conviene leggere con calma anche se l'argomento sembra semplice. Approfondimento segnala un passaggio più impegnativo, utile ma rinviabile senza interrompere il percorso principale.
Questi richiami possono accompagnare sia il titolo di un capitolo sia una sezione interna. Un capitolo può iniziare con nozioni per tutti e contenere più avanti un approfondimento: il segno sul titolo offre una prima indicazione, quello sulla sezione è più preciso. Se manca una marcatura avanzata, il lettore non deve dedurre che l'argomento sia misteriosamente più difficile; il testo seguirà il percorso comune. Le icone non sostituiscono i prerequisiti dichiarati: indicano dove fermarsi, non che cosa si possa conoscere senza spiegazione.
I box Definizione fissano il significato di un termine che useremo ancora. I box Concetto chiave offrono il modello mentale necessario per seguire una sezione. Una Nota può aggiungere contesto o una curiosità senza interrompere il filo del discorso. Il box Versione Java specifica a quale release e a quale stato appartiene una funzionalità. Queste etichette sono scritte per esteso, così restano comprensibili anche se il libro viene letto senza colori o con un dispositivo che non riproduce bene le icone.
Una Nota bene merita attenzione particolare: di solito mette in evidenza un punto su cui è facile costruire un'idea sbagliata. Non è un invito a memorizzare un'eccezione isolata, ma a fermarsi un momento e verificare il modello che abbiamo appena usato. Una Buona pratica è diversa: propone una scelta concreta di scrittura o progettazione e ne spiega la ragione. Una definizione, infine, non è un ornamento tipografico; è il patto sul significato di una parola che ritroverai nelle pagine successive.
I richiami di versione distinguono ciò che appartiene stabilmente a Java 25 da ciò che è in prova. Quando indichiamo la versione in cui una funzione è stata introdotta, il numero non serve a creare una cronologia da imparare a memoria. Serve a capire perché un esempio non compila con un JDK precedente o perché due progetti scritti in anni diversi adottano forme differenti. Se una possibilità è ancora preview o incubator, il box lo dice e riporta le opzioni necessarie per provarla in modo separato dal percorso principale.
Nel testo, parole chiave, comandi, nomi di file, classi e package sono scritti come codice: class, javac, Saluto.java, java.util. Il corsivo distingue il titolo di un'opera o un termine che stiamo introducendo; il grassetto richiama una parola decisiva nella spiegazione. Un programma completo è separato dalla prosa e ha un nome di file preciso. Un frammento, invece, viene dichiarato tale: non devi aspettarti che compili da solo.
Anche le figure che rappresentano classi e interfacce seguono una regola semplice. Una freccia di ereditarietà sale dalla classe più specifica verso quella più generale; una freccia di uso indica chi si serve di un altro oggetto. Quando incontreremo questi rapporti nel capitolo sugli oggetti li interpreteremo insieme. Il colore aiuta a distinguere gli elementi, ma sono etichette e frecce a dare il significato.
Nelle figure tecniche una classe e un'interfaccia hanno forme o etichette distinguibili. «Estende» descrive la relazione fra una sottoclasse e la sua classe base, oppure fra interfacce; «implementa» collega una classe al contratto di un'interfaccia; «usa» dice che un elemento collabora con un altro senza dichiarare una parentela di tipo. Se disegniamo una classe B che estende A, non stiamo dicendo che B contiene fisicamente un oggetto A separato. Se B implementa l'interfaccia A, non stiamo dicendo che eredita lo stato di un'altra classe. E se B usa A, non abbiamo ancora specificato se la relazione è temporanea o conservata in un campo: lo spiegherà il testo vicino alla figura. Colori e orientamento possono variare per esigenze di pagina; nomi e didascalie devono lasciare intatto il significato.
Nota bene – Un esempio non è una prescrizione universale. Nei primi capitoli alcuni programmi sono piccoli di proposito. Servono a isolare un'idea e possono tralasciare controlli, gestione degli errori o organizzazione che sarebbero necessari in un'applicazione reale. Indicherò questi limiti, senza far passare una scorciatoia didattica per una buona pratica generale.
Licenza d'uso
L'edizione 2022 è stata pubblicata con licenza Creative Commons Attribuzione – Non commerciale 4.0 Internazionale. La licenza consente, alle condizioni indicate nel testo ufficiale, di condividere e adattare il materiale attribuendone la paternità, segnalando le modifiche e senza usarlo per scopi commerciali. Altri diritti, come quelli relativi a immagini di terzi, possono richiedere verifiche specifiche. Per conoscere tutte le condizioni e le eccezioni bisogna leggere la licenza, non affidarsi a questa sintesi.
Vale la pena leggere il significato delle condizioni, perché «libro aperto» non vuol dire privo di regole. La licenza dell'edizione precedente permette la condivisione del materiale e la creazione di adattamenti; chi lo fa deve indicare in modo adeguato l'autore, collegare la licenza e rendere riconoscibili le modifiche. L'attribuzione non deve far pensare che l'autore approvi l'uso che altri fanno del testo. La clausola non commerciale limita gli usi rivolti prevalentemente a un vantaggio commerciale o a un compenso. Non si possono poi aggiungere vincoli legali o misure tecnologiche che impediscano agli altri gli usi già permessi dalla licenza.
Ci sono anche limiti che un lettore potrebbe non aspettarsi. Le parti già nel pubblico dominio e gli usi consentiti da eccezioni di legge seguono le proprie regole. La licenza non fornisce garanzie e non risolve automaticamente diritti di terzi: una fotografia, un marchio, l'immagine di una persona o un contributo altrui possono richiedere controlli distinti. Il riepilogo ufficiale Creative Commons aiuta a orientarsi, mentre il testo giuridico collegato da quella pagina contiene le condizioni complete. Per la nuova edizione, testo revisionato e immagini nuove dovranno avere crediti e condizioni espliciti prima della pubblicazione.
Le fonti
La prima fonte di questo libro è stata l'esperienza di programmare, sbagliare, correggere e spiegare. Quando scrivevo l'edizione del 2022 avevo alle spalle ventisei anni di lavoro professionale come programmatore. In quel conto non entravano le ore passate a scrivere assembler sul Commodore 64, né gli esperimenti con C e Pascal sul mio Amiga 2000. Ho lavorato con linguaggi diversi e in ambiti molto diversi fra loro, dal settore militare alle telecomunicazioni fino ai sistemi enterprise. Ciascuno mi ha insegnato qualcosa sul modo in cui un programma viene scritto, usato e poi mantenuto da altri. Ho incontrato Java nel 1996: per usare le parole con cui lo raccontavo allora, fu amore a prima vista.
Il metodo di questo libro è costruire una spiegazione passo dopo passo. Ogni esempio deve aiutare chi legge a riconoscere un problema, seguire una soluzione e metterla alla prova. Una novità di Java acquista significato quando risponde a una necessità concreta e si collega a un’idea già costruita. Per questo non basta ricordare la sintassi: occorre capire che cosa permette di esprimere, quali condizioni richiede e dove smette di essere utile.
La documentazione ufficiale di Java è il riferimento per sintassi, comportamento della piattaforma e API. Le specifiche descrivono il significato dei costrutti del linguaggio e delle operazioni della macchina virtuale; la documentazione delle librerie dice che cosa promette un metodo a chi lo usa. Consultarle non è soltanto un dovere di precisione: aiuta a distinguere ciò che Java garantisce da ciò che sembra accadere in un singolo programma o in una particolare implementazione. Quando incontreremo una regola delicata, proverò prima a renderla comprensibile con un esempio e poi a indicare dove controllarne la formulazione esatta.
Accanto alla documentazione, Java Magazine di Oracle offre spunti, tecniche e riflessioni sul linguaggio; Baeldung è una risorsa pratica per approfondire problemi specifici. Queste letture hanno alimentato il percorso del libro. Un articolo può far nascere la domanda giusta o suggerire una prova; se però stiamo stabilendo che cosa garantisce Java 25, torniamo alla specifica e alle API della versione pertinente. È un modo per usare fonti diverse senza confondere un'idea interessante con una regola del linguaggio.
Infine ci sono le persone. Programmatori amici, colleghi, conoscenti e lettori mi hanno offerto consigli, correzioni e frammenti di codice interessanti. A volte basta una domanda posta nel momento giusto per accorgersi che la spiegazione data per chiara non lo è affatto. Altre volte è un errore segnalato da chi prova davvero un esempio a far migliorare la pagina. Si impara da chiunque abbia qualcosa da dire. Non dimentichiamolo quando una soluzione ci sembra già ovvia.
Ringraziamenti e una piccola scusa
Un grazie particolare va a Catia Niccolai, compagna nella vita e collega nel lavoro. Ha seguito da vicino le varie versioni del libro, sopportando i tempi lunghi e le revisioni che una pagina comporta, e ha riletto le bozze. È un lavoro meno visibile di una copertina, ma chi ha provato a portare a termine un libro sa quanto conti una lettura attenta quando l'autore non riesce più a vedere i propri errori.
Infine, una scusa preventiva per qualche esempio che non somiglia a un problema di lavoro. A volte una situazione piccola e perfino un po' artificiale permette di vedere un meccanismo che un'applicazione reale nasconderebbe fra molti dettagli. Quando accade, il motivo sarà dichiarato. E appena quel meccanismo sarà chiaro, proveremo a usarlo in un contesto più credibile.
Per verificare di aver capito
Prima di iniziare il capitolo successivo, prova a rispondere senza tornare indietro: che differenza c'è fra una sezione Base e un Approfondimento? Dove cercheresti lo stato di una funzionalità sperimentale? Che cosa controlli se un programma copiato dal libro non compila? Le risposte sono nelle convenzioni: riconoscerle adesso ti farà risparmiare tempo durante la lettura.
Per un'attività pratica, prepara una cartella di lavoro per gli esempi e annota la versione del JDK che hai installato eseguendo java --version e javac --version in un terminale. Conserva i due output. L'attività è completata quando entrambi i comandi sono disponibili e riportano una versione coerente; se uno dei due non viene trovato, il capitolo sugli strumenti spiegherà come distinguere un JDK assente da un percorso di esecuzione non configurato.