Angelika Langer - Training & Consulting
HOME | COURSES | TALKS | ARTICLES | GENERICS | LAMBDAS | IOSTREAMS | ABOUT | CONTACT | Twitter | Lanyrd | Linkedin
 
HOME 

  OVERVIEW

  BY TOPIC
    JAVA
    C++

  BY COLUMN
    EFFECTIVE JAVA
    EFFECTIVE STDLIB

  BY MAGAZINE
    JAVA MAGAZIN
    JAVA SPEKTRUM
    JAVA WORLD
    JAVA SOLUTIONS
    JAVA PRO
    C++ REPORT
    CUJ
    OTHER
 

GENERICS 
LAMBDAS 
IOSTREAMS 
ABOUT 
CONTACT 
Java 7 - JSR 334 - Project Coin - Strings in switch, Exception Handling, ARM, numerische Literale

Java 7 - JSR 334 - Project Coin - Strings in switch, Exception Handling, ARM, numerische Literale
Java 7 
JSR 334 - "Project Coin"
(Strings in switch, Exception Handling, ARM, numerische Literale)
 

Java Magazin, August 2011
Klaus Kreft & Angelika Langer

Dies ist die Überarbeitung eines Manuskripts für einen Artikel, der im Rahmen einer Kolumne mit dem Titel "Effective Java" im Java Magazin erschienen ist.  Die übrigen Artikel dieser Serie sind ebenfalls verfügbar ( click here ).

Die Version 7 von Java wird eine Reihe von kleineren Sprachergänzungen bringen, die unter dem Namen "Project Coin" entwickelt wurden.  In diesem Beitrag stellen wir einen Teil dieser neuen Sprachmittel aus dem Project Coin vor, nämlich verbesserte Notationen für numerische Literale, Strings in switch-Anweisungen, Verbesserungen beim Exception Handling und das Automatic Resource Management.  Die übrigen Verbesserungen im Zusammenhang mit Generics werden wir im nächsten Artikel besprechen.

"Project Coin"  ist eine Sammlung kleinerer Spracherweiterungen.  Die Ideen für diese Ergänzungen stammen aus der Java Community selbst.  Sun Microsystems hatte die Community aufgefordert, entsprechende Vorschläge zu machen, und hatte aus der Fülle der Ideen eine Handvoll aufgegriffen.  Die Idee dabei war es, die Sprache um Mittel zu erweitern, die nützlich und "klein" sind.

Folgende neue Sprachmittel werden mit Java 7 freigegeben:

  • Verbesserte Schreibweisen für numerische Literale
  • Strings in switch-Anweisungen
  • Verbessertes Exception Handling
  • Automatic Resource Management
  • Vereinfachungen beim Aufruf von Methoden mit variabler Argumentenliste
  • Verbesserte Type Inference für Konstruktoren generischer Typen ( diamond operator)
Die letzten beiden Punkte betreffen Verbesserung der Sprache im Zusammenhang mit Generics; wir diskutieren sie im nächsten Beitrag.  Dieses Mal stellen wir die ersten vier der oben genannten Spracherweiterungen für Java 7 vor.
 

Verbesserte Schreibweise für numerische Literale

Binary Literals

Bislang konnten numerische Literale nur dezimal (als 1), octal (als 01) oder hexadezimal (als 0x1) hingeschrieben werden.  Mit dem JDK 7 (siehe /JSR334/ und  /BINLIT/) gibt es nun auch die Möglichkeit der Binärdarstellung (als 0b1).

Hier ist ein Beispiel für die neue Binär-Darstellung:

    int decimal = 43;
    int hex     = 0x2B;
    int octal   = 053;
    int binary  = 0b101011;

Underscores in Numbers

