Java 11
JDK 11.0.1 verfügbar
Die ersten ersten Updates von Java 11 sind vorhanden: https://jdk.java.net/11/
Java 11 ist draußen
Download unter
- https://www.oracle.com/technetwork/java/javase/downloads/jdk11-downloads-5066655.html
- http://jdk.java.net/11
Unter http://www.tutego.de/java/java-se-11-oracle-jdk-11-openjdk_11_java_18.9.html fasse ich die Neuerungen kompakt zusammen.
Hier im Blog gibt es die Kategorie http://www.tutego.de/blog/javainsel/category/java-11/ für alle Neuerungen in Java 11. Das geht in der Regel ins Buch.
Heise hat eine Java 11-Launch-Session aufgenommen: https://www.youtube.com/watch?v=CUuCVHWeO-Y
Eclipse 4.9 (2018-09) ist fertig, Spring Tool Suite 3.9.6 setzt sofort drauf auf
Heise schreibt recht gut darüber: https://www.heise.de/developer/meldung/Entwicklungsumgebung-Eclipse-Auf-Photon-folgt-2018-09-4168224.html. Leider ist noch ein Java 11-Plugin nötig, so muss ich das im kommenden Java 11-Buch auch extra mit einführen.
Zur STS-Ankündigung: https://spring.io/blog/2018/09/20/spring-tool-suite-3-9-6-released, https://docs.spring.io/sts/nan/v396/NewAndNoteworthy.html
Weißraum entfernen
In einer Benutzereingabe oder Konfigurationsdatei steht nicht selten vor oder hinter dem wichtigen Teil eines Textes Weißraum wie Leerzeichen oder Tabulatoren. Vor der Bearbeitung sollten sie entfernt werden. Die String-Klasse bietet dazu trim() und seit Java 11 strip(), stripLeading() und stripTrailing() an. Der Unterschied:
Methode | Entfernt … |
trim() | … am Anfang und am Ende des Strings alle Codepoints kleiner oder gleich dem Leerzeichen ‚U+0020‘ |
strip() | … alle Zeichen am Anfang und am Ende des Strings, die nach der Definition von Character.isWhitespace(int) Leerzeichen sind |
stripLeading() | … wie strip(), allerdings nur am Anfang des Strings |
stripTrailing() | … wie strip(), allerdings nur am Ende des Strings |
Unterschiede von trim() und stripXXX()
Alle vier Methoden entfernen keinen Weißraum inmitten des Strings.
Beispiel: Entferne Leer- und ähnliche Füllzeichen am Anfang und Ende eines Strings:
String s = “ \tSprich zu der Hand.\n \t „;
System.out.println( „‚“ + s.trim() + „‚“ ); // ‚Sprich zu der Hand.‘
Beispiel: Teste, ob ein String mit Abzug allen Weißraums leer ist:
boolean isBlank = „“.equals( s.trim() );
Alternativ:
boolean isBlank = s.trim().isEmpty();
Strings aus Wiederholungen generieren
In Java 11 ist eine Objektmethode repeat(int count) eingezogen, die einen gegeben String vervielfacht.
Beispiel: Wiederhole den String s dreimal:
String s = „tu“;
System.out.println( s.repeat( 3 ) ); // tututu
Bevor es die Methode in Java 11 gab, sah eine alternative Lösung etwa so aus:
int n = 3;
String t = new String( new char[ n ] ).replace( „\0“, s );
System.out.println( t ); // tututu
String-Länge und Test auf Leer-String
String-Objekte verwalten intern die Zeichenreihe, die sie repräsentieren, und bieten eine Vielzahl von Methoden, um die Eigenschaften des Objekts preiszugeben. Eine Methode haben wir schon benutzt: length(). Für String-Objekte ist sie so implementiert, dass sie die Anzahl der Zeichen im String (die Länge des Strings) zurückgibt. Um herauszufinden, ob der String keine Zeichen hat, lässt sich neben length() == 0 auch die Methode isEmpty() nutzen. In Java 11 ist die Methode isBlank() hinzugekommen, die testet, ob der String leer ist, oder nur aus Weißraum besteht; Weißraum ist jedes Zeichen, bei dem Character.isWhitespace(int) wahr anzeigt.
Anweisung | Ergebnis |
„“.length() | 0 |
„“.isEmpty() | true |
“ „.length() | 1 |
“ „.isEmpty() | false |
“ „.isBlank() | true |
String s = null; s.length(); | NullPointerException |
Tabelle 1.1: Ergebnisse der Methoden length(), isEmpty() und isBlank()
Vom Zeichen zum String
Um ein Unicode-Zeichen ein einen String zu konvertieren können wir die statische überladene String-Methode valueOf(char) nutzen. Eine vergleichbare Methode gibt es auch in Character, und zwar die statische Methode toString(char). Beide Methoden haben die Einschränkung, dass das Unicode-Zeichen nur 2 Byte lang sein kann. String deklariert dafür auch valueOfCodePoint(int). So eine Methode fehlte bisher in Character; erst in Java 11 ist toString(int) eingezogen; intern delegiert sie an valueOfCodePoint(int).
Statische compare(…)-Methode in CharSequence
Seit Java 11 gibt es in CharSequence eine neue Methode compare(…), die zwei CharSequence-Objekte lexikografisch vergleicht.
interface java.lang.CharSequence
- static int compare(CharSequence cs1, CharSequence cs2)
Vergleicht die beiden Zeichenketten lexikografisch.
Die statische Methode hat den Vorteil, dass nun alle Kombination von CharBuffer, Segment, String, StringBuffer, StringBuilder mit nur dieser einen Methode geprüft werden können. Und wenn der Vergleich 0 ergibt, so wissen wir auch, dass die Zeichenfolgen die gleichen Zeichen enthalten.
Vergleichen von StringBuilder-Exemplaren und String mit StringBuilder
Zum Vergleichen von Strings bietet sich die bekannte equals(…)-Methode an. Diese ist aber bei StringBuilder nicht wie erwartet implementiert. Dazu gesellen sich andere Methoden, die zum Beispiel unabhängig von der Groß-/Kleinschreibung vergleichen.
equals(…) bei der String-Klasse
Die Klasse String implementiert die equals(Object)-Methode, sodass ein String mit einem anderen String verglichen werden kann. Allerdings vergleich equals(Object) von String nur String/String-Paare. Die Methode beginnt erst dann den Vergleich, wenn das Argument auch vom Typ String ist. Das bedeutet, dass der Compiler alle Übergaben auch vom Typ StringBuilder bei equals(Object) zulässt, doch zur Laufzeit ist das Ergebnis immer false, da eben ein StringBuilder nicht vom Typ String ist. Ob die Zeichenfolgen dabei gleich sind, spielt keine Rolle.
contentEquals(…) beim String
Eine allgemeine Methode zum Vergleichen eines Strings mit entweder einem anderen String oder mit StringBuilder ist contentEquals(CharSequence). Die Methode liefert die Rückgabe true, wenn der String und die CharSequence (String, StringBuilder und StringBuffer sind Klassen vom Typ CharSequence) den gleichen Zeicheninhalt haben. Die interne Länge des Puffers spielt keine Rolle. Ist das Argument null, wird eine NullPointerException ausgelöst.
Beispiel: Vergleiche einen String mit einem StringBuilder:
String s = „Elektrisch-Zahnbürster“;
StringBuilder sb = new StringBuilder( „Elektrisch-Zahnbürster“ );
System.out.println( s.equals(sb) ); // false
System.out.println( s.equals(sb.toString()) ); // true
System.out.println( s.contentEquals(sb) ); // true
Kein eigenes equals(…) bei StringBuilder
Wollen wir zwei StringBuilder-Objekte miteinander vergleichen, so geht das nicht mit der equals(…)-Methode. Es gibt zwar die übliche von Object geerbte Methode, doch das heißt, nur Objektreferenzen werden verglichen. Anders gesagt: StringBuilder überschreibt die equals(…)-Methode nicht. Wenn also zwei verschiedene StringBuilder-Objekte mit gleichem Inhalt mit equals(…) verglichen werden, kommt trotzdem immer false heraus.
Beispiel: Um den inhaltlichen Vergleich von zwei StringBuilder-Objekten zu realisieren, können wir sie erst mit toString() in Strings umwandeln und dann mit String-Methoden vergleichen:
StringBuilder sb1 = new StringBuilder( „The Ocean Cleanup“ );
StringBuilder sb2 = new StringBuilder( „The Ocean Cleanup“ );
System.out.println( sb1.equals( sb2 ) ); // false
System.out.println( sb1.toString().equals( sb2.toString() ) ); // true
System.out.println( sb1.toString().contentEquals( sb2 ) ); // true
StringBuilder ist Comparable
Seit Java 11 bietet StringBuilder eine Methode int compareTo(StringBuilder another) sodass lexikografische Vergleiche möglich sind. (StringBuilder implementiert die Schnittstelle Comparable<StringBuilder>.) Somit realisieren String und StringBuilder beide eine Ordnung, siehe „Lexikografische Vergleiche mit Größer-kleiner-Relation“.
Eine Begleiterscheinung ist die Tatsache, dass bei gleichen Zeichenfolgen die Rückgabe von compareTo(…) gleich 0 ist. Das ist deutlich besser als erst den StringBuilder in einen String zu konvertieren.
Beispiel:
StringBuilder sb1 = new StringBuilder( „The Ocean Cleanup“ );
StringBuilder sb2 = new StringBuilder( „The Ocean Cleanup“ );
System.out.println( sb1.compareTo( sb2 ) == 0 ); // true
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.
Files: Einfaches Einlesen und Schreiben von Dateien
Mit den Methoden readAllBytes(…), readAllLines(…), readString(…), lines(…)und write(…) und writeString(..) kann Files einfach einen Dateiinhalt einlesen oder Strings bzw. ein Byte-Feld schreiben.
URI uri = ListAllLines.class.getResource( „/lyrics.txt“ ).toURI();
Path p = Paths.get( uri );
System.out.printf( „Datei ‚%s‘ mit Länge %d Byte(s) hat folgende Zeilen:%n“,
p.getFileName(), Files.size( p ) );
int lineCnt = 1;
for ( String line : Files.readAllLines( p ) )
System.out.println( lineCnt++ + „: “ + line );
final class java.nio.file.Files
- staticbyte[]readAllBytes(Pathpath)throwsIOException
Liest die Datei komplett in ein Byte-Feld ein. - staticList<String>readAllLines(Pathpath)throwsIOException
- staticList<String>readAllLines(Pathpath,Charsetcs)throwsIOException
Liest die Datei Zeile für Zeile ein und liefert eine Liste dieser Zeilen. Optional ist die Angabe einer Kodierung, standardmäßig ist es UTF_8. - static String readString(Path path) throws IOException
- static String readString(Path path, Charset cs) throws IOException
Liest eine Datei komplett aus und liefert den Inhalt als String. Ohne Kodierung gilt standardmäßig UTF-8. Beide Methoden neu in Java 11. - staticPathwrite(Pathpath,byte[]bytes,..options)throwsIOException
Schreibt ein Byte-Array in eine Datei. - staticPathwrite(Pathpath,Iterable<?extendsCharSequence>lines,..
options) throws IOException - staticPathwrite(Pathpath,Iterable<?extendsCharSequence>lines,Charsetcs,
.. options) throws IOException
Schreibt alle Zeilen aus dem Iterable in eine Datei. Optional ist die Kodierung, die StandardCharsets.UTF_8 ist, so nicht anders angegeben. - static Path writeString(Path path, CharSequence csq, OpenOption… options) throws IOException
- static Path writeString(Path path, CharSequence csq, Charset cs, OpenOption… options) throws IOException
Schreibt eine Zeichenfolge in die genannte Datei. Der übergebene path wird zurückgegeben. Ohne Kodierung gilt standardmäßig UTF-8. Beide Methoden neu in Java 11.
Die Aufzählung OpenOption ist ein Vararg, und daher sind Argumente nicht zwingend nötig. StandardOpenOption ist eine Aufzählung vom Typ OpenOption mit Konstanten wie APPEND, CREATE usw.
Beispiel: Lies eine UTF-8-kodierte Datei ein:
String s = Files.readString( path );
Bevor die praktische Methode in Java 11 einzog, sah eine Alternative so aus:
String s = new String( Files.readAllBytes( path ), StandardCharsets.UTF_8 );
Hinweis: Auch wenn es naheliegt, die Files-Methode zum Einlesen mit einem Path-Objekt zu füttern, das einen HTTP-URI repräsentiert, funktioniert dies nicht. So liefert schon die erste Zeile des Programms eine Ausnahme des Typs »java.nio.file.FileSystemNotFoundException: Provider ›http‹ not installed«.
URI uri = new URI( „http://tutego.de/javabuch/aufgaben/bond.txt“ );
Path path = Paths.get( uri ); //
List<String> content = Files.readAllLines( path );
System.out.println( content );
Vielleicht kommt in der Zukunft ein Standard-Provider von Oracle, doch es ist davon auszugehen, dass quelloffene Lösungen diese Lücke schließen werden. Schwer zu programmieren sind Dateisystem-Provider nämlich nicht.
Prädikate aus java.util.regex.Pattern
Die Pattern-Methoden asPredicate() und asMatchPredicate() (ab Java 11) liefern ein Predicate<String>, sodass ein regulärer Ausdruck als Kriterium, zum Beispiel zum Filtern oder Löschen von Einträgen in Datenstrukturen, genutzt werden kann.
Es unterscheiden sich die Methoden wie folgt:
Methode | Implementierung |
Predicate<String> asPredicate() | return s -> matcher(s).find() |
Predicate<String> asMatchPredicate() | return s -> matcher(s).matches(); |
asPredicate() matcht bei einem Teilstring, asMatchPredicate() den gesamten String
Beispiel: Lösche aus einer Liste alle Strings, die leer sind oder Zahlen enthalten:
List<String> list = new ArrayList<>( Arrays.asList( "", "69cool", "1898", "Sisi" ) ); list.removeIf( Pattern.compile( "\\d+" ).asPredicate().or( String::isEmpty ) ); System.out.println( list ); // [Sisi] Ändern wir asPredicate() in asMatchPredicate() ist die Ausgabe [69cool, Sisi].
Java 11 wird weiter entschlackt, Pack200 und Nashorn raus?
Siehe
JEP 335: Deprecate the Nashorn JavaScript Engine
http://openjdk.java.net/jeps/335
http://mail.openjdk.java.net/pipermail/jdk-dev/2018-June/001338.html
und
JEP 336: Deprecate the Pack200 Tools and API
http://openjdk.java.net/jeps/336
http://mail.openjdk.java.net/pipermail/jdk-dev/2018-June/001358.html
Neuer JDK 11 Early-Access Builds, JavaFX fliegt aus Java 11
Download und Details unter http://jdk.java.net/11/. Änderungen unter https://download.java.net/java/early_access/jdk11/14/jdk-11+14.html.
- https://bugs.openjdk.java.net/browse/JDK-8201593
- http://hg.openjdk.java.net/jdk/jdk/rev/92560438d306e2a3084f1dce917d0f9af5796aa9
Im Projekt http://jdk.java.net/openjfx/ (openjfx-11-ea+13 vom 9. 5. 2018) wird JavaFX weiterentwickelt.
jdk-11-ea+2 freigegeben
Die größte Änderung ist, was angekündigt wurde:
These builds include JEP 320 (Remove the Java EE and CORBA Modules) [1], so they're significantly smaller (nine fewer modules, 22 fewer megabytes on Linux/x64). - Mark
Weitere Infos und Download unter http://jdk.java.net/11/. Folgende Änderungen gibt es:
Changeset | Bug ID | Synopsis |
d9fce53461a1 | 8197812 | (ref) Data race in Finalizer |
c38163717870 | 8198227 | Fix COMPARE_BUILD after forest consolidation |
329428e095b6 | 8198306 | Add post custom extension hooks to two launchers |
67cdc215ed70 | 8198228 | Spec clarification: j.u.Locale.getDisplayName() |
edaa989b4e67 | 8058965 | Remove IPv6 support from TwoStacksPlainSocketImpl [win] |
01237b276b8b | 8198318 | Make build comparisons clean again |
7f9c3cd11e97 | 8170120 | jimage throws IOException when the given file is not a jimage file |
0a185d6fafa1 | 8198379 | tools/jimage/JImageListTest.java failing |
b417304c811b | 8198380 | tools/jimage/JImageExtractTest.java failing |
42cec55157fa | 8198417 | Exclude tools/jimage/JImageExtractTest.java and tools/jimage/JImageListTest.java on Windows |
37beaca49e63 | 8194922 | jlink –exclude-resources should never exclude module-info.class |
18debf414948 | 8198425 | make/Main.gmk Add extra extension/override points to the make file |
c7e84c0a51c3 | 8198328 | Create devkit for Solaris with developer studio 12.6 and Solaris11.3 |
916690b5edc9 | 8194892 | add compiler support for local-variable syntax for lambda parameters |
576e024f10b6 | 8198418 | Invoke LambdaMetafactory::metafactory exactly from the BootstrapMethodInvoker |
906025796009 | 8198441 | Replace native Runtime::runFinalization0 method with shared secrets |
b75c9e2e3b1f | 8198450 | Make jdk.internal.vm.compiler/module-info.java.extra reproducable |
1913e7fc6be9 | 8198301 | jdk11+1 was built as ‚fcs‘ instead of ‚ea‘ |
b2bba53b079d | 8198303 | jdk11+1 was build with incorrect GA date as 2018-03-20 |
02404e27d356 | 8198479 | JDK build is broken by 8194892 |
847a988152b8 | 8194154 | System property user.dir should not be changed |
cc30928a834e | 8198385 | Remove property sun.locale.formatasdefault |
28d8fc8cd3cd | 8190904 | Incorrect currency instance returned by java.util.Currency.getInstance() |
b1a5b4ad7427 | 8198523 | Refactor BootstrapMethodInvoker to further avoid runtime type checks |
b25eb74ec283 | 8197439 | Crash with -XDfind=lambda for anonymous class in anonymous class. |
9e3f2ec326ba | 8198502 | Exception at runtime due to lambda analyzer reattributes live AST |
20358c9f72c1 | 8198563 | Test langtools/tools/javac/analyzer/AnonymousInAnonymous.java failing after JDK-8198502 |
03ae177c26b0 | 8198512 | compiler support for local-variable syntax for lambda parameters |
Release Notes Since build 1 Integrations
ThreadPoolExecutor should not specify a dependency on finalizationPrevious versions of ThreadPoolExecutor had a finalize method that shut down the thread pool, but in this version the finalize method does nothing. This should have no visible effect unless a subclass explicitly invokes the finalize method and relies on the executor being shutdown.
jarsigner should print when a timestamp will expireThe jarsigner tool now shows more information about the lifetime of a timestamped JAR. New warning and error messages are displayed when a timestamp has expired or is expiring within one year.