Diamant vs. var

Diamant und var haben vergleichbare Aufgaben, unterscheiden sich aber durch die Quelle der Informationen. Beim Diamanten ist es zum Beispiel bei einer Zuweisung die linke Seite, die dem Compiler die Information gibt, was auf der rechten Seite der Zuweisung für ein Typ gemeint ist. Bei var wiederum ist das anderes herum: die rechte Seite hat den Kontext und daher kann links der Variablentyp entfallen:

List<String> list1 = new ArrayList<>();  // List<String>

var list2 = new ArrayList<String>();     // ArrayList<String>

var list3 = new ArrayList<>();           // ArrayList<Object>

Im letzten Fall gibt es keinen Compilerfehler, nur ist eben nichts bekannt über das Typargument, und daher gilt Object.

Um Code abzukürzen haben wir damit zwei Möglichkeiten: var oder Diamond.

Mit ByteArrayOutputStream in ein Byte-Feld schreiben

Ein ByteArrayOutputStream ist ein OutputStream, der die geschriebenen Daten intern in einem byte-Array speichert. Die Größe des Arrays vergrößert sich dynamisch zu den geschriebenen Daten.

class java.io.ByteArrayOutputStream
extends OutputStream

  • ByteArrayOutputStream()
    Erzeugt ein neues OutputStream-Objekt, das die Daten in einem internen Byte-Array abbildet.
  • ByteArrayOutputStream(intsize)
    Erzeugt ein ByteArrayOutputStream mit einer gewünschten anfänglichen Pufferkapazität.

Als OutputStream erbt der ByteArrayOutputStream alle Methoden, die jedoch allesamt eine IOException auslösen. Bei einem Strom der in den Speicher schreibt kann das nicht passieren. Daher wurde in Java 11 eine neue Methode writeBytes(byte[]) eingeführt, die keine IOException auslöst.

Mit die wichtigste Methode ist toByteArray(), die ein byte[] mit dem geschriebenen Inhalt liefert. reset() löscht den internen Puffer. Eine praktische Methode ist writeTo(OutputStream out). Hinter ihr steckt ein out.write(buf, 0, count), das für uns in das nicht sichtbare interne Feld buf schreibt. Es gibt drei toString(…)-Methoden, die das Byte-Array in einen String konvertieren: toString(String charsetName) und toString​(Charset charset) – seit Java 10 – bekommen als Argument die Zeichenkodierung übergeben und ByteArrayOutputStream überschreibt toString() von der Oberklasse Object was die Standard Plattform-Zeichenkodierung nimmt.

Automatisches Feststellen der Typen mit var

Java 10 hat eine Erweiterung gebracht, dass der Variablentyp bei gewissen Deklarationen entfallen kann und wir einfach stattdessen var nutzen können:

var name = „Barack Hussein Obama II“;

var age = 48;

var income = 400000;

var gender = ‚m‘;

var isPresident = false;

Wir sehen, dass im Gegensatz zu unserem vorherigen Beispiel nicht mehr die Variablentypen wie String oder int bei der Variablendeklaration explizit im Code stehen, sondern nur noch var. Das heißt allerdings nicht, dass der Compiler die Typen offen lässt! Der Compiler braucht zwingend die rechte Seite neben dem Gleichheitszeichen, um den Typ feststellen zu können, das nennt sich Local-Variable Type Inference. Daher gibt es in unserem Programm auch eine Unstimmigkeit, nämlich bei var income = 400000, die gut ein Probleme mit var aufzeigt: die Variable ist kein double mehr wie vorher, sondern 400000 ist ein Ganzzahl-Literal, weshalb der Java-Compiler der Variablen income den Typ int gibt.