Im Java-Source-Code mussten numerische Literale bisher immer dicht geschrieben werden, d.h. ohne Leerzeichen oder andere Strukturierungszeichen zu enthalten.  Für das menschliche Auge sind solche Strukturierungselemente aber sehr hilfreich, z.B. wenn man eine Telefonnummer oder eine Kreditkartennummer hinschreiben will. Die Nummer +49721629188 ist schwer verdaulich und in der Schreibweise +49 721 6291 88 deutlich besser als Telefonnummer zu erkennen.  Um solche lesbareren Darstellungen zu erlauben, ist es im JDK 7 nun erlaubt, an praktisch allen stellen in einem numerischen Literal Unterstriche einzufügen (siehe /INTLIT/). Man dürfte die obige Telefonnummer nun also so schreiben: +49_721_6291_88.  Der Compiler entfernt beim Parsen die Unterstriche, so dass im Byte-Code wieder die alte kompakte Darstellung auftaucht.

Hier ein paar Beispiele:

long phoneNumber      = +49_721_6291_88L;
long creditCardNumber = 1234_5678_9012_3456L;
long hexWords         = 0xFFEC_DE5E;

Strings in switch-Anweisungen

Bislang konnte man in einer switch -Anweisung nur über Werte eines primitiven oder Enum-Typs verzweigen. In Java 7 darf auch über konstante Strings verzweigt werden (siehe /JSR334/ und  /STRSWT/). Der Vorteil liegt darin, dass der Compiler aus einem switch über Strings effizienteren Code erzeugen kann, als es mit den bislang zur Verfügung stehenden Sprachmitteln möglich ist.
Man darf also in Java 7 folgendes schreiben:
     private static final String IDLE = "idle";

    public static void newStringSwitch(String state) {
        final String terminal = "terminated";

        if (state== null)
            System.out.println("No state");
        switch (state) {
        case "busy":   // fall through works as before
        case terminal: // local final variables are ok
        case IDLE: {   // constants are ok
            System.out.println("Matched state");
            break; }
        default: {
            System.out.println("Unknown state");
            break; }
        }
    }


Im switch wird über eine String-Variable verzweigt und die case -Labels dürfen String-Literale oder final String-Variablen sein; non- final String-Variablen sind als case -Labels nicht erlaubt.

Der Effizienzzuwachs rührt daher, dass man mit heutigen Sprachmitteln eine if - else -Kaskade mit equals() -Vergleichen für alle Strings hinschreiben müsste.  Eine solche Kaskade kann vom Compiler schlecht optimiert werden.  Aus einem switch über Strings kann der Compiler hingegen einen switch über die Hashcodes der Strings machen, was dann nur noch einen einzigen equals() -Aufruf statt einer Sequenz von Methodenaufrufen erfordert.

Mit herkömmlichen Mitteln wäre die Verzweigung im obigen Beispiel nur mit einer if - else -Kaskade möglich gewesen, in der der variable String state sukzessive mit allen konstanten Strings verglichen wird, bis eine Übereinstimmung gefunden wird.  Das hätte dann etwa so ausgesehen:

    public static void classicStringSwitch(String state) {
        System.out.println("OLD ...");
        final String terminal = "terminated";
        if (state== null)
            System.out.println("No state");
        else if (state.equals("busy") || state.equals(terminal) || state.equals(IDLE))
            System.out.println("Matched state");
        else
            System.out.println("Unknown state");// default
    }
Die vielen Vergleiche mit String.equals() sind ineffizient. Die Implementierung des neue String- switch eliminiert den Overhead indem sie erst über die HashCodes der String verzweigt und danach (bei Bedarf) noch den Vergleich per String.equals() nutzt.  Das heißt, nachem der Compiler den String- switch in Byte-Code übersetzt hat, sieht die Verzweigung sinngemäß so aus:
    public static void newStringSwitch(String state) {
        if(s == null)
            System.out.println("No state");
        String s1 = state;
        byte byte0 = -1;
        switch(s1.hashCode())
        {
        case 3035641:
            if(s1.equals("busy"))
                byte0 = 0;
            break;

        case -1308815837:
            if(s1.equals("terminated"))
                byte0 = 1;
            break;

        case 3227604:
            if(s1.equals("idle"))
                byte0 = 2;
            break;
        }
        switch(byte0)
        {
        case 0:
        case 1:
        case 2:
            System.out.println("Matched state");
            break;

        default:
            System.out.println("Unknown state");
            break;
        }
    }

Der neue String- switch ist also nicht nur übersichtlicher, sondern auch noch effizienter.

