Sinds enige tijd is de release-versie van Java 7 op het toneel verschenen. Voor een Java-bedrijf is het zeer interessant om de nieuwe features van de taal eens te bekijken, dus een blogpost kon niet uitblijven. Waar ik het in deze post niet (verder) over zal over hebben, is het debacle dat Oracle van de lancering heeft gemaakt: er zit een serieuze bug in de compiler-optimizaties, dus best nog even wachten met upgraden! (Toch wat weinig tijd tussen de release candidate en de echte ‘rush-release’ gelaten, naar mijn mening.)
Maar goed, ter zake! Wat brengt Java 7 ons voor vernieuwingen?
Ik moet echter beginnen met een disclaimer: na jaren van ontwikkeling is er natuurlijk heel wat meer bijgekomen in de taal dan ik hier kan beschrijven. Mijn oplijsting is dus niet exhaustief. Het blijkt trouwens vrij moeilijk om een perfect juist beeld bij elkaar te googlen van wat er nu precies wél of niet inzit, en daarbij ook nog eens een goede uitleg over deze zaken te krijgen (maar vandaar ook het nut van een blogpost als deze).
De vernieuwingen dan:
Eerst de zaken die we niet meteen met het blote oog kunnen zien: de virtuele machine heeft een hele evolutie doorgemaakt sinds het begin van Java, en in versie 7 is er voor gezorgd dat er goede support is voor dynamische talen, zoals Groovy. Deze talen zullen nu quasi even performant zijn als Java zelf (no pun intended). Verder zijn er een aantal zaken verbeterd betreffende class loaders, die voor minder bugs zorgen wanneer er meerdere van gebruikt worden, en er is nu ook een URLClassLoader.
Ook de ondersteuning voor parallelisme is nog wat beter geworden, met nieuwe klassen in het concurrency framework zoals de ForkJoinPool en de TransferQueue. Dit lijken mij goeie toevoegingen, maar de ondersteuning voor multithreading, met een hoog niveau van abstractie, was reeds erg goed. Ik bespreek dit raamwerk graag nog uitgebreider in een toekomstige blogpost. Multithreading zal zeker nog aan belang winnen in de toekomst, wanneer we meer en meer cores in onze computers krijgen.
Wat IO en netwerken betreft, zijn er voorts nog een aantal interessante toevoegingen, zoals een vernieuwing van de IO api (New IO: “NIO”), scp en sctp ondersteuning, gebruik van windows vista ipv6 en, last but not least: TLS 1.2 (ook wel SSL 3.3 genoemd).
Voor de security mensen: Elliptic Curve Cryptography is nu out-of-the-box beschikbaar.
En dan één van mijn stokpaardjes: de client, en Swing! Er is nu een nieuwe rendering-pipeline voor Java2D, waardoor een aantal features van moderne gpu’s ter beschikking komen te staan. Verder is er ondersteuning voor translucente en onregelmatig gevormde vensters, een nieuwe Look and Feel, en een nieuwe sound synthesizer. En ten slotte, zoals gewoonlijk, zijn een aantal zaken van SwingLabs gemigreerd naar de standaard Swing api.
Tot zover de ‘saaiere’ vernieuwingen; de echte vraag die echter op ieders lippen ligt, is natuurlijk: Wat zijn de nieuwe dingen die we kunnen doen als programmeur? Give us the language features!
Een eerste kleine verbetering, is de mogelijkheid om Strings te gebruiken in een switch statement. Persoonlijk vind ik dit niet supernuttig, dus ik ga er ook geen voorbeeld van geven. Volgens mij zijn enums veel beter geschikt om ‘of-of-of’ constructies op poten te zetten, en is een goed uitgedacht design, gebruik makende van polymorfisme en dynamische binding, meestal zowiezo een beter alternatief. Maar goed, het was een zinloze beperking, en het is goed dat deze nu is weggewerkt.
Next! Naast hexadecimale, octale en (gewone) decimale getallen, komt er nu ook een voorstellingswijze voor binaire getallen: ik moet zeggen: in quasi alle gevallen: blijf er van weg! Wat wel interessant is, is dat men nu underscores in getallen kan plaatsen om de leesbaarheid te verhogen. Zo is b.v. 1_000_000 vanaf nu een correcte en beter leesbare voorstellingswijze voor het getal 1000000. Ook in de andere voorstellingswijzen, en in floating point getallen, kan men ze gebruiken. Een getal moet wel nog altijd met een cijfer starten en eindigen.
Nog een kleine, eenvoudige verbetering is type inferentie bij het aanroepen van de constructor van generische klassen. Stel: je declareert een List<String> en je wil deze lijst initialiseren als een arraylist. Vroeger moest je dan als volgt de constructor aanroepen: new ArrayList<String>(). Met type inferentie wordt dit gewoon: new ArrayList<>(). De compiler is dus eindelijk slim genoeg geworden om te raden welk type je wou maken. Bemerk dat er nog steeds een diamandje “<>” nodig is, anders heb je een raw type. Vandaar dat men deze verbetering “diamond” heeft gedoopt. Eenvoudig en handig.
Een iets minder voor de hand liggende taaluitbreiding, is automatic resource management (ARM). De standaard manier van werken om een InputStream of File terug vrij te geven in geval van onverwachte gebeurtenissen, is dit in een finally clausule te zetten ( finally { file.close(); } ). Dit kan echter problemen opleveren wanneer je meerdere close-statements moet uitvoeren en de eerste close-methode zelf een foutmelding geeft, waardoor de erop volgende close-statements niet meer worden uitgevoerd. De nieuwe manier van werken, is de resources aan te maken in een statement, ingesloten in haakjes, volgende op het ‘try’-keyword. Een beetje zoals de declaratie van de teller in een for-statement. Bijgevolg krijg je dan iets als volgt: try (InputStream i = …; OutputStream o = …) {…} finally {/*niet meer nodig*/}. Achter de schermen zou dit dan werken alsof men recursieve try-finally statements gebruikt om alle mogelijke fouten op te vangen (dus de eerste close zit nog in een extra try blok, gevolgd door een finally block met daarin de tweede close; het geheel van deze try-finally zit op zijn beurt in het finally blok van de uit te voeren code). Je kan je inbeelden dat, als je dit manueel moest doen voor meer dan twee resources, er nogal wat boilerplate code aan te pas kwam; dit is dus een vrij nuttige feature.
De laatste taaluitbreiding die ik wil bespreken, heeft opnieuw met exception-handling te maken, ditmaal met het catch-blok. Bij het loggen van excepties die men niet onmiddellijk kan afhandelen, zal men deze vaak vangen, loggen, en dan opnieuw gooien. Vaak heeft men echter een try-blok dat verschillende soorten uitzonderingen kan gooien, waardoor men hetzelfde stukje code moet herhalen in een hele resem catch-blokken. Een superklasse gebruiken voor het catch-blok is vaak gevaarlijk, omdat er eventueel exceptie-types kunnen omvat worden waarvoor dit in eerste instantie niet de bedoeling was. Wanneer men b.v. het type “Exception” gebruikt, omvat dit alle mogelijke RuntimeExceptions, terwijl men misschien enkel een aantal niet-gerelateerde checked exceptions wou opvangen. De boilerplate code die hierbij komt kijken, kan men nu voor een deel schrappen, doordat men in de catch-expressie nu een lijst van types kan geven, gescheiden door verticale of-strepen ( “|” ). Men zou bijvoorbeeld kunnen zeggen: catch (NullPointerException | IndexOutOfBoundsException e) {log(e); throw e;}, in plaats van voor elk type uitzondering een apart catch-blok te maken. Ik had nog niet echt stilgestaan bij deze problematiek, maar ik denk wel dat het kan helpen om robuuste code te maken, voorzien van alle toeters en bellen om ze “enterprise-ready” te maken.
Meer uitleg betreffende de kleine, handige taaluitbreidingen, kan je vinden op de site van Project Coin. Een aantal goeie voorbeelden kan je bekijken op een presentatie die een tijdje terug op JavaOne is gegeven.
Tussen haakjes: tijdens mijn zoektocht ben ik ook de filosofie van Java nog eens tegengekomen, wat betreft het evolueren van de taal:
- Reading is more important than writing
- Code should be a joy to read
- The language should not hide what is happening
- Code should do what it seems to do
- Simplicity matters
- A clear semantic model greatly boosts readability
- Every “good” feature adds more “bad” weight
- Sometimes it is best to leave things out
Of deze principes tot nu toe trouw gevolgd zijn, laat ik over aan de lezer.
En als afsluiter: wat zit er niet in? Een aantal zaken zijn reeds lang in ontwikkeling, maar voorlopig blijkbaar toch nog iets te moeilijk: Doorgedreven modularisatie is o.a. al zeker tot Java 8 uitgesteld. Ook de veelgeplaagde, vaak gevraagde closures (Project Lambda), zijn voorlopig nog even terug in de kast gestoken, alsook een meer directe taalondersteuning voor het collection framework. Meer geluk eind 2012?
Leave a Reply