Die Nutzung von var soll Entwicklern helfen, Code kürzer zu schreiben, insbesondere, wenn der Variablenname schon eindeutig auf den Typ hinweist. Finden wie eine Variable text vor, ist der Typ String naheliegend, genauso wie age ein int ist, oder ein Präfix wie is oder has auf eine boolean-Variable hinweist. Aber wenn var auf die Kosten der Verständlichkeit geht, darf die Abkürzung nicht eingesetzt werden. Auch der Java-Compiler gibt Schranken:

  • var ist nur dann möglich, wenn eine Initialisierung einen Typ vorgibt. Eine Deklaration der Art var age; ohne Initialisierung ist nicht möglich und führt zu einem Compilerfehler.
  • var kann nur bei lokalen Variablen eingesetzt werden, wo der Bereich überschaubar ist. Es gibt aber noch viele weitere Stellen, wo in Java Variablen deklariert werden – dort ist var nicht möglich.

Sprachvergleich: Java ist mit var relativ spät dran.[1] Andere statisch getypte Sprachen bieten die Möglichkeit schon länger, etwa C++ mit auto oder C# auch mit var. Auch JavaScript nutzt var, allerdings in einem völlig anderen Kontext: in JavaScript sind Variablen erst zur Laufzeit getypt, und alle Operationen werden erst zur Ausführungszeit geprüft, während Java die Typsicherheit mit var nicht aufgibt.

[1] http://openjdk.java.net/jeps/286

Herunterladen der JDK 10 Early-Access Builds

Das ist unter http://jdk.java.net/10/ möglich. Die Javadoc liegt unter https://download.java.net/java/jdk10/docs/api/overview-summary.html. Release Notes unter http://jdk.java.net/10/release-notes

Interessanter ist:

tools/javadoc(tool)

 Provide a new comment tag to specify the summary of an API description.

By default, the summary of an API description is inferred from the first sentence, which is determined by using either a simple algorithm or java.text.BreakIterator. But, the heuristics are not always correct, and can lead to incorrect determination of the end of the first sentence. A new inline tag {@summary ...} is now available, to explicitly specify the text to be used as the summary of the API description. Please refer to Documentation Comment Specification for the Standard Doclet.

security-libs/java.security

 Remove policytool

The policytool security tool has been removed from the JDK.

Auch Eclipse kann mittlerweile schon zumindest Java 10 im Dialog einstellen, einige Updates wurden gemacht, siehe https://bugs.eclipse.org/bugs/show_bug.cgi?id=529875.

Feature-Release vs. zeitorientiertes Release (ab Java 10)

20 Jahre lang bestimmten Features die Freigabe von neuen Java-Versionen; die Entwickler setzten bestimmte Neuerungen auf die Wunschliste, und wenn alle Features realisiert und getestet waren, erfolgte die allgemeine Verfügbarkeit (eng. general availability, kurz GA). Hauptproblem dieses Feature-basierten Vorgehensmodells waren die Verzögerungen, die mit Problemen bei der Implementierung einhergingen. Vieldiskutiert war das Java 9-Release, weil es unbedingt ein Modulsystem enthalten sollte.

Die Antwort auf diese Probleme, und der Wusch der Java-Community nach häufigeren Releases, beantwortet Oracle mit der „JEP 322: Time-Based Release Versioning“[1]. Vier Releases sind im Jahr geplant:

  • Im März und September erscheinen Haupt-Releases, wie Java 10, Java 11.
  • Updates erscheinen einen Monat nach einem Haupt-Release und dann im Abstand von drei Monaten. Im April und Juli erscheinen folglich Updates 10.0.1 und 10.0.2. Für Java 11 wären das Oktober 2018 und Januar 2019.

Anders gesagt: Im Halbjahresrhythmus gibt es Updates, die es Oracle erlauben, in der schnelllebigen IT-Zeit die Bibliotheken weiter zu entwickeln und neue Spracheigenschaften zu integrieren. Kommt es zu Verzögerungen, hält das nicht gleich das ganze Release auf. Java 10 erscheint als erste Version im März 2018 nach diesem Modell.[2]

[1]      http://openjdk.java.net/jeps/322

[2] http://openjdk.java.net/projects/jdk/10/