Verbessertes Exception Handling

Die Verbesserungen beim Exception Handling bestehen in einer Flexibilisierung beim Rethrow von Exceptions und einer Multi-Catch-Klausel (siehe /MULCAT/).

Flexibilisierung beim Rethrow von Exceptions

Manchmal will man eine catch -Klausel schreiben, in der alle Exceptions – egal von welchem Typ – gefangen werden, damit ein Cleanup gemacht werden kann, und danach wird die ursprüngliche Exception weiter geworfen. In einer solchen catch -Klausel würde man gerne Throwable fangen, um alle Exception-Typen zu erwischen.  Daraus ergibt sich beim Rethrow ein Problem:  der Compiler ist dann nämlich aufgrund der statischen Typinformation Throwable der Meinung, die Methode werfe nun beliebige Exceptions vom Typ Throwable und gibt eine Fehlermeldung aus.  Hier ist ein Beispiel:
    public void someMethod throws SomeSpecificException {
        …
        try {
            doWork(file);  // might throw SomeSpecificException
        } catch (Throwable ex) {
            // some cleanup activity
            throw ex;    // error
        }
        …
    }
_______________________________________________________________________
unreported exception Throwable; must be caught or declared to be thrown
            throw ex;
            ^
In Java 7 werden die Compilerprüfungen dahingehend geändert, dass der Compiler beim Rethrow nicht mehr die statische Typinformation der gefangenen Exception zugrunde legt, sondern davon ausgeht, dass lediglich die Exception-Typen beim Rethrow vorkommen können, die in dem try -Block geworfen werden können.  Das sieht dann so aus:
    public void someMethod throws SomeSpecificException {
        …
        try {
            doWork(file);  // might throw SomeSpecificException
        } catch (Throwable ex) {
            // some cleanup activity
            throw ex;     // fine
        }
        …
    }
Nun muss man die throws -Klausel der Methode nicht mehr ändern und throws Throwable deklararieren, sondern die throws -Klausel der Methode kann wie gewünscht die spezifischen, tatsächlich zu erwartenden Exception-Typen deklarieren.

Allerdings darf man an die Referenzvariable ex im catch -Block nichts zuweisen, wenn man einen Rethrow machen will.  Sobald im catch -Block an die Referenzvariable ex zugewiesen wird, weigert sich der Compiler, einen Rethrow zu akzeptieren.  Der Compiler erkennt nämlich daran, dass der Referenzvariablen im catch -Block  nichts Neues zugewiesen wurde, dass es sich um einen Rethrow der Original-Exception handelt und dass nicht etwa eine andere Exception geworfen wird.  Wenn man eine Zuweisung Referenzvariable im catch -Block macht, dann ist es eben kein Rethrow mehr.

In diesem Fall behandelt der Compiler die Exception dann so, wie früher in Java 6 schon:  er beschwert sich darüber, dass die Methode eine Exception vom Typ Throwable wirft, diesen Exception-Typ aber nicht in ihrer throws -Klausel deklariert hat und dann muss man die throws -Klausel der Methode ändern und throwsThrowable deklararieren.

Man sich sollte deshalb merken, dass die Referenzvariable ex im catch -Block "effectively final" sein muss, wenn man einen Rethrow machen will.  Das heißt, man muss die Variable zwar nicht ausdrücklich als final deklarieren, aber man sollte sie dennoch wie eine final -Variable behandeln.
 

Multi-Catch

Mit dem Multi-Catch soll redundanter Code vermieden werden.  Anstelle von
    public void someMethod throws IOException,InterruptedException {
        …
        try {
            doWork(file);
        } catch (IOException ex) {
            logger.log(ex);
            throw ex;
        }catch (InterruptedException ex) {
            logger.log(ex);
            throw ex;
        }
        …
    }
darf man nun catch -Klauseln mit identischem Code zu einer einzigen Klausel zusammenfassen.  Das sieht dann so aus:
    public void someMethod throws IOException,InterruptedException {
        …
        try {
            doWork(file);
        } catch ( IOException | InterruptedException ex) {
            logger.log(ex);
            throw ex;
        }
        …
    }
