Proseguiamo la serie dedicata all’evoluzione Java iniziata con il numero precedente in cui si è illustrata quella che può essere considerata la preistoria del linguaggio, quando Java non si chiamava neanche Java. In questo numero presentiamo una disamina delle varie versioni che si sono succedute fino al giorno d‘oggi, inclusa la futura Java SE 8 e uno sguardo a possibili aree di interesse di Java SE 9, evidenziando le principali feature introdotte. Si tratta di un lungo viaggio di circa un ventennio tra le tecnologie Java che ne hanno caratterizzato l’evoluzione.
Introduzione
Come visto nell’articolo precedente (cfr. [1]) la (prei)storia di Java inizia nel gennaio del 1991 con il progetto Stealth (in gergo, sono indicati con il nome “Stealth” progetti creati dalle aziende in segreto per evitare la “fuoriuscita” di informazioni su stato, mission, membri, etc. del progetto). Tuttavia bisogna attendere oltre quattro anni affinche’ Java venga catapultato alla ribalta della comunità OO. Dopo una serie di strategie, che per diversi motivi, non riescono a ottenere i risultati sperati, nel giugno/luglio 1994, dopo tre giorni di brainstorming che videro la partecipazione di John Gage, direttore del Science for Sun Microsystem, Gosling, Joy, Naughton, Wayne Rosing ed Eric Schmidt, viene finalmente presa la decisione che risulterà vincente: posizionare Java come piattaforma di riferimento per il World Wide Web. Da allora molte versioni si sono susseguite, fino alla versione Java SE 7 rilasciata nel luglio 2011, tuttavia la filosofia iniziale sembrerebbe essere sopravvissuta nel tempo.
Java 1.0.2
Le prime versioni di Java iniziarono ad essere disponibili intorno al 1994 (Java 1.0a fu resa disponibile per il download a partire dal giugno 1994). Tuttavia per la prima versione stabile fu necessario attendere fino al 23 gennaio del 1996 (cfr. [2]), quando fu resa disponibile la versione Java 1.0.2 completa del Java Development Kit (JDK, kit per lo sviluppo di applicazioni Java) per i soli ambienti Windows e Solaris. Da notare che a quei tempi, il JDK includeva tutte le varie componenti, incluso l’ambiente di run-time (JRE, Java Runtime Environmnet) apparso come entità a se’ stante solo a partire dalla versione 1.1. Oltre alle feature ereditate dal progenitore Oak (cfr. [1]), Java 1.0.2 includeva due package allora particolarmente apprezzati.
AWT
Il primo package importante era una prima versione, probabilmente disegnata molto rapidamente, di Abstract Window Toolkit (AWT, toolkit astratto di GUI a finestre) utilizzabile per la creazione di interfacce utente grafiche portabili. Il nome abstract deriva dal fatto che il package java.awt.peer si occupa di realizzare il collegamento tra le componenti grafiche di questo framework e i correspondenti moduli presenti nella piattaforma di esecuzione (runtime). Sebbene l’idea base di AWT avesse diversi vantaggi, finiva per minare alla base la filosofia “core” di Java: Write Once Run Anyware (WORA, “implementa una volta ed esegui su ogni piattaforma”). Infatti, poiche’ le GUI AWT una volta in esecuzione sulle varie piattaforme sono a tutti gli effetti native, ne segue che le interfacce utente presentano un comportamento che può variare, a volte anche significativamente, a seconda della piattaforma di esecuzione. Ne segue che il package AWT è, per certi versi, platform specific.
Applet
La definizione del concetto delle Applet consisteva a particolari applicazioni Java di venire scaricate automaticamente da siti Internet e di funzionare in browser commerciali dotati della Java Virtual Machine (JVM, macchina virtuale Java).
Da un punto di vista “strutturale”, Java 1 era formato dai seguenti otto package (sì solo 8!) tuttora disponibili.
java.lang
Package fondamentale di Java che conteneva classi fondamentali come numeri (Byte, Double, Long, etc), String, Runtime, Thread, etc. Si tratta del package fondamentale che viene sempre incluso di default in ogni classe Java.
java.io
Package che forniva le classi per gestire stream di input e di output per leggere e scrivere dati su file, stringhe ed altre fonti.
java.util
Conteneva classi di utilità varie, comprese le strutture di dati generiche (Vector, Hastable, etc.), insiemi di bit, ora, data, manipolazione di stringhe, la generazione di numeri casuali, proprietà di sistema, la notifica (Observer, Observable, etc) ed enumerazione di strutture di dati (come l’interfaccia Enumeration).
java.net
Forniva classi per il supporto del networking, inclusi Universal Resource Locator (URL, localizzatore universale di risorse), socket Transmission Control Protocol (TCP, protocollo di controllo di trasmissione) e User Datagram Protocol (UDP, protocollo datagrammi utente), indirizzi Internet Protocol (IP, protocollo Internet), e un convertitore di binario/test.
java.awt
Includeva un insieme integrato di classi per gestire i componenti dell’interfaccia utente. Vi erano le classi per rappresentare finestre, finestre di dialogo, pulsanti, caselle di controllo, elenchi, menu, barre di scorrimento, e campi di testo.
java.awt.image
Forniva le classi per la gestione di immagini, compresi i modelli di colore, ritaglio, filtro colore, e l’impostazione dei valori dei pixel e PixelGrabber.
java.awt.peer
Package di collegamento tra le componenti AWT alle correspondenti componenti specifiche della piattaforma di esecuzione (esempio: widget Motif e controlli Microsoft Windows).
java.applet
Consentiva la creazione di applet tramite la classe Applet. Prevedeva inoltre diverse interfacce necessarie a collegare le Applet al corrispondente documento e alle risorse per le riproduzioni audio.
Questa release includeva (figura 1) 8 package e 212 classi. Da notare che a quei tempi le 212 classi di Java, organizzate in otto package, sembravano un ricco supporto di librerie.
Figura 1 – L’evoluzione di Java attraverso le differenti versioni, dal punto di vista del numero di package e classi. Si può notare il grande incremento nel corso degli anni.
Sebbene la Java 1.0.2 presentasse molte interessanti potenzialità, si trattava comunque di una prima versione ancora acerba. Il package AWT soffriva di molte limitazioni a partire dal fatto che violava la filosofia base di Java (WORA, Write Once Run Anyware). Inoltre, il controllo della user interface era limitato e le corrispondenti interfacce peccavano di mancanza di stabilità; non c’era il supporto per la connessione a database (JDBC acronimo non ufficiale per Java DataBase Connectivity, connettività al database di Java: per essere precisi ne esisteva una versione embrionale esterna), non erano ancora state incluse le feature dell’internaziolizzazione, della localizzazione, non esisteva il framework Remote Method Invocation (RMI, invocazione di metodo remoto) ne’ la serializzazione, era assente il costrutto delle inner class, il Just-In-Time (JIT) era più un’idea che una vera implementazione e così via.
Java 1.1
La successiva major release, Java 1.1, fu rilasciata il 19 febbraio 1997 (cfr. [3]). Secondo molti programmatori questa era la prima vera e propria versione di Java utilizzabile professionalmente per la costruzione di sistemi complessi. La sua formulazione fu il risultato di una estesa rivisitazione del linguaggio, di cui le feature principali includevano molti aspetti. Vediamoli di seguito.
AWT rinnovato
Ci fu una completa rivisitazione dei package AWT. La parte del modello degli eventi (event model) fu interamente reingegnerizzata.
Classi annidate
L’aggiunta delle classi annidate (nested classes/inner class) rappresentò un importante passo avanti. Si tratta di costrutti fondamentali per la corretta implementazioni di framework/classi di utilità come le collezioni. Per esempio, l’utilizzatissima classe java.util.HashMap (introdotta con Java 1.2) dichiara una serie di classi annidate, di cui le più importanti sono: Entry (utilizzata per incapsulare gli oggetti memorizzati nella map in modo da poter costruire delle linked list), HashIterator (necessaria per implementare la funzionalità di iterazione degli elementi della mappa) e gli altri iterator (ValueIterator, KeyIterator, EntryIterator), KeySet (serve per costruire una view dell’insieme delle chiavi presenti nella mappa), Values (serve per costruire una view dell’insieme delle chiavi presenti nella mappa) ed EntrySet (serve per costruire una view delle Entry presenti nella mappa). Le tipologie di classi annidate aggiunte furono quelle riportate di seguito.
- static member: come suggerito dal nome, si tratta di membri statici che come tali ubbidiscono alle corrispondenti regole: le istanze possono accedere agli altri membri statici della classe contenente (o di livello superiore), qualora la visibilità lo conceda può essere instanziata senza necessità di instanziare la classe contenente, e così via.
- “standard” member: si tratta di classi annidate non statiche e che quindi seguono le regole che si applicano a tutti gli elementi membri della classe: le istanze della classi annidate hanno accesso a tutti i membri della classe contenente o di livello superiore e possono accedere ai membri dichiarati privati.
- local: si tratta di classi dichiarate all’intero di un blocco di codice e pertanto sono “visibili” solo all’interno di tale blocco (per questo sono definite locali), ne’ più ne’ meno di una qualsiasi variabile definita in un blocco.
- anonime: questa tipologia di classi locali sono definite anonime in quanto, come suggerito dal nome, sono dichiarate senza nome. Le classi locali e anonime sono tipicamente utilizzate per definire dei callback utili nella implementazione di codice di gestione degli eventi generati nella GUI.
JavaBeans
La definizione dei JavaBean ([4]). Da notare che la definizione della JavaBeans API (java.beans package) ha influenzato tutta una serie di package appartenenti al core Java, come per esempio reflection e serializzazione.
JDBC
Altro passo importante fu l’introduzione del Java DataBase Connectivity (JDBC cfr. [5]). Nella versione 1.0 esisteva una versione embrionale del package JDBC come libreria esterna, mentre con la versione 1.1. diventò parte integrante del core java (java.sql). In breve, JDBC è l’architettura e la corrispondente API che permettono alle applicazioni Java di interagire con i DBMS per eseguire comandi SQL. L’architettura JDBC è stata disegnata prendendo spunto da Microsoft Open Database Connectivity (ODBC, connettività aperta al database) utilizzato per l’accesso e la gestione di database con la differenza che mentre JDBC è Java specifico, ODBC è indipendente dai specifici linguaggi di programmazione. Al fine di mantenere Java indipendente dalle specifiche piattaforme (incluse quelle dei DB), la strategia utilizzata prevede che l’API JDBC rappresenti uno strato di indirezione verso gli specifici database. Tale astrazione deve poi essere colmata, a run-time, da appositi driver (jdbc driver) che effettuano il bridge con le specifiche piattaforme. In questo modo le applicazioni Java posso restare indipendenti dalla piattaforma fino al tempo di esecuzione e lo stesso codice (con qualche accorgimento) può funzionare efficacemente su diverse piattaforme. Per la versione 1.1 era stato previsto un semplice brigde con gli esistenti driver ODBC: si trattatava di un’ottima strategia per poter permettere alle applicazioni Java di iniziare da subito a interagire con DBMS con minimo sforzo sfruttando il preesistente insieme driver ODBC. Ma successivamente gli architetti Java definirono quattro tipologie di driver
- type 1 JDBC-ODBC bridge: si tratta di un bridge verso i driver di tipo ODBC (quindi astrazione su astrazione).
- type 2 Native API driver: driver nativo tra l’API JDBC ed l’API del DBMS specifico
- type 3 Network-Protocol driver: protocollo di rete tra l’API JDBC ed un middleware in grado di fornire un livello di indirezione per diversi DBMS.
- type 4 Native Protocol driver: protocollo nativo tra JDBC e protocollo del DBMS (in questo caso si aggira anche l’API del DB).
Remote Method Invocation
Va notata anche la definizione di una prima versione del framework RMI mancante del supporto del protocollo IIOP. Si tratta di un meccanismo che permette di eseguire un metodo esposto da un oggetto remoto (Remote Method Invocation) tipicamente presente in una diversa JVM. La versione iniziale, denominata Java Remote Method Protocol (JRMP, protocollo Java specifico di invocazione dei metodi remoti), era specifica Java (non IIOP). RMI è l’equivalente Java di CORBA. Tuttavia, sebbene entrambi rappresentino un meccanismo OO per eseguire Remote Prodecure Call (RPC, chiamate a procedure remote), esistono importanti differenze: CORBA è uno standard indipendente dalla piattaforma (Java ha parzialmente colmato questa lacuna con l’introduzione di RMI over IIOP grazie a un progetto congiunto con IBM disponibile dalla versione 2); CORBA include diversi meccanismi standard come quello per i Transaction Processing monitor (TP monitor, monitor per l’elaborazione di transazioni) non presenti in RMI; RMI non necessita di ORB (Object Request Borker, broker per la richiesta di oggetti) forniti da terze parti tipicamente a costi elevati; RMI permette il caricamento dinamico del codice non permesso in CORBA; RMI nativo non richiede di definire le interfacce in un altro linguaggio, CORBA invece richiede che le interfacce siano definite con IDL (Interface Definition Language, linguaggio per la definizione di interfacce).
Reflection
L’introduzione di una versione iniziale della reflection basata essenzialmente sull’introspezione (introspection). In particolare, queste feature permettono di ottenere informazioni relative alle classi a run-time come costruttori, metodi e attributi. L’introspection (e la reflection più in generale) sono un meccanismo fondamentale, tra l’altro, per poter implementare architetture basate su plug-in.
JNI
Ultimo aspetto da non trascurare fu l’introduzione dell’interfaccia Java per il codice nativo (Java Native Interface, JNI). Si tratta di una potente funzionalità della piattaforma Java che permette alle applicazioni di incorporare codice nativo scritto in linguaggi di programmazione come C e C++ e vice versa. La JNI consente ai programmatori di sfruttare la potenza della piattaforma Java, senza dover per questo rinunciare agli investimenti passati su codice legacy. Poiche’ JNI è parte della piattaforma Java, i programmatori possono risolvere i problemi di interoperabilità, una volta, ed essere sicuri che tali soluzioni funzionino in tutte le implementazioni della piattaforma Java. Sebbene JNI sia stato introdotto con questa release, Java 1.1 manteneva chiamate native precedenti, che invece verranno soppiantate da soluzioni JNI solo con la version Java 2.
1.1.x: minor releases
La versione iniziale del JDK 1.1 fu rilasciata nel febbraio 1997 (giusto in tempo per la JavaOne conference di aprile), e ad essa seguirono tutta una serie di progetti e nuove “minor release” per oltre 2 anni fino all’aprile 1999 quando fu rilasciata la versione JDK 1.1.8 denominata Chelsea (quartiere presente sia a New York, sia a Londra). Da notare che nel frattempo era intanto stata rilasciata la versione Java 2 (dicembre 1998). In particolare, si assistette alla seguente progressione di progetti:
- settembre 1997: JDK 1.1.4 (Sparkler, “stella filante”)
- dicembre 1997: JDK 1.1.5 (Pumpkin, “zucca”)
- aprile 1998: JDK 1.1.6 (Abigail, personaggio femminile della Bibbia)
- settembre 1998: JDK 1.1.7 (Brutos, Bruto figlio adottivo nonche’ uno degli assassini di Giulio Cesare)
- aprile: JDK 1.1.8 (Chelsea, nome di quartiere presente sia a New York, sia in quel di Londra)
Queste versioni si resero necessarie per sistemare inevitabili bug, per continuare a migliorare le prestazioni, il livello di sicurezza, rivistare alcune librerie I/O, e così via.
Va notato come in questo processo, a partire dalla 1.1, si verificò una triplicazione dei package e delle classi (figura 1). In particolare, 23 package e 503 classi.
Java 2/J2SE 1.2
L’8 dicembre del 1998 fu rilasciata la nuova major release di Java, che per sopresa di molti fu inizialmente battezzata Java 2 (la stragrande maggioranza delle persone si aspettava la versione Java 1.2). Si trattò di un nome abbastanza infelice che finì per creare non poca confusione (vedremo che questa costante della denominazione tornerà altre volte), al punto che “Java 2” fu cambiato retrospettivamente nella sigla “J2” facendo nascere J2SE (Java 2 Platform, Standard Edition) ma in versione 1.2. Questa nomenclatura è stata poi mantenuta fino a Java 6 in cui si assiste al nuovo cambiamento. Si decise di sostituire la dicitura JDK con J2 per poter distinguere le tre piattaforme base:
- edizione standard, J2SE
- edizione enterprise, J2EE (Java 2 Platform, Enterprise Edition)
- edizione micro, J2ME (Java 2 Platform, Micro Edition)
Le feature principali di Java 2, o meglio, J2SE 1.2 includevano (cfr. [6]) numerose novità.
JCF
Fu operata una completa rielaborazione del framework delle collezioni JCF (Java Collections Framework). Si tratta di un insieme di classi e interfacce che implementano strutture dati di utilizzo frequente come per esempio array di dimensioni variabili e mappe. Le versioni precedenti di Java già includevano concetti equivalenti (per esempio Vector e HashMap), tuttavia queste non erano organizzate in un framework (non si basavano su un insieme di interfacce standard e la loro “estensione” non era immediata). Inoltre erano state disegnare per funzionare in ambiente concorrente con una policy di sincronizzazione coarse-grained e restrittiva. La logica consequenza è che tutte le applicazioni finivano per pagare il costo della sincronizzazione anche per utilizzi che non lo richiedevano. Il JCF è stato fondato principalmente sul lavoro di Doug Lea, Collection package (cfr. [7]), e dal gruppo ObjectSpace della Stanford University Generic Collection Library (JGL, cfr. [8]).
Swing
Java 2 vide l’inclusione dell’API grafica Swing. La versione primordiale delle Swing si deve alle Internet Foundation Classes (IFC, classi fondamentali internet) per Java sviluppate originariamente dalla Netscape Communications Corporation e rilasciate per la prima volta nel dicembre del 1996. Nell’Aprile dell’anno seguente (cfr. [9]) Sun Microsystems and Netscape Communications Corporation iniziarono a lavorare al progetto di integrazione delle IFC nelle Java Foundation Classes (attualmente le JFC includono AWT, Swing e Java 2D). Le IFC furono successivamente ribattezzate in Swing. Come evidenziato precedentemente, l’AWT presentava una serie di limitazioni e per molti si trattava essenzialmente di un wrapper molto sottile delle capacità grafiche native offerte delle varie piattaforme. Ciò, tra l’altro, richiedeva che gli sviluppatori avessero una buona consapevolezza delle differenze di comportamento della GUI nelle varie piattaforme al fine di prendere le dovute contromisure per far sì che le interfacce utente fossero veramente portatili. A partire dalle IFC si cercò di realizzare un framework grafico veramente platform-independent. Tra le varie caratteristiche introdotte con Swing, spiccava la possibilità di avere widget dal look and feel “pluggable” che gli consentiva di mimare il comportamento delle interfacce utente basate su componenti native delle varie piattaforme. Inoltre, il set dei widget grafici a disposizione (completamente scritto in Java secondo una ben definita architettura modulare), fu largamente esteso e gli stessi furono resi più potenti e flessibili. Da notare che per via della scelta architetturale completamente basata su implementazione Java, i widget Swing tendevano a essere meno efficienti dei corrispondenti AWT.
RMI-IIOP e supporto IDL
Introduzione del supporto IDL e di RMI-IIOP. Fu pertanto introdotta la capacità di Java di invocare e di esporre servizi compatibili CORBA, permettendo un’interoperabilità run-time con componenti implementati con diversi linguaggi di programmazione. Si trattò di fondere insieme le feature di Java RMI con quella di CORBA. Per questo lavoro la Sun Microsystem si avvalse della collaborazione dell’IBM.
strictfp
Fu introdotta la parola chiave strictfp (strict floating point, aritmetica a virgola mobile rigida). L’aritmetica dei floating point è definita dallo standard IEEE 754 e le versioni di Java precedenti alla 2 ne seguivano ridigamente le regole anche per la memorizzazione dei risultati intermedi dei calcoli in virgola mobile. Tale rigidità è stata attenuata a partire dalla versione Java 2 in cui la memorizzare dei risultati intermedi avviene sfruttando un formato esteso normalmente fornito direttamente dalle CPU. Ciò genera il vantaggio di ridurre errori di calcolo dovuti a frequenti arrotondamenti, overflow e underflow. Tuttavia, il prezzo da pagare è che si introduceva la possibilità da parte di diverse piattaforme di produrre risultati leggermente diversi per la valutazione di calcoli in floating point non banali. strictfp può essere utilizzata sia per classi, interfacce e metodi non astratti.
JIT Compilation
La JVM (Java Virtual Machine) fu equipaggiata per la prima volta con un componente Just In Time (JIT compilation, compilazione appena in tempo). Si tratta di una strategia atta ad acelerare le performance a tempo di esecuzione del bytecode. Ciò è ottenuto attraverso un’analisi basata su due direttive principali:
- compilazione di blocchi di codice in anticipo rispetto alla reale richiesta;
- esecuzione di ottimizzazioni basati su pattern pre-definiti sul bytecode stesso. Alcuni semplici esempi di ottimizzazioni sono lo spostamento della dichiarazione di variabili al di fuori dei cicli e l’ottimizzazione delle operazioni su stringhe evitando la generazione di oggetti stringa intermedi.
Java Plug-in
L’introduzione dell’architettura Java Plug-in (cfr. [10]). Java Plug-in estende le funzionalità dei browser permettendo ad Applet o JavaBeans di poter essere eseguiti dal Java 2 Runtime Environment (JRE) invece che dall’ambiente di runtime Java fornito con il browser. Java Plug-in fa parte della JRE di Sun e viene installato con il JRE.
Con questa release i package e le classi subirono un’ulteriore, sostanzioso incremento (figura 1): 59 package e 1520 classi.
J2SE 1.3
La versione J2SE 1.3 fu rilasciata l’8 maggio 2000 con il nome di Kestrel (si tratta di un piccolo falco, comunemente noto come Gheppio). Non si tratta di una versione particolarmente rivoluzionaria, tuttavia introdusse alcune significative caratteristiche, tra le quali le più importanti sono sicuramente (cfr. [11]) quelle che vediamo di seguito.
JNDI
Java Naming and Directory Interface (JNDI, interfaccia Java per i servizi di denominazione e directory) è una API Java disegnata per integrare servizi di naming e directory. Si tratta di software che permettono di mermorizzare e organizzare informazioni, tipicamente secondo un ordine strettamente gerarchico, e di accedervi per mezzo di una chiave tipicamente mnemonica. Le informazioni memorizzate nei directory service sono coppie (chiave, oggetto). L’esempio classico è il Domain Name System (DNS, sistema dei nomi di dominio): si tratta di un sistema distribuito di nomi organizzati gerarchicamente dei computer, servizi e più in generale delle risorse collegate ad Internet o a una rete privata che essenzialmente permette di reperire gli indirizzi IP di tali risorse a partire da un nome mnemonico. Lo stesso avviene in Java EE dove JNDI permette di reperire (look-up) l’indirizzo di bean e di EJB a partire da un loro nome mnemonico. Le specifiche JNDI rispettano la classica strategia Java che consiste nel definire una API unificata e indipendente dalle varie implementazioni e piattaforme di esecuzione. Come al solito, il bridge tra il livello di astrazione Java e l’implementazione specifica deve essere colmato a run-time per mezzo di appositi driver, identificati con il nome di Service Provider Interface (SPI, interfaccia del fornitore del servizio). JNDI è utilizzata per accedere a risorse di di tipo Lightweight Directory Access Protocol (LDAP), CORBA Common Object Services (COS), RMI Registry, etc. La prima versione delle specifiche JNDI fu rilasciata dalla Sun nel Marzo del 1997 e dopo qualche tempo iniziarono a circolare le prime versioni. Tuttavia, solo con J2SE 1.3, JNDI viene integrata nel core Java.
Java Sound
L’API del suono Java è una API di basso livello che permette alle applicazioni Java di controllare l’input e l’output di media audio, incluso il formato Musical Instrument Digital Interface (MIDI, interaccia digitale dei strumenti musicali). La API Java Sound fornisce un controllo esplicito delle feature normalmente richieste per l’input e l’output dei media audio, in un framework che promuove l’estensibilità e la flessibilità.
JPDA
Java Platform Debugger Architecture (JPDA, architettura della piattaforma di debugging Java) è una collezione di API che permettono appunto di eseguire il debug del codice Java. In particolare, questa architettura include le seguenti API:
- Java Debugger Interface (JDI, interfaccia del debugger Java) che definisce un’interfaccia di alto livello semplice da utilizzare per l’implementazione di strumenti per il debugger remoto.
- Java Virtual Machine Tools Interface (JVMTI, interfaccia per i tools della JVM): si tratta di un’interfaccia nativa che permette di eseguire l’ispezione dello stato e del controllo di esecuzione dell’applicazione in corso di esecuzione sulla JVM.
- Java Virtual Machine Debug Interface (JVMDI e rinominata in JVM TI J2SE 5.0 e poi rimossa con Java SE 6).
- Java Debug Wire Protocol (JDWP, protocollo di rete per il degub Java) che definisce il protocollo di comunicazione tra l’applicazione oggetto di debug e l’applicazione debugger.
HotSpot
Si tratta di una JVM gestita e distribuita da Oracle Corporation. Le sue feature più interessanti ai tempi erano la presenza del compilatore Just-In-Time e un ottimizzatore adattivo (si tratta di una componente che esegue compilazioni dinamiche di porzioni di programma in funzione del corrente profilo di esecuzione) disegnato per migliorare le performance. La JVM HotSpot fu rilasciata per la prima volta nell’aprile del 1999. Si tratta di una tecnologia sviluppata originariamente da una start-up chiamata Longview Technologies LLC (cfr. [12]). Questa azienda fu poi acquisita dalla Sun Microsystem e HotSpot fu aggiunta come add-on nella versione Java 2 e divenne la JVM di default Sun a partire dalla versione 1.3. Il nome è dovuto al fatto che mentre esegue il byte code, la JVM analizza continuamente le performance del programma per individuarne i punti caldi (hot spots) eseguiti più frequente o ripetutamente che, come tali, costituiscono i target ideali per possibili ottimizzazioni.
Synthetic proxy classes / dynamic proxy
I proxy sintetici, successivamente renominati in proxy dinamici, (dynamic proxy) sono stati introdotti in Java 1.3 tramite l’introduzione della classe Proxy (java.lang.reflect.Proxy) e dell’interfaccia InvocationHandler (java.lang.reflect.InvocationHandler) al package java.lang.reflect. Questa coppia consente la creazione di “oggetti proxy sintetici”: una classe dynamic proxy è una classe che implementa un elenco di interfacce specificate a run-time quando la classe viene creata. Ogni istanza del proxy è associata ad un oggetto di gestione delle invocazioni (implementa l’interfaccia InvocationHandler). Una chiamata di un metodo di un’istanza proxy attraverso una delle sue interfacce proxy viene passata al metodo invoke del gestore di invocazione dell’istanza, passando all’istanza proxy tutti le informazioni della chiamata. Il gestore dell’invocazione esegue le previste elaborazioni e a seconda dei casi il risultato viene restituito come risultato della chiamata del metodo sull’istanza di proxy. Si tratta di un importante meccanismo che consente di intercettare le chiamate a specifici metodi in modo da poter interporre un comportamento aggiuntivo tra il chiamante di un oggetto e l’oggetto stesso. Dal punto di vista del chiamante, un proxy non è diverso dalla classe reale che incapsula: implementa le stesse interfacce e segue tutte le regole e le convenzioni previste della classe reale. Si tratta di un ottimo meccanismo che permette di implementare aspetti importanti per l’applicazione, ma ortogonali al compito principale delle singole classi (AOP, Aspect-Oriented Programming). Invece di programmare questa logica in tutta l’applicazione, con proxy dinamici è possibile implementarli in un framework specifico. I proxy dinamici sono alla base di molti importanti framework, tra cui Spring.
Aggiornamento di RMI-IIOP
L’aggiornamento di RMI-IIOP fu realizzato al fine di supportare alcune feature optionali di CORBA.
Questa release portò un aumento più graduale del codice della piattaforma Java (figura 1), in particolare: 76 package e 1842 classi.
J2SE 1.4 e la Java Community
La versione J2SE 1.4 fu rilasciata il 6 febbraio del 2002 con il nome di Merlin (anche questo è un piccolo falco, lo Smeriglio, nome scientifico Falco columbarius, per via della sua preda preferita: i colombi). Si tratta di una versione che ha fatto la storia di Java in quanto è stata la prima major release sviluppata attraverso il Java Community Process (JCP, processo della Java Community). Si tratta di un’organizzazione creata dalla Sun nel 1998 dietro la crescente pressione da parte di importanti stakeholder preoccupati per uno sviluppo monopolistico di una tecnologia come Java considerata sempre più strategica per le varie imprese. Il JCP permette alla parti interessate di lavorare allo sviluppo delle specifiche standard Java e quindi di collaborare alla definizione del futuro della tecnologia Java. J2SE 1.4 è parte della Java Specification Request 59 (JSR, richiesta di specificazione Java, cfr. [13]). I JSR sono i documenti formali che descrivono le proposte di modifiche e relativa evoluzione. Sebbene tutti possano partecipare alla JCP, le decisioni finali spettano al comitato esecutivo (JCP Executive Committee), che, a detta di molti, era di fatto un feudo controllato da Sun Microsystem prima e, successivamente, da Oracle. Non a caso, Apache Software Foundation decise di dimettersi dal tale comitato (9 dicembre 2010, cfr. [14]) proprio per via di questa posizione della Sun.
La J2SE versione 1.4 introdusse una serie di cambiamenti: vediamo i più significativi.
Assert
Venne introdotta la struttura assert (JSR 41, cfr. [15]). Si tratta di un costrutto utilizzato per specificare delle assunzioni del programmatore in merito a determinate condizioni che devono essere soddisfatte in specifici punti del codice. L’obiettivo consiste nel migliorare la robustezza dei programmi. Ogni assert contiene espressioni booleane che si crede debbano essere soddisfatte durante l’esecuzione: in caso contrario il sistema genera un errore runtime incluso nella classe java.lang.AssertionError. Da notare che AssertionError specializza la classe Error la quale indica errori seri che, secondo le direttive, il codice non dovrebbe tentare di intercettare. Pertanto questa feature andrebbe utilizzata soprattutto durante lo sviluppo, mentre il suo utilizzo andrebbe ponderato in fase di rilascio; per esempio, non è ideale per verificare i parametri di metodi pubblici. Il costrutto assert era stato già pensato da Gosling ai tempi di Oak, ma alla fine è stato introdotto solo con la versione J2SE 1.4. Più in generale, assert è utile per verificare pre-conditions (prerequisiti), post-conditions (post) e condizioni invarianti;
Regular expression
La versione 1.4 vide l’integrazione delle regular expression. Il meccanismo delle espressioni regolari permette di descrivere un insieme di stringhe in base alle caratteristiche comuni condivise da ogni stringa dell’insieme. Questo meccanismo si presta a essere utilizzato per cercare, modificare e manipolare del testo. Le espressioni regolari sono definite dall’API java.util.regex che include i tre costrutti fondamentali: java.util.regex.Pattern, java.util.regex.Matcher, java.util.regex.PatternSyntaxException). Il mondo delle espressioni regolari prevede diverse approcci e sintassi, come per esempio grep, Perl, Tcl, Python, PHP, e awk. Per quanto attiene a Java, si è deciso di seguire l’approccio Perl.
NIO
Fu introdotta una nuova API di Input/Output (New Input/Output, NIO) specificata per mezzo della JSR51 (cfr. [16]). L’API NIO venne introdotta per sopperire ad alcune lacune presenti nel package I/O originale di Java (java.io). Sebbene per molti programmatori l’API Java NIO sia stata introdotta essenzialmente per disporre di operazioni di I/O non bloccanti, in realtà è stato fatto molto di più a partire dall’introduzione di un nuovo elegante disegno. Le principali feature introdotte sono: possibilità di eseguire il mapping in memoria dei files; operazioni orientate ai blocchi che sfruttano i servizi messi a disposizione dalle piattaforme di esecuzione al posto del tradizione flusso di byte; operazioni di I/O asyncrone e quindi non bloccanti e lock dei file o di opportune sezioni. Sebbene il package java.nio includa molti elementi interessanti, il framework è basato su tre concetti fondamentali: buffer, che come atteso sono contenitori di dati; charset, con i corrispondenti decoder ed encoder, eseguono la traduzione tra byte e caratteri Unicode; channels ossia canali di vario tipo che rappresentano le connessioni con dispositivi di vario tipo in grado di eseguire operazioni I/O; selectors (selettori), che insieme ai canali permettono di definire oeprazioni multiplex e non-bloccanti. Java SE7 ha recentemente rilasciata la seconda versione di questa API, cioè NIO2.
Concatenamento di eccezioni
La possibilità di creare catene di eccezioni (exception chaining) permette di rilanciare una specifica eccezione dopo averla incapsulata in una nuova eccezione. Si tratta di un ottimo meccanismo per fornire eccezioni al livello di astrazione adatto per uno specifico strato dell’architettura senza perdere informazioni di un problema di maggiore dettaglio. Questa feature ha richiesto la modifica della classe java.lang.Throwable.
IPv6
Supporto per Internet Protocol versione 6, IPv6. Si tratta di un aggiornamento del formato dell’indirizzo dei pacchetti di reti resosi necessario per fronteggiare il previsto esaurimento delle configurazioni specificate dalla versione precedente (da IPv4 a 32 bit si è passati a IPv6 a 128 bit).
Logging
Definizione dell’API di logging (JSR 47, cfr [17]). Per molti si è trattato di un tentativo abbastanza affrettato di includere nel core Java una versione del celebre framework log4j. Nonostante l’introduzione di questo framework di logging che doveva di fatto diventare lo standard Java e quindi soppianare log4j e Apache Commons Logging (che non è un meccanismo di logging ma un comodo wrapper), questi ultimi sembrano mantenere la loro popolarità.
Java Advanced Imaging
Introduzione dell’API JAI (Java Advanced Imaging, immagini avanzate Java) per leggere e scrivere formati grafici come GIF, JPEG e PNG. (Java2D, javax.imageio.ImageIO).
JAXP
Altra caratteristica degna di nota fu l’integrazione JAXP (Java API for XML Processing, API Java per l’elaborazione XML) che include il parser XML (JSR 5, cfr. [18]) e il processore XSLT (JSR 63, cfr. [19]). JAXP consente alle applicazioni di eseguire il parsing, trasformare, validare e interrogare (query) documenti XML utilizzando una API indipendente da una particolare implementazione del processore XML. JAXP definisce un livello a plug-in per consentire a terze parti di fornire proprie implementazioni senza introdurre dipendenze nel codice dell’applicazione. Inoltre fornisce una semplice API per il parsing XML (SAX, Simple API for XML, semplice API per XML) e Document Object Model (DOM, modello ad oggetti del documento) in modo da consentire di analizzare stringhe XML o come un flusso di eventi o di costruirne una rappresentazione ad oggetti. JAXP supporta anche le standard eXtensible Stylesheet Language Transformations (XSLT, linguaggio di trasformazione dell’XML) offrendo il controllo della presentazione dei dati e consentendo di convertire i dati in altri documenti XML o in altri formati, come ad esempio HTML. JAXP fornisce anche il supporto dello spazio dei nomi (namespace), permettendo di lavorare con Document Type Definition (DTD, definizione del tipo documento) che altrimenti potrebbero generare conflitti sui nomi.
Security
Nella versione 1.4 fu data particolare importanza al tema dell’integrazione della sicurezza e delle estensioni per il supporto della crittografia. Ciò include una serie di API quali:
- JAAS (Java Authentication and Authorization Service, servizi Java di autenticazione e autorizzazione). Inizialmente definito come package opzionale (estensione) per J2SE 1.3 è stato poi integrato definitivamente in J2SE 1.4 (cfr. [20]). Questa API definisce il framework per implementare servizi di autenticazione, il cui obiettivo è di accertarsi in maniera affidabili che l’utente (o il componente software) sia effettivamente chi dichiara di essere, e di autorizzazione, il cui obiettivo è di verificare che l’utente (o il sistema) precedentemente autenticato abbiamo i permessi necessari per eseguire una determinata azione. Come da buone tradizioni Java, l’architettura JAAS prevede una strategia basata sui plug-in: ciò permette al sistema di utilizzare dei servizi in maniera astratta e indipendente dalla tecnologia di autenticazione effettivamente utilizzata.
- JSSE (Java Secure Socket Extension, estensione per la sicurezza dei socket Java). Anche in questo caso si tratta di un package che era opzionale per le versione J2SE 1.2 e 1.3, e che viene completamente integrato con la versione J2SE 1.4. JSSE è un insieme di package che permettono di effettuare comunicazione Internet sicure. In particolare, vi è una versione Java dei protocolli Secure Sockets Layer (SSL, strato socket sicuri) e del Transport Layer Security (TLS, strato di sicurezza del trasporto). Inoltre, include funzionalità per la crittografia dei dai, l’integrità dei messaggi e l’autenticazione dei server.
- JCE (Java Cryptography Extension, estensione Java per la crittografia). Come visto prima, anche JCE era un package opzionale per le versioni J2SE 1.2 e 1.3 ed è stato poi integrato al J2SE versione 1.4. Si tratta di un framework con relativa implementazione che fornisce servizi di crittografia, generazione di chiavi con relativa certificazione e algoritmi Message Authentication Code (MAC, codice di autenticazione del messaggio). I servizi di crittografia, a loro volta, includono cifrature simmetriche, asimmetriche, a cipher a blocchi e stream. Come lecito attendersi, JCE si basa sugli stessi principi di progettazione del JCA basati sull’indipendenza dalla specifica implementazione e, ove possibile, anche da specifici algoritmi. Pertanto, il funzionamenteo richiede la presenza di plug-in in grado di fornire i servizi specifici.
Java WS
Integrazione di Java Web Start (JavaWS o JAWS, avvio Web di Java, cfr. [21]). La prima versione di Java Web Start fu rilasciata nel marzo 2001 come estensione per J2SE 1.3. Si tratta di un framework originariamente sviluppato dalla Sun Microsystem che permette agli utenti di eseguire applicazioni Java scaricate direttamente da Internet attraverso un browser commerciale: un po’ come avviene con le Applet con la grande differenza però che queste applicazioni non funzionano all’interno di un browser (non sono parte della pagina da cui sono scaricate). Tuttavia, per default, funzionano in un ambiente ristretto simile al sandbox previsto per le Applet con qualche piccola concessione. Applicazioni che possono essere scaricate ed eseguite attravero Java Web Start devono includere il file Java Network Launching Protocol (JNLP, protocollo di rete di avvio Java), definito attraverso apposito schema XML. Questo include informazioni come la posizione dei JAR, il nome della classe principale dell’applicazione, oltre a eventuali altri parametri per il programma. I browser forniscono i file JNLP a un JRE che a sua volta scarica l’applicazione sul computer dell’utente e lo fa eseguire. I vantaggi principali che si possono conseguire attravero Java Web Start includono la facilità di distribuzione del software particolarmente utile con parchi utente molto grandi o addirittura globali, e controllo dell’allocazione di memoria della JVM.
java.utils.prefs
L’introduzione dell’API Java preferences (preferenze API, package java.util.prefs) permette di gestire in maniera semplice e sistematica i file di configurazione e le preferenze utente e del sistema, l’ultimo valore posseduto da un determinato campo, etc. Il formato utilizzato è la classica coppia (key, value). In particolare, questa API fornisce gli strumenti per memorizzare e leggere le preferenze utente in maniera semplice (le preferenze sono memorizzate e lette attraverso metodi put e get) e veloce. La memorizzazione di queste informazioni è dipendente dalla piattaforma (ogni piattaforma utilizza un proprio meccanismo), tuttavia il comportamento del sistema resta indipendente dalla piattaforma.
Le numerose novità introdotte ebbero il loro riflesso sul numero di classi e pacchetti della piattaforma, che salirono a (figura 1) 136 package e 2991 classi.
Una piccola rivoluzione: J2SE 5.0
A questo punto dell’evoluzione di Java, appariva chiaro che nella versione successiva ci sarebbero state alcune novità di rilievo. Lo sviluppo delle tecnologie Internet, l’adozione globale del linguaggio Java come piattaforma di sviluppo per progetti importanti e mission critical, la base sempre più ampia di sistemi e dispositivi che facevano uso di Java erano il presupposto per una piccola rivoluzione. Il primo cambiamento netto, comunque, si ebbe ancora una volta nella denominazione della versione. Laddove ci si aspettava la versione 1.5 di Java 2 (il che non è già di per se’ il massimo della linearità, ma rientrava comunque nello standard di denominazione adottato fin qui), ossia una J2SE 1.5, assistemmo invece al rilascio della versione 5.0, con una mutazione nella progressione dei numeri che poi sarà meglio definita nelle versioni successive (quelle con cui operiamo attualmente).
La versione J2SE 5.0 rilasciata il 30 settembre del 2004 con la JSR 176 (cfr. [22]), nome in codice Tiger (“tigre”), ha rappresentato una piccola rivoluzione del linguaggio Java per via degli importanti cambiamenti apportati al linguaggio (cfr. [23]). In particolare, i cambiamenti principali sono quelli descritti qui sotto.
Generics
Introduzione dei generics, le template class in Java (JSR 14, cfr. [24]). Si tratta di un costrutto a lungo richiesto dalla comunità di programmatori Java che finalmente è stato rilasciato nel 2004 con qualche compromesso necessario per mantenere la sacra retrocompatibilità Java (back compatibility). Il meccanismo dei generics permette ai tipi e metodi di poter operare su oggetti di vario tipo, fornendo type-safety a tempo di compilazione. Pertanto, si rimuove la necessità di eseguire dei poco eleganti e pericolosi down-casting a tempo di esecuzione (in passato ogni istanza reperita da una collezione era restuita del tipo della classe genitore di tutte le altre classi, Object e quindi era necessario eseguire il down-casting al tipo voluto). L’implementazione di questa feature ha richiesto la completa revisione di tutte le classi Java. Poiche’ questa feature doveva essere implementata senza modificare il bytecode, il compilatore deve rimuovere le informazioni relative ai generics. Per esempio, una dichiarazione del tipo List è convertita nella versione semplice List che può contenere qualsiasi tipi di oggetto, creando problemi a ispezioni a run-time. Questa strategia ampiamente utilizzata in J2SE 5.0 si chiama type erasure (cancellazione).
Annotations
Le annotations (annotazioni) sono note anche come metadata (JSR 175, cfr. [25]) e permettono di aggiungere delle etichette atte a specificare ulteriori informazioni a costrutti del linguaggio come per esempio metodi, classi, variabili e package per uso e consumo di tool (chiamati annotation processors) in grado di comprendere tali informazioni e di usarle per fornire determinati servizi. Per esempio, il framework JUnit (a partire dalla versione 4) richiede di evidenziare i metodi di test (che pertanto devono essere eseguiti dal framework) attraverso l’annotazione @Test. Ancora, Spring basa la gran parte della configurazione sulle annotazioni (annotation-based configuration). Per esempio, è possibile definire delle proprietà la cui presenza è obbligatoria con l’annotazione @Required, @Autowired è utilizzato per indicare a Spring di eseguire l’auto-wire di un bean (inserirne il riferimento) secondo i dettami dell’Inversion Of Control (IoC, inversione del controllo).
Autoboxing/Unboxing
Autoboxing/unboxing (inscatolamento e spacchettamento), specificato dalla JSR 201 (cfr. [26]) è la conversione automatica che esegue il compilatore Java tra i tipi primitivi e le corrispondenti classi wrapper (ad esempio, int e Integer, double e Double, e così via). In Java non è permesso inserire un tipo base, come per esempio un int, in una collezione. Queste possono contenere solo oggetti, o più precisamente riferimenti a oggetti. Pertanto, qualora sia necessario inserire in una collezione un tipo base, è necessario utilizzare la corrispondente classe wrapper (Integer, nel caso di int). Quando poi si prende l’oggetto dalla collezione, è necessario eseguire la conversione inversa al tipo base l’oggetto reperito (nel caso dell’intero si usa il metodo intValue). Eseguire esplicitamente la conversion dal tipo base al corrispondente wrapper (Autoboxing) e vice versa (Unboxing) è un’attività noiosa che spesso finisce per rendere il codice meno chiaro e quindi meno leggibile. Il meccanismo dell’autoboxing e unboxing automatizza questo processo, riducendo il lavoro per il programmatore e mantenendo il codice più pulito. Tuttavia, le differenze tra tipi base e oggetti continuano ad esistere e un utilizzo poco accorto dell’autoboxing può presentare delle sorprese sgradevoli come il tentativo di eseguire il test di uguaglianza diretto su due oggetti wrapper.
Concorrenza
Introduzione del package della concorrenza di Doug Lea, java.util.concurrent (introdotto con la piattaforma J2SE 5.0, e quindi incorporato, backporting, nella versione 1.4, JSR 166 cfr. [27]). La versione iniziale di questo package includeva 15 nuove interfacce, 47 nuove classi, un nuovo tipo enumeratore e 5 nuove eccezioni. I principali meccanismi introdotti con il package della concorrenza sono schedulazione e gestione dell’esecuzione di task, strutture di dati coda e code bloccanti, nuove collezioni concorrenti (ottimizzate per MT), blocchi (locks), sincronizzatori (semafori, barriere e variabili atomiche). La libreria della concorrenza è organizzata in tre package: java.util.concurrent che ha due sottopacchetti, locks e atomic.
Enumerations
Anche Enumerations (enumerazioni, JSR 201, cfr. [26]) era stata inizialmente pensata già ai tempi di Oak ma poi si è dovuto attedere fino alla versione 5 per vederla implementata. Le enumerazioni sono insiemi di items strettametne correlati come per esempio le direzioni cardinali (NORD, SUD, EST e OVEST), i mesi dell’anno (gennaio, febbraio, …, dicembre), e così via. Si utilizzano per definire il tipo di attributi che possono assumere solo un valore presente in una lista predefinita. Le enumerazioni sono state introdotte in Java attraverso la parola chiave enum e permettono di definire una classe speciale chiamata un enum type. Il corpo della classe enum può includere metodi e altri campi. Il compilatore aggiunge automaticamente una serie di metodi predefiniti come per esempio il metodo statico che restituisce un array contenente tutti i valori di enum nell’ordine in cui sono dichiarati.
Variable arguments
varargs (variable arguments, argomenti variabili, cfr. [26]) fu una nuova feature utile in tutte quelle situazioni dove è necessario passare a un determinato metodo diverse istanze dello stesso senza però conoscere al momento della compilazione il numero esatto di tali istanze. In passato, l’unico modo per gestire situazioni di questo tipo era raggruppare questi oggetti in un array o lista. Tuttavia, con l’introduzione di varargs è possibile utilizzare parametri di cardinalità variabile. La sintassi prevede di specificare tre punti di sospensione immediatamente dopo il tipo del parametro e prima del nome. Chiaramente, a tempo di esecuzione i parametri varargs sono trasformati in array.
for each
La versione 5.0 vide anche l’introduzione del costrutto for each (JSR 201, cfr. [26]).
S tatic import
Con l’introduzione degli static import (importazione statica, JSR 201, cfr. [26]) si ha una funzionalità che permette ai membri (campi e metodi) definiti in una classe come static public di poter essere utilizzati nel codice Java senza specificare la classe di provenienza. In altre parole, consente ai programmatori di fare riferimento ai membri statici importati in una classe come se fossero dichiarate nella classe che li utilizza: ciò rimuove la necessità di qualificare i membri statici importati con il nome della classe in cui sono dichiarati.
Memory Model
Ridefinizione del Java Memory Model che definisce le modalità con cui i thread interagiscono con la memoria.
Synth
Introduzione di Synth, ossia di uno skinnable look and feel per i widget Swing, configurabile attraverso un file di configurazione XML.
Scanner
Introduzione della classe Scanner (java.util.Scanner) utilizzabile per eseguire il parser dei dati da diversi input come streams e buffer. In pratica, spezzetta l’input in una serie di token utilizzando un pattern di delimitazione, che di default corrisponde a uno spazio bianco. I token risultanti possono poi essere convertiti in specifici tipi utilizzando vari metodi next. La funzione Scanner è similie a StringTokenizer, tuttavia presenta una maggiore ricchezza e flessibilità, non sempre di immediato utilizzo.
Con questa release la piattaforma Java raggiunge (figura 1) la ragguardevole cifra di 166 package e 3562 classi.
Java SE 6
Con la versione 6, rilasciata l’11 dicembre del 2006, la Sun Microsystem aggiorna nuovamente la strategia per la denominazione delle versioni: si passa da J2SE x.0 a Java x, rimuovendo la parte decimale “.0” e la sigla “J2”, definitivamente sostituita da un più lineare “Java”. Il nome in codice di questa release è Mustang (una possente razza di cavallo che vive anche allo stato brado negli USA) e la JSR è la 270 (cfr. [28]). Sebbene si tratti di una major release ricca di aggiornamenti, è forse più nota per una certa difficoltà nel riuscire a raggiungere una versione senza difetti che per le novità apportate: la versione beta venne rilasciata nel febbraio del 2006 mentre l’ultimo update, il 31, è stato rilasciato poche settimane fa, nel febbraio 2012). Inoltre, dopo la notevole rivoluzione introdotta con la versione 5, la versione Java SE 6 è passata un po’ sottogamba. Ciò nonostante, anche Java 6 ha le sue novità, che in alcuni casi sono dei semplici, ma importanti, aggiornamenti.
Scripting
Java 6 presenta il supporto per i linguaggi di scripting (javax.script, JSR 223 cfr. [29]) e l’integrazione di Mozilla JavaScript Rhino (cfr. [30]). Rhino è un un engine open source per JavaScript, è stato scritto interamente in Java dalla Mozilla Foundation. La stessa fondazione fornisce anche un’altra versione del motore JavaScript scritto in C/C++ di nome SpiderMonkey (cfr. [31]). Rhino converte script JavaScript in classi e funziona sia in modalità compilato, sia interpretato. Poiche’ è destinato a essere utilizzato lato server, non include il supporto per gli oggetti web browser tipici di JavaScript. La piattaforma Java offre un ricco insieme di risorse per lo sviluppo di applicazioni sia server side, sia lato web. Tuttavia, l’utilizzo di queste risorse al di fuori della piattaforma precedente alla versione 6 era tutt’altro che agevole a meno di ricorrere a soluzioni proprietarie. Non esisteva uno standard riconosciuto e chiarito per stabilire come gli sviluppatori potessero utilizzare classi Java da altri linguaggi di programmazione. Inoltre, i linguaggi di scripting non sono supportati da uno standard che stabilisca le regole di integrazione con le tecnologie Java. La JSR 223 aiuta gli sviluppatori a integrare la tecnologia Java e i linguaggi di scripting defininendo un framework e una API per eseguire operazioni come accesso e controllo di oggetti della tecnologia Java da ambienti scripting, creazione di contenuti web con linguaggi di scripting, incapsulamento di ambienti di scripting all’interno di applicazioni Java.
Prestazioni
Signficativo miglioramento delle performance sia del core Java sia della API Swing. Sebbene non esistano stime veramente oggettive, molti test informali mostrano per Mustang un aumento delle performarce dell’ordine del 50-60% rispetto alle precedente versione Tiger (cfr. [32]). Java 6 segna un miglioramento delle prestazioni della JVM (cfr. [32]), tra i quali i più interessanti sono l’ottimizzazione delle prestazioni dell’interprete (accelerazione del metodo System.arraycopy(), un nuovo Linear Scan Register Allocation Algorithm) e della gestione della sincronizzazione (biased locking, lock coarsening, adaptive spinning) a cui si affianca l’introduzione di nuovi algoritmi per il thread del garbage collection (Parallel Compaction Collector, Concurrent Low Pause Collector) e il migliormento di quelli esistenti. Si assiste a un miglioramento delle performance durante il processo di start-up delle applicazioni.
Web Service
Migliorato supporto per i Web Service tramite la Java API for XML Web Services (JAX-WS, JSR 224, cfr. [33]). In particolare, gran parte di questa specifica verte sulla definizione delle annotazioni per JAX-WS 2.0.
JDBC 4.0
Supporto per la JDBC API versione 4.0 (JSR 221, cfr. [34]). Interessanti novità riguardano il fatto che non è più necessario caricare esplicitamente il driver JDBC utilizzando codice come Class.forName() per registrare il driver JDBC. La classe DriverManager si fa carico di questa attività localizzando automaticamente un driver adatto all’atto dell’esecuzione del metodo DriverManager.getConnection(). JDBC 4.0 fornisce anche un migliore ambiente di sviluppo riducendo al minimo il codice “infrastutturale” (boiler plate) necessario per accedere a database relazionali. Inoltre sono state aggiunte classi di utilità per migliorare la registrazione del driver JDBC, per la gestione dei data source, e per una migliore gestione della connessione. Con JDBC 4.0, inoltre, gli sviluppatori possono specificare query SQL mediante opportune annotazioni. La versione Java 6 inoltre include nel bundle Apache Derby (cfr. [35]): si tratta di un database relazionale molto leggero, sviluppato interamente in Java.
Java Compiler
Introduzione della Java Compiler API (JSR 199, cfr. [36]). Si tratta di una API che permette di invocare il compilatore Java dal codice Java (package: javax.tools, Tool javac = ToolProvider.getSystemJavaCompiler()). Il compilatore Java API si propone tre obiettivi principali: invocazione del compilatore e di altri strumenti, accesso programmatico ai messaggi diagnostici strutturati, possibilità di personalizzare il file di input e output.
JAXB 2.0
Upgrade della versione 2.0 JAXB con incluso il supporto per il parser StAX (Streaming API for XML). Le specifiche JAXB 2.0 sono strate definite per mezzo di JSR 222 (cfr. [37]) e i principali miglioramenti riguardano l’utilizzo dei generics che permettono la verifica del tipo a tempo di compilazione, l’introduzione delle annotazioni al fine di ottenere metadati strutturati utilizzabili per generare codice a partire da dichiarazioni opportunamente etichettate, il supporto di tutti i costrutti degli schema XML alcuni dei quali non erano supportati con la versione JAXB 1.0, la riduzione del numero delle classi Java generate a partire da uno schema XML (per ogni complexType livello superiore, viene generata una classe di valore, invece che un’interfaccia e una classe di implementazione; per ciascun elemento di livello superiore, viene generato un metodo di classe factory, invece di un’interfaccia e una classe di implementazione), la riduzione del numero di librerie di runtime necessare, un migliore supporto per il binding Java di stringhe XML tramite l’aggiunta del pacchetto javax.xml.bind.annotation, una migliore integrazione con JAX-WS. ll parser StAX si occupa di eseguire l’elaborazione di documenti XML utilizzando una nuova strategia. Tradizionalmente era possibile utilizzare due diversi approacci:
- utilizzo dell’analisi ad albero, ossia costruzione del modello DOM basato sul caricamento dell’intero file XML in memoria, costruzione del corrispondente albero per poi analizzarlo attraverso le apposite librerie;
- utilizzo dell’API basata sugli eventi: l’API invia eventi corrispondenti ai nuovi elementi individuati.
Entrambe le strategie forniscono all’utente un controllo ridotto o inesistente durante il parsing. Una volta avviato il processo, entrambi gli approcci di analisi processano l’intero flusso di dati prima di restituire il controllo. La StAX (JSR 173, cfr. [38]) definisce un modello pull di streaming dove, a differenza di SAX, il cliente può iniziare, proseguire, sospendere e riprendere il processo di analisi disponendo di un controllo completo sul processo.
Pluggable annotations
Supporto per le annotazioni pluggable (JSR 269, cfr. [39]). La possibilità di utilizzare metadati strutturati è stata introdotta con J2SE 5 attraverso il famoso meccanismo delle annotazioni. Queste permettono di specificare meta information che sono o processate da appositi tool di compilazione (tipicamente chiamati precompilatori) o da librerie a tempo di esecuzione al fine di ottenere nuovi comportamenti semantici. Il framework delle annotazioni pluggable fornisce un supporto standard per la scrittura di processori di annotazioni personalizzate. L’aggettivo pluggable indica che i processori di annotazioni possono essere inseriti dinamicamente nel compilatore Java (javac) permettendogli di operare sulle annotazioni che appaiono nei file sorgenti Java. Il nuovo framework consta di due parti principali: una API per la dichiarazione e l’interazione con i processori di annotazione (javax.annotation.processing) e una API per modellare il linguaggio di programmazione Java (javax.lang.model).
Novità per l’interfaccia grafica utente
Introduzioni di nuovi componenti per la GUI, come per esempio lo SwingWorker, javax.swing.SwingWorker, progettato per risolvere elegantemente le situazioni in cui si ha bisogno di eseguire dei task in un thread in background, fornendo aggiornamenti all’interfaccia utente. Le specializzazioni di SwingWorker devono implementare il metodo doInBackground () per eseguire le elaborazioni dovute in background. Inoltre, ordinamento e filtro delle tabelle, un vero e proprio double-buffer per Swing per eliminare il problema della visualizzazione del rettangolo grigio.
Con questa release, la piattaforma Java raggiunge (figura 1) i 203 package e le 3793 classi.
Java SE 7: OpenJDK e acquizione Oracle
Per quanto riguarda Java SE 7, diamo qui solo alcune informazioni: scenderemo nei dettagli in un prossimo articolo di questa serie opportunamente dedicato a Java 7. Il nome in codice di questa versione è Dolphin (“delfino”) e il rilascio ufficiale è avvenuto il 7 luglio del 2011 mentre per l’apertura al pubblico si è dovuto attendere per tre settimane. Il progetto è stato organizzato in 13 milestone: il “feature complete” è stato raggiunto il 23 dicembre 2011, mentre la preview per gli sviluppatori è iniziata solo il 17 febbraio 2012, quindi un paio di mesi fa(cfr. [40]). Due eventi molto importanti hanno caratterizzato la gestione del progetto Dolphin:
- nel maggio del 2007 Sun Microsystem decide di rilasciare OpenJDK kit, implementazione aperta e gratuita del linguaggio di programmazione Java. L’implementazione è stata rilasciata sotto licenza GNU General Public License (GPL), con un’eccezione di collegamento (linking exception), che esenta Java Class Library dai termini della licenza GPL (cfr. [41]).
- nel gennaio del 2010 Sun Microsystem viene acquisita da Oracle Coporation con un accordo da 7.4 miliardi di dollari. Il 2 aprile del 2010 James Gosling, da molti considerato il padre di Java, dopo aver severamente criticato la gestione da parte di Oracle, si dimette da Oracle per iniziare con Google una collaborazione che a sua volta sarà destinata a non durare molto (cfr. [42]).
Roadmap
La release 7, dopo un inizio promettente, non procede esattamente come da programma. All’interno della JCP vi sono accesi dibatti, e l’acquisizione di Sun da parte di Oracle, con inevitabili avvicendamenti alle poltrone, di certo non facilita la situazione. Il comportamento di Oracle soprattutto in merito al licensing non è particolarmente apprezzato da diversi stakeholder come IBM, RedHat e Google. Anche le espressioni lambda creano più di di qualche grattacapo e pertanto si procede con il “Plan B”, che comporta lo slittamento di importanti feature dalle versione 7 alla versione 8. In particolare, i progetti Lambda, Jigsaw e parte del progetto Coin, vengono fatti slittare alla versione Java SE 8.
Ad ogni modo, anche se la vedremo meglio nei dettagli nei prossimi articoli, anche Java 7 ha le sue belle novità.
Modifiche al linguaggio
Ci sono una serie di variazioni minori del linguaggio, raggruppate nel progetto Coin (“moneta”, cfr. [43]).
È adesso possibile, ad esempio, realizzare costrutti switch con stringhe, anche se probabilmente questa non verrà annoverata tra le buone pratiche.
È stata poi adottata una gestione automatica delle risorse attraverso la nuova versione del costrutto try “con risorse” (try-with-resources). L’istruzione try-with-resources è un blocco try che dichiara una o più risorse, ossia oggetti che devono essere opportunamente chiusi dopo che il programma ne ha terminato l’utilizzo. L’istruzione try-with-resources assicura che ogni risorsa venga chiusa correttamente alla fine della dichiarazione. Qualsiasi classe che implementa java.lang.AutoCloseable, che comprende tutti gli oggetti che implementano java.io.Closeable, può essere come risorsa del costrutto try-with-resource.
C’è anche un miglioramento dell’inferenza di tipo per la creazione di istanze generiche. Questa nuova feature rende possibile sostituire gli argomenti di tipo necessari per invocare il costruttore di una classe generica con un insieme vuoto di parametri di tipo (<>) fintanto che il compilatore possa dedurre gli argomenti di tipo dal contesto. La coppia di parentesi angolari aperta-chiusa viene informalmente chiamata “diamante” (<>) chiaramente per la sua forma. Ad esempio la seguente dichiarazione:
Map <String, List > myMap = new HashMap <String, List > ()
con la nuova feature può essere sostituita con un insieme vuoto di parametri di tipo (<>):
Map <String, List > myMap = new HashMap <> ()
Un altro miglioramento è quello dei warnings e degli errori generati dal compilatore quando si utilizzano parametri formali non reifiable con i metodi varargs. La maggior parte dei tipi parametrizzati, come ArrayList e List, sono detti tipi non-reifiable per indicare che il tipo non è completamente disponibile a runtime. Al momento della compilazione, il tipo di oggetti non-reifiable subisce un processo chiamato cancellazione di tipo (erasure) durante il quale il compilatore rimuove le informazioni relative ai parametri di tipo e gli argomenti di tipo per assicurare la compatibilità binaria con le versioni Java antecedenti ai generics.
Vengono introdotti i tipi letterali binari. Con questa feature è possibile assegnare ai tipi interi (byte, short, int e long) valori espressi utilizzando il sistema binario. Questi letterali vanno specificati premettendo il valore con la stringa 0b. Per esempio
byte aByte = (byte) 0b00100001 short aShort = (short) 0b1010000101000101
C’è poi la possibilità di utilizzo degli underscore nei letterali numerici. Questa feature permette di inserire un numero qualsiasi di caratteri di sottolineatura (_)tra le cifre di un valore letterale numerico. L’idea di base è di separare gruppi di cifre in valori numerici al fine di migliorare la leggibilità del codice. Per esempio, se il codice contiene numeri con molte cifre, è possibile utilizzare un carattere di sottolineatura per separare le cifre in gruppi di tre, in modo simile a come si userebbe un segno di punteggiatura, come una virgola o uno spazio come separatore.
long = creditCardNumber 1234_5678_9012_3456L long socialSecurityNumber = 999_99_9999L
Da non trascurare è il nuovo costrutto catch che consente di specificare diversi tipi di eccezione concatenati per mezzo di un carattere pipe (|). In particolare, è possibile specificare costrutti catch del tipo
catch (IOException|SQLException ex)
E infine, tra le varie piccole modifiche al linguaggio, c’è il rilancio di eccezioni con controllo di tipo più preciso. Il compilatore Java SE 7 esegue un’analisi più precisa che consente di specificare i tipi di eccezione più specifiche da rilanciare nella clausola throws della dichiarazione di metodo.
Compressione dei puntatori per default
Questa feature era disponibile in Java 6 attraverso l’ozpione -XX:+UseCompressedOops (OOP, Ordinary Object Pointer, Puntatore a un normale oggetto). In Java SE 7, l’uso di puntatori compressi è il default per processi che funzionano su architetture a 64 bit quando JVM-Xmx non è specificato e per i valori di -Xmx minori di 32 gigabyte. Questo argomento è stato trattato in dettaglio nella nostra miniserie di articoli dedicati alle architetture a 64 bit (cfr. [44] e [45]). Si tratta di una tecnica che permette alle applicazioni che non intendano sfruttare le potenzialità di un indirizzamento a 64 bit di non pagare lo scotto, in termini di performance e di allocazione di memoria, di riferimenti estesi.
Estensione della JVM
L’estensione della JVM è stata realizzata per aumentare il supporto dei linguaggi dinamici (alcuni esempi di linguaggi definiti dinamici sono JavaScript, Lua, Objective-C, Perl, PHP, Python, Ruby, Tcl e Dolphin Smalltalk). La Macchina di Da Vinci (the Da Vinci Machine), è un progetto avviato originariamente dalla Sun Microsystems al fine di generare uno prototipo della Java Virtual Machine che includesse un’estensione atta ad aggiungere il supporto per i linguaggi dinamici, per questo il progetto è anche noto con il nome di Multi Language Virtual Machine (macchina virtuale multi-linguaggio). Sebbene sia già possibile eseguire linguaggi dinamici sulla JVM, l’obiettivo consiste nel facilitare le nuove implementazioni di linguaggi dinamici, aumentandone, contestualmente, le performance. Questo progetto è l’implementazione di riferimento di JSR 292 (Supporting Dynamically Typed Languages on the Java Platform, supporto di linguaggi dinamicamente tipizzati sulla piattaforma Java, cfr. [46]).
Libreria I/O
Nuove feature per la libreria I/O disegnate al fine di aumentare l’indipendenza dalla piattaforma e aggiungere il supporto per i metadati e i collegamenti simbolici. I nuovi package sono java.nio.file e java.nio.file.attribute. Tra le altre feature è importante menzionare l’introduzione (tanto attesa) di servizi per la copia ed il trasferimento di file e directory.
Package della concorrenza
Miglioramento del package della concorrenza java.util.concurrent e introduzione di nuove feature. Tra le nuove feature introdotte va sicuramente considerato il framework per il fork and join ottenuto per mezzo di un’implementazione dell’interfaccia ExecutorService che permette di sfruttare tutti i processori in architetture multi processore. Il disegno di base prevede task che possono essere suddivisi in parti più piccole. L’obiettivo è di sfruttare appieno la potenza di elaborazione disponibile nelle nuove architetture per migliorare le prestazioni dell’applicazione. Come con qualsiasi ExecutorService, il framework fork/join suddivide i compiti di thread di lavoro in un pool di thread e si contraddistingue per l’utilizzo di un innovativo algoritmo work-stealing (ruba-lavoro). I thread di lavoro a corto di lavoro sono in grado di rubare i compiti ad altri thread che sono ancora impegnati.
Cifratura ECC
L’implementazione Java dell’algoritmo Elliptic Curve Cryptography (ECC, crittografia basata sulle curve ellettiche) è un approccio di crittografia per chiavi pubbliche basato sulla struttura algebrica delle curve ellittiche su campo finito. ECC è ideale per l’utilizzo in ambienti ristretti come pager (cercapersone), PDA, telefoni cellulari e smart card. L’implementazione Java è stata denominata JECC. L’utilizzo di questo algoritmo per la crittografia fu suggerito in maniera indipendente sia da Neal Koblitz sia da Victor S. Miller nel 1985.
Miglioramenti a Java 2D
Introduzione di una pipeline grafica XRender per Java 2D, atta a migliorare la gestione delle funzionalità specifiche delle GPU moderne (X11-based desktop).
Nuova piattaforma per la grafica
Definizione di una nuova piattaforma per la grafica. Queste funzionalità erano originariamente previste per il rilascio già dalla versione Java 6u10, ma sono state implementate solo a partire dalla Java 7.
Supporto a nuovi protocolli
Aggiunta delle librerie per il supporto di nuovi protocolli come Stream Control Transmission Procotol (SCTP, protocollo di trasmissione su stream controllato). Si tratta di un protocollo di trasporto, che rappresenta un ibrido tra i popolari protocolli TCP (Transmission Control Protocol, protocollo a controllo di trasmissione) e UDP (User Datagram Protocol). In particolare è orientato al messaggio come UDP e, allo stesso tempo, assicura un trasporto affidabile e nella giusta sequenza come con il controllo di trasmissione tipico di TCP. Inoltre è supportato adesso anche il Sockets Direct Protocol.
Unicode 6.0
In Java 7 si è provveduto all’aggiornamento dello standard Unicode alla versione 6.0.
Aggiornamenti XML
Java 7 vede inoltre l’aggiornamento dei componenti dello stack XML alle versioni più recenti e stabili: JAXP 1.4, JAXB 2.2 e JAX-WS 2.2.
Con queste aggiunte e con tali aggiornamenti, la piattaforma Java attualmente include (figura 1) 209 package e 4024 classi. Un bel balzo in avanti rispetto agli iniziali soli 8 package di Java 1!
Java SE8
La trattazione di Java SE 8 è oggetto di uno dei prossimi numeri, quindi faremo solo un breve accenno. Il rilascio della versione 8 è stato programmato per l’estate del 2013 con l’obiettivo principale di rilasciare una serie di feature che erano state originariamente programmate per la release 7 e che poi sono state posticipate. Come menzionato sopra, si tratta principalmente dei progetti Lambda e Jigsaw e, più marginalmente, di Coin. Tra le nuove feature, una delle più interessanti è sicuramente il supporto delle lambda expression (espressioni lambda). Il rilascio di questa feature è stata fatta slittare a seguito di un acceso dibattito all’interno del Java Community Process che, tra le altre cose, ha determinato un grande ritardo del rilascio della stessa versione 7 e la messa in opera del famoso piano B. Le importanti feature che la Java SE dovrebbe includere sono quelle sotto riportate.
Lambda Expression
Java 8 dovrebbe vedere l’introduzione delle espressioni Lambda. Esse vengono definite anche closure, ma non in maniera ufficiale.
Modularizzazione
Java 8 prevede una decisione oramai non più rimandabile, ossia la completa modularizzazione del JDK (progetto Jigsaw, “puzzle a incastro”). Il JDK ha acquisito in questi venti anni una certa pesantezza, dovuta in gran parte agli effetti collaterali di uno dei capisaldi della filosofia Java: la famosa (o famigerata) back compability (retrocompatibilità).Tale strategia è stata giusta, perche’ ha consentito sempre di avere bytecode compatibile; ma sul lungo termine ha finito per appesantire eccessivamete il JDK. Basti pensare che, come già detto, Java SE 7 include più di quattromila classi(figura 1) tra le quali ancora figurano classi come java.util.Vector e java.util.Hashtable! La presenza di queste feature obsolete crea una serie di importanti effetti negativi, come per esempio, una limitazione allo sviluppo di nuove feature, la necessità di cambiare e verificare un grande quantitativo di codice a seguito di ogni nuovo cambiamento. La modularizzazione dovrebbe risolvere tale inconveniente, con una razionalizzazione delle librerie per ridurre le dipendenze fra le classi.
Java FX
Altra caratteristica che dovrebbe essere presente in Java 8 è il miglioramento dell’integrazione con JavaFX. JavaFX è una piattaforma software per la creazione e la distribuzione di Rich Internet Application (applicazioni internet con una sofisticata esperienza utente) che possono essere eseguite in una vasta gamma di dispositivi collegati in rete. Le nuovi versioni consentono di realizzare applicazioni per ambienti desktop, broswer Internet, telefoni cellulari e dispositivi come decoder TV, games console, lettori blu-ray e così via.
Java SE 9
Come lecito attendersi, è ancora abbastanza prematuro parlare di Java SE 9 quando ancora Java SE 8 non è disponibile e ancora molto lavoro è necessario. Tuttavia, da una serie di indiscrezioni apparse nei vari blog, e seguendo il corrente trend evolutivo dell’IT, è possibile immaginare che il futuro sviluppo della piattaforma Java verterà nelle aree che riportiamo nei prossimi paragrafi.
Quasi sicura una maggiore scalabilità della JVM e delle librerie al fine di poter sfruttare al meglio le moderne architetture multi-core. Sarà poi tenuto in debita considerazione il supporto per il cloud-computing.
Da tenere in considerazione sarà l’integrazione di Hypervisor, denominato anche Virtual Machine Manager,VMM (ossia Gestore delle macchine virtuali). Si tratta di una delle molte tecniche di virtualizzazione hardware che permette a più sistemi operativi, denominati guests (“ospiti”), di girare in maniera concorrente su un computer host. È stato chiamato così perche’ è concettualmente a un livello più alto di un programma di supervisione: una ipervisione, appunto. L’hypervisor fornisce ai sistemi operativi ospiti una piattaforma virtuale e gestisce l’esecuzione dei rispettivi sistemi operativi. Più istanze di uno stesso tipo di sistemi operativi possono condividere le risorse hardware virtualizzate. Software hypervisor sono comunemente installati sull’hardware dei server. Il termine hypervisor è stato coniato nel 1965, riferendosi al software che ha accompagnato uno RPQ IBM per l’IBM 360/65, che ha permesso al modello IBM 360/65 di condividere la sua memoria tra IBM 360 e IBM 7080 in versione emulata. Il software hypervisor effettua la commutazione tra le due modalità in split-time.
Un altro ambito in cui probabilmente assisteremo a miglioramenti saranno le JVM sempre più sofisticate e performanti in grado di fornire tutta una serie di nuovi servizi con il self-tuning. A questo si aggiungerà un maggiore sfruttamento delle caratteristiche native delle piattaforme in cui gira la JVM.
Inoltre, si parla di supporto per il protocollo per i meta-oggetti (Meta-Object Protocol, MOP). Si tratta di un interprete aperto ed estensibile. Un MOP pertando determina cosa un programma significhi da un punto di vista semantico, e quale sia il suo comportamento. Inoltre è estensibile nel senso che un programmatore può alterare il comportamento del programma, estendendo parti del MOP. A tal fine il MOP espone parte della struttura interna dell’interprete al programmatore. Il MOP si può manifestare come un insieme di classi e metodi che consentono ad un programma di controllare (inspecting) lo stato del sistema di supporto e modificarne il comportamento. i MOP sono tipicamente implementati secondo il paradigma OO in cui tutti gli oggetti sono meta-oggetti.
Infine, si parla di supporto per i big-data (grandi dati). Big data è un termine applicato a un set di dati la cui dimensione è al di là della tipica capacità di strumenti software comunemente usati per memorizzare, gestire ed elaborare i dati all’interno di un lasso temporale considerato tollerabile. Le grandi dimensioni dei dati sono un limite in continuo movimento verso l’alto: vanno attualmente da un Terabyte a poche decine di Petabyte di dati diversi in un unico insieme di dati. Una caratteristica corrente dei big-data è la difficoltà di gestirli per mezzo dell’utilizzo di database relazionali e desktop statici o visualizzati. Questi dati invece richiedono software paralleli massivamente in esecuzione su decine, centinaia o persino migliaia di server.
Conclusione
Con questo articolo abbiamo coperto quasi un ventennio della tecnologia Java: dalla versione JDK 1.0 rilasciata nel giugno del 1994 siamo giunti fino alle versione Java SE 7 rilasciata nel febbraio 2011, e abbiamo fornito anche una con una piccola preview di Java SE 8 e della possibile versione 9. Nell’allegato, scaricabile dal menu in alto a destra, c’è una sintesi grafica di questo lungo processo, con le tappe fondamentali collocate cronologicamente.
In particolare, abbiamo visto come da una piattaforma composta da 8 package e 212 classi (che allora fu considerata una piattaforma molto ricca) si sia giunti a ben 209 package ed oltre 4 mila classi esempio. Questa pesantezza, dovuta in gran parte alla pur valida strategia della retrocompatibilità, finisce per incidere, ad esempio, su cicli di rilascio delle nuove feature che richiedono tempi e costi aggiuntivi necessari per modificare e testare del codice che ormai, in diversi casi, si può definire “zavorra”. La buona notizia è che la versione Java SE 8, attraverso il progetto Jigsaw, dovrebbe puntare alla modularizzazione della piattaforma Java con conseguente snellimento, ma la cosa è ancora da vedere in pratica.
Un altro interessante elemento che abbiamo analizzato, e che è fonte di una certa confusione ancora oggi, è la denominazione da utilizzare per la piattaforma Java. In particolare, si è partiti con i JDK 1.0 e 1.1 poi si è passati a JDK 2 (invece che 1.2). Poi si è deciso di cambiare JDK 2 in J2SE 1.2. Questa nomenclatura è stata mantenuta fino a Java 6, battezzata Java SE 6.
Per finire, questo articolo ci ha permesso ti toccare un vasto insieme di tecnologie (e di sigle e acronimi) nel contesto della release Java in cui sono state introdotte. La speranza è che questo articolo abbia contribuito a fare chiarezza nella galassia delle tecnologie Java. Galassia, peraltro, in perenne espansione!
Riferimenti
[1] Luca Vetti Tagliati, “L’evoluzione di Java: verso Java 8 – I parte: il caffè… da una quercia”, Mokabyte 171, marzo 2012
https://www.mokabyte.it/2012/03/javaevolution-1/
[2] JavaSoft Ships Java 1.0
[3] JDK 1.1, Sun Press Room
[4] Sun Microsystems, “JavaBeans tm”, Graham Hamiltom (Editor), 24 Luglio, 1997
http://www.cs.vu.nl/~eliens/documents/java/white/beans.101.pdf
[5] JDBC Overview
http://www.oracle.com/technetwork/java/overview-141217.html
[6] JavaTM 2 Release note
[7] Doub Lea, “Overview of the collections Package”
http://gee.cs.oswego.edu/dl/classes/collections/index.html
[8] “Generic Collection Library for Java”, Gennaio 2011
http://www.stanford.edu/group/coursework/docsTech/jgl/
[9] Sun and Netscape to Jointly Develop Java Foundation Classes
[10] Overview—What Is Java Plug-in? What Does It Support?
http://docs.oracle.com/javase/1.4.2/docs/guide/plugin/developer_guide/overview.html
[11] JavaTM 2 SDK, Standard Edition, version 1.3, Summary of New Features and Enhancements
http://docs.oracle.com/javase/1.3/docs/relnotes/features.html
[12] Chirs Nerney, “Are Java magic bullets on target?”
http://www.networkworld.com/news/0706java.html, Luglio 1998
[13] JSR 59: J2SE Merlin Release Contents
http://www.jcp.org/en/jsr/detail?id=59
[14] The Apache Software Foundation Blog, “The ASF Resigns from teh JCP Executive Committee”
https://blogs.apache.org/foundation/entry/the_asf_resigns_from_the
[15] JSR 41: A Simple Assertion Facility
http://www.jcp.org/en/jsr/detail?id=41
[16] JSR 51: New I/O APIs for the JavaTM Platform
http://www.jcp.org/en/jsr/detail?id=51
[17] JSR 47: Logging API Specification
http://www.jcp.org/en/jsr/detail?id=47
[18] JSR 5: XML Parsing Specification
http://www.jcp.org/en/jsr/detail?id=5
[19] JSR 63: JavaTM API for XML Processing 1.1
http://www.jcp.org/en/jsr/detail?id=63
[20] Java Authentication and Authorization Service (JAAS) Reference Guide
http://docs.oracle.com/javase/1.4.2/docs/guide/security/jaas/JAASRefGuide.html
[21] JavaTM Web Start Technology
http://www.oracle.com/technetwork/java/javase/javawebstart/index.html
[22] JSR 176: J2SETM 5.0 (Tiger) Release Contents
http://www.jcp.org/en/jsr/detail?id=176
[23] J2SE 5.0, New Features and Enhancements
http://docs.oracle.com/javase/1.5.0/docs/relnotes/features.html
[24] JSR 14: Add Generic Types To The JavaTM Programming Language
http://www.jcp.org/en/jsr/detail?id=14
[25] JSR 175: A Metadata Facility for the JavaTM Programming Language
http://www.jcp.org/en/jsr/detail?id=175
[26] JSR 201: Extending the JavaTM Programming Language with Enumerations, Autoboxing, Enhanced for loops and Static Import
http://www.jcp.org/en/jsr/detail?id=201
[27] JSR 166: Concurrency Utilities
http://www.jcp.org/en/jsr/detail?id=166
[28] JSR 270: JavaTM SE 6 Release Contents
http://www.jcp.org/en/jsr/detail?id=270
[29] JSR 223: Scripting for the JavaTM Platform
http://www.jcp.org/en/jsr/detail?id=223
[30] Mozilla Rhino: JavaScript for Java
[31] Mozilla SpiderMonkey
https://developer.mozilla.org/en/SpiderMonkey
[32] JavaTM SE 6 Performance White Paper
http://java.sun.com/performance/reference/whitepapers/6_performance.html
[33] JSR 224: JavaTM API for XML-Based Web Services (JAX-WS) 2.0
http://www.jcp.org/en/jsr/detail?id=224
[34] JSR 221: JDBCTM 4.0 API Specification
http://www.jcp.org/en/jsr/detail?id=221
[35] Apache Derby
[36] JSR 199: JavaTM Compiler API
http://www.jcp.org/en/jsr/detail?id=199
[37] JSR 222: JavaTM Architecture for XML Binding (JAXB) 2.0
http://www.jcp.org/en/jsr/detail?id=222
[38] JSR 173: Streaming API for XML
http://www.jcp.org/en/jsr/detail?id=173
[39] JSR 269: Pluggable Annotation Processing API
http://www.jcp.org/en/jsr/detail?id=269
[40] JDK 7 Milestones
http://openjdk.java.net/projects/jdk7/milestones/
[41] OpenJDK
[42] Il nuovo Blog di James Gosling
http://nighthacks.com/roller/jag/entry/time_to_move_on
[43] Aggiornamenti del linguaggio di programmazione Java
[44] Luca Vetti Tagliati, “Java e le architetture a 64 bit: i puntatori compressi – I parte: Cosa succede con i 64 bit”, MokaByte 157, Dicembre 2010
https://www.mokabyte.it/2010/12/java64bit-1/
[45] Luca Vetti Tagliati, “Java e le architetture a 64 bit: i puntatori compressi – II parte: Sfruttare i vantaggi in ottica SOA”, MokaByte 158, Gennaio 2011
https://www.mokabyte.it/2011/01/java64bit-2/
[46] JSR 292: Supporting Dynamically Typed Languages on the JavaTM Platform
http://jcp.org/en/jsr/detail?id=292