JEP Draft für „Raw String Literals“ in Java

In der Diskussion ist der „Back-Tick“, sodass es so aussehen würde:

File Paths Example

Traditional String Literals Raw String Literals
Runtime.getRuntime().exec("\"C:\\Program Files\\foo\" bar");
Runtime.getRuntime().exec(`"C:\Program Files\foo" bar"`);

Multi-line Example

Traditional String Literals Raw String Literals
String html = "<html>\n"
              "    <body>\n" +
              "		    <p>Hello World.</p>\n" +
              "    </body>\n" +
              "</html>\n";
String html = `<html>
                   <body>
                       <p>Hello World.</p>
                   </body>
               </html>
              `;

Regular Expression Example

Traditional String Literals Raw String Literals
System.out.println("this".matches("\\w\\w\\w\\w"));
System.out.println("this".matches(`\w\w\w\w`));

Output:

true

Polyglot Example

Traditional String Literals Raw String Literals
String script = "function hello() {\n" +
                "   print(\'\"Hello World\"\');\n" +
                "}\n" +
                "\n" +
                "hello();\n";
ScriptEngine engine = new ScriptEngineManager().getEngineByName("js");
Object obj = engine.eval(script);
String script = `function hello() {
                    print('"Hello World"');
                 }
hello();
            `

ScriptEngine engine = new ScriptEngineManager().getEngineByName(„js“); Object obj = engine.eval(script);

Output:

"Hello World"

Database Example

Traditional String Literals Raw String Literals
String query = "SELECT EMP_ID, LAST_NAME\n" +
               "FROM EMPLOYEE_TBL\n" +
               "WHERE CITY = 'INDIANAPOLIS'\n" +
               "ORDER BY EMP_ID, LAST_NAME;\n";
String query = `SELECT EMP_ID, LAST_NAME
                FROM EMPLOYEE_TB
                WHERE CITY = 'INDIANAPOLIS'
                ORDER BY EMP_ID, LAST_NAME;
               `;

Ich bin gespannt, ob das in Java 10 kommen wird. Ich dachte schon, dass Java 10 Release wird eher klein, doch zusammen mit den var-Variablen sind das zwei kleine, aber bedeutende Sprachänderungen.

Details unter http://openjdk.java.net/jeps/8196004.

Aktuelles zu Java 10

Nach Java 9 wird uns Java 10 beglücken. Die Zeitleiste sieht so aus:

2017/12/14 Rampdown Phase One
2018/01/11 All Tests Run
2018/01/18 Rampdown Phase Two
2018/02/22 Final Release Candidate
2018/03/20 General Availability

Java 10 ist laut http://openjdk.java.net/projects/jdk/10/ ab heute in der „Rampdown Phase One“ (http://openjdk.java.net/projects/jdk8/milestones#Rampdown_start):

  • Rampdown — Phases in which increasing levels of scrutiny are applied to incoming changes. In phase 1, only P1-P3 bugs can be fixed. In phase 2 only showstopper bugs can be fixed.

Neuerungen dir wir für Java 10 erwarten können, beschrieben im JEP:

286: Local-Variable Type Inference
296: Consolidate the JDK Forest into a Single Repository
304: Garbage-Collector Interface
307: Parallel Full GC for G1
310: Application Class-Data Sharing
312: Thread-Local Handshakes
313: Remove the Native-Header Generation Tool (javah)
314: Additional Unicode Language-Tag Extensions
316: Heap Allocation on Alternative Memory Devices
317: Experimental Java-Based JIT Compiler
319: Root Certificates
322: Time-Based Release Versioning

Es wird auch Java 10, Java 11, usw. heißen und nicht, wie vorher angedacht, Java 18, etc. nach Jahreszahlen. Aus dem http://openjdk.java.net/jeps/322:

  • $FEATURE is incremented every six months: The March 2018 release is JDK 10, the September 2018 release is JDK 11, and so forth.