Eine weitere Alternative für die Implementierung, die bereits heute genutzt werden kann, sieht so aus:
    public void someMethod throws Exception {
        …
        try {
            doWork(file);
        } catch ( Exception ex) {
            logger.log(ex);
           throw ex;
        }
        …
    }
Der Nachteil ist, dass mehr Exception-Typen gefangen werden, als man eigentlich will.  Zusätzlich wird die Deklaration der throws -Klausel der Methode sehr unspezifisch, da der Exception-Supertyps verwendet werden muss.  Mit dem Multi-Catch entfällt sowohl die Redundanz als auch die unspezifische throws -Klausel.

Es gibt eine Randbedingung bei der Verwendung des neuen Multicatch-Features: die Referenzvariable ex im catch -Block ist "effectively final".  Das heißt, man muss die Variable nicht ausdrücklich als final IOException | InterruptedException ex deklarieren, aber sie wird dennoch wie eine final -Variable behandelt und man darf an diese Variable nichts zuweisen.  Wenn man es trotzdem tut, bekommt man eine Fehlermeldung vom Compiler, die besagt, man dürfe an den Multicatch-Parameter nichts zuweisen.

Automatic Resource Management

Der Vorschlag für eine automatische Unterstützung solcher Klassen, die dynamisch angeforderte Ressourcen verwalten, stammt von Joshua Bloch und ist als ARM (= Automatic Resource Management ) bekannt (siehe /ARM/ und /ARMUPD/).

Damit wird ein Problem gelöst, das schon so alt ist wie Java selbst.  In Java gibt es zwar Konstruktoren, in denen ein Objekt zu Beginn seiner Lebenszeit Ressourcen beschaffen kann, aber es gibt kein gutes Instrument, mit dem das Objekt seine Ressourcen beim Ableben automatisch loswerden könnte.  Die Finalizer haben sich für diesen Zweck als wenig hilfreich erwiesen und so muss sich der Benutzer des Objekts meist selbst darum kümmern, dass die Ressourcen des Objekts freigegeben werden.

Am Beispiel eines Input-Streams sieht es so aus:

String readFirstLineFromFile(String path) throws IOException {
  BufferedReader br = new BufferedReader(new FileReader(path));
  try     { return br.readLine(); }
  finally { br. close (); }
}
Der Benutzer des BufferedReader -Objekts muss dafür sorgen, dass die verwendete Datei wieder geschlossen wird.  Dazu genügt nicht einmal ein einfacher Aufruf von close() am Ende der Methode, sondern der Benutzer benötigt eine finally -Klausel, damit die Datei auch im Falle einer Exception geschlossen wird.

In dieser Situation soll das Automatic Resource Management helfen.  Die Idee besteht darin, dass Klassen mit dynamischen Ressourcen, wie z.B. ein BufferedReader , ein spezielles Interface AutoCloseable implementieren können (und im Fall von JDK Klassen auch tun):

public interface AutoCloseable {
  void close() throws Exception;
}
Eine Klasse, die AutoCloseable implementiert, wird als Resource Type bezeichnet.

Dazu gibt es eine neue Form des try -Blocks, ein sogenanntes "try-with-resources", bei dessen Verlassen automatisch die close() -Methoden aller spezifizierten Resource-Typen aufgerufen werden.  Das sähe zum Beispiel so aus:

String readFirstLineFromFile(String path) throws IOException {
    try ( BufferedReader br = new BufferedReader(new FileReader(path)) ) {
      return br.readLine();
    }
}
Bei diesem Beispiel muss man übrigens aufpassen, wie man die try-with-resources-Klausel gestaltet.  Die folgende Variante wäre ungünstig:
String readFirstLineFromFile(String path) throws IOException {
    try ( FileReader    fin = new FileReader(path);
         BufferedReader br = new BufferedReader(fin) ) {
      return br.readLine();
    }
}
Wenn anstelle von einer Ressource zwei Ressourcen aufgelistet werden, dann wird auch für beide Ressourcen die close() -Methode aufgerufen.  Da aber die close() -Methode von BufferedReader ohnehin bereits die close() -Methode von FileReader aufruft, würde letztere zweimal gerufen.  Das ist in diesem Fall zwar nicht völlig falsch, aber auch nicht besonders sinnvoll.  In anderen Fällen kann es durchaus erwünscht und notwendig sein, dass für jede separat aufgelistete Ressource die jeweilige close() -Methode gerufen wird.  Der Aufruf erfolgt übrigens in umgekehrter Reihenfolge der Deklaration, d.h. die erste Ressource wird als letzte weggeräumt.

Suppressed Exceptions

Bei einem solchen try-with-resources-Konstrukt kann es nun passieren, dass nach einer Exception aus dem try -Block noch eine weitere Exception beim automatischen Aufruf der close() -Methode ausgelöst wird.  Bisher hat eine solche zweite Exception (z.B. aus einem finally -Block) die erste unterdrückt, denn es kann immer nur eine Exception an den Aufrufer der Methode weitergeleitet werden.  Damit keine Information verloren geht, ist die Klasse Throwable um Information über unterdrückte Exceptions ergänzt worden und hat entsprechende Methoden addSuppressed() und getSuppressed() .  Die Method readFirstLineFromFile() im obigen Beispiel würde nun im JDK 7 die erste Exception aus dem try -Block propagieren und diese Exception enthält die zweite unterdrückte Exception aus der close() -Methode.

Ohne try-with-resources sähe es so aus:

void method() throws Exception {
  Resource r = new Resource();
  try { ... does something useful that may raise an exception ...
        throw new Exception("from try block");
  } catch (Exception e) {
        ... does cleanup and re-throws initial exception ...
        throw e;
  } finally {
        r.close();
  }
}
Es würde diejenige Exception weiter propagiert, die von der close() -Methode geworfen wurde.  Eine Exception aus dem try - catch -Konstrukt ginge in einem solchen Falle verloren.

Mit try-with-resources sähe es so aus:

void method() throws Exception {
  try (Resource r = new Resource()) {
     ... does something useful that may raise an exception ...
     throw new Exception("from try block");
  } catch (Exception e) {
     ... does cleanup and re-throws initial exception ...
     throw e;
  }
}
Die c lose() -Methode wird automatisch gerufen.  Wenn sie eine Exception auslöst, dann wird diese Exception in eine zuvor im try -Block ausgelöste Exception als "suppressed exception" eingepackt.  Propagiert würde dann die initiale Exception aus dem try - catch -Konstrukt mit der unterdrückten Exception aus close() im Gepäck.  Auf diese Weise geht keine Exception-Information verloren.

Nun stellt sich die Frage: was passiert eigentlich, wenn ein try-with-resources-Konstrukt eine explizite finally -Klausel hat und darin auch eine Exception geworfen wird?  Hier ist ein Beispiel:

void method() throws Exception {
  try (Resource r = new Resource()) {
     ... does something useful that may raise an exception ...
     throw new Exception("from try block");
  } finally {
     ... does something useful that may raise an exception ...
     throw new Exception("from finally block");
  }
}
Es sind nun drei Exceptions im Spiel: diejenige aus dem try -Block, eine weitere aus der close() -Methode und noch eine dritte aus dem finally -Block.  Welche Exception bekommt der Aufrufer zu sehen?

Da die close() -Methoden aller Ressourcen vor den Anweisungen im finally -Block aufgerufen werden, sind wir wieder in der Situation, in der wir ohne das neue try-with-resources-Konstrukt waren: es wird nur die allerletzte Exception aus dem finally -Block geworfen; die Exception aus dem try -Block mit der eingepackten Exception aus der close() -Methode geht verloren.

Wie ist die Situation, wenn es noch komplizierter wird und es im try-with-resources-Konstrukt sowohl eine catch - als auch eine finally -Klausel gibt?  Im Wesentlichen ist es so wie oben beschrieben:  nach Verlassen des try -Block werden die close() -Methoden der Ressourcen gerufen, danach geht es im catch - und anschließend im finally -Block weiter.

void method() throws Exception {
  try (Resource r = new Resource()) {
     ... does something useful that may raise an exception ...
     throw new Exception("from try block");
  }
                        <= Hier werden die close()-Methoden gerufen.
  catch(Exception e) {
     ... does cleanup and re-throws initial exception ...
     throw e;
  }
  finally {
     ... final work ...
  }
}
Die Exception, die nach einer Exception im try -Block von einer close() -Methode ausgelöst wird, ist als "suppressed exception" in die erste Exception eingepackt.  Wenn sie im catch -Block mit einem Rethrow propagiert wird, dann geht nichts verloren.  Wenn allerdings im catch -Block kein Rethrow gemacht wird, sondern eine andere Exception geworfen wird, dann kommt beim Aufrufer nur diese andere Exception an und der Rest der Exception-Information geht verloren.   Dasselbe passiert, wenn danach im finally -Block noch eine Exception geworfen wird: dann wird nur diese allerletzte Exception weitergegeben und alles andere ist verloren.

Sinnvoll ist also im catch -Block nur

  • der Rethrow der initialen Exception, welche dann automatisch die Exception von einer close() -Methode als unterdrückte Exception mitbringt, oder
  • das Behandeln der initialen Exception; nach der Behandlung wird dann keine Exception mehr propagiert, oder
  • wenn man eine andere als die initiale Exception werfen will, dann sollte man explizit die vorangegangene Exception eingepackt mitliefern.  Das würde man aber nicht als unterdrückte Exception machen, sondern als Ursache, das heißt, man würde den Exception-Chaining-Mechanismus verwenden, den es schon seit Java 1.4 gibt.
Hier ist ein Beispiel:
void method() throws Exception1, Exception2 {
  try (Resource r = new Resource()) {
     ... does something useful that may raise an exception ...
  } catch (Exception1 initialExc) {
     ... does cleanup and re-throws initial exception ...
     throw initialExc;
  }
  catch(Exception2 initialExc) {
     ... handle exception ...
  }
  catch(Exception3 initialExc) {
     ... re-map exception ...
     throw new Exception4(initialExc);
  }
  finally {
     ... final work – no exceptions ...
  }
}
Wenn nun beispielsweise im try -Block eine Exception3 ausgelöst wird, dann wird sie im dritten catch -Block gefangen und abgebildet auf eine Exception4 . Der Aufrufer bekommte diese Exception4 , in der als Ursache (siehe Throwable.getCause() ) die initiale Exception steckt, in der die  unterdrückte Exception von der close() -Methode enthalten ist.
 

Ursache vs. Unterdrückung

Es mag ein wenig verwirrend erscheinen, dass es nun zwei Mechanismen für das Einpacken von Exceptions in andere Exceptions gibt: unterdrückte Exceptions (siehe (siehe Throwable.getSuppressed() ) und die Ursache (siehe Throwable.getCause() ).

Eine unterdrückte Exception wird automatisch erzeugt im Zusammenhang mit dem neuen try-with-resources-Konstrukt. Man kann weitere unterdrückte Exceptions selber hinzufügen mit Throwable.addSuppressed() .  Eine Exception kann also beliebig viele unterdrückte Exceptions enthalten.  Unterdrückte Exceptions entstehen "gleichzeitig" und gehören zur selben Fehlersituation; es handelt sich um einen initialen Fehler und seine Folgefehler.

Eine Ursache hingegen entsteht beim Abbilden einer Exception auf eine andere Exception.  Das ist der Exception-Chaining-Mechanismus, den wir schon seit Java 1.4 kennen und der in geschichteten Architekturen häufig vorkommt.  Die Exception-Kette entsteht nie automatisch, sondern sie muss ausdrücklich hergestellt werden mit Throwable.initCause() oder durch die Benutzung des Exception-Konstruktor.  Dabei enthält jede Exception nur genau eine Ursache, die wiederum genau eine Ursache enthält, usw.  Die Ursachen entstehen "nacheinander" und beschreiben eine Abbildungskette über einen Call-Stack hinweg.
 

Zusammenfassung und Ausblick

In diesem Beitrag haben wir einige der neuen Sprachmittel aus dem Project Coin betrachtet.  Die verbesserten Notationen für numerische Literale sind so naheliegend, dass man sich fragt, warum es sie nicht schon immer gegeben hat. Strings in switch -Anweisungen sorgen für bessere Lesbarkeit des Codes und sind zudem auch noch effizienter als die herkömmlichen Sprachmittel. Die Verbesserungen beim Exception Handling bestehen aus einem Multi-Catch, der redundanten Code beim Exception Handling vermeidet, und einem verbesserten Rethrow, bei dem der Compiler die Exception-Typen automatisch deduziert. Das Automatic Resource Management sorgt dafür, dass für sogenannte Ressource-Typen -die Ressourcen-Freigabe automatisch angestoßen wird und dabei keine Exceptions verloren gehen.  Dazu wurde ein try-with-resources-Konstrukt erfunden und die Exceptions können nun unterdrückte Exceptions enthalten.  Die übrigen Sprachverbesserungen im Zusammenhang mit Generics werden wir im nächsten Artikel besprechen.
 

Literaturverweise

/JSR334/  JSR 334: Small Enhancements to the JavaTM Programming Language
URL: http://jcp.org/en/jsr/detail?id=334
/STRSWT/ String in switch
URL: http://mail.openjdk.java.net/pipermail/coin-dev/2009-February/000001.html
/COIN/  Project Coin/JSR 334 Final Release Specification, v1.0
URL: http://download.oracle.com/otn-pub/jcp/enhancements-1_0-final-eval-spec/enhancements-1_0-final-eval-spec.zip
 

Die gesamte Serie über Java 7:

/JAVA7-1/ Java 7 - Überblick
Klaus Kreft & Angelika Langer, Java Magazin, Juni 2011
URL: http://www.angelikalanger.com/Articles/EffectiveJava/57.Java7.Overview/57.Java7.Overview.html
/JAVA7-2/ JSR 334 - "Project Coin" (Strings in switch, Exception Handling, ARM, numerische Literale)
Klaus Kreft & Angelika Langer, Java Magazin, August 2011
URL: http://www.angelikalanger.com/Articles/EffectiveJava/58.Java7.Coin1/58.Java7.Coin1.html
/JAVA7-3/ JSR 334 - "Project Coin" (Sprachneuerungen im Zusammenhang mit Generics)
Klaus Kreft & Angelika Langer, Java Magazin, Oktober 2011
URL: http://www.angelikalanger.com/Articles/EffectiveJava/59.Java7.Coin2/59.Java7.Coin2.html
/JAVA7-4/ JSR 203 - "NIO2" (Erweiterung der I/O Funktionalität)
Klaus Kreft & Angelika Langer, Java Magazin, Dezember 2011
URL: http://www.angelikalanger.com/Articles/EffectiveJava/60.Java7.NIO2/60.Java7.NIO2.html
/JAVA7-5/ JSR 166y - Fork-Join-Framework (Teil 1: Internals)
Klaus Kreft & Angelika Langer, Java Magazin, Februar 2012
URL: http://www.angelikalanger.com/Articles/EffectiveJava/61.Java7.ForkJoin.1/61.Java7.ForkJoin.1.htm
/JAVA7-6/ JSR 166y - Fork-Join-Framework (Teil 2: Benutzung)
Klaus Kreft & Angelika Langer, Java Magazin, April 2012
URL: http://www.angelikalanger.com/Articles/EffectiveJava/62.Java7.ForkJoin.2/62.Java7.ForkJoin.2.htm
/JAVA7-7/ Thread-Synchronisation mit Hilfe des Phasers
Klaus Kreft & Angelika Langer, Java Magazin, Juni 2012
URL: http://www.angelikalanger.com/Articles/EffectiveJava/63.Java7.Phaser/63.Java7.Phaser.htm

 
 

If you are interested to hear more about this and related topics you might want to check out the following seminar:
Seminar
 
Effective Java - Advanced Java Programming Idioms 
4 day seminar ( open enrollment and on-site)
 
  © Copyright 1995-2013 by Angelika Langer.  All Rights Reserved.    URL: < http://www.AngelikaLanger.com/Articles/EffectiveJava/58.Java7.Coin1/58.Java7.Coin1.html  last update: 24 Jan 2013