jdep: Paket-Abhängigkeiten anzeigen, neues Tool für Java 8 in Planung

http://mail.openjdk.java.net/pipermail/core-libs-dev/2012-December/012684.html. Aufruf:

$ jdep -h
Usage: jdeps <options> <files....>
where possible options include:
   -version                 Version information
   -classpath <path>        Specify where to find class files
   -summary                 Print dependency summary only
   -v:class                 Print class-level dependencies
   -v:package               Print package-level dependencies
   -p <package name>        Restrict analysis to classes in this package
                            (may be given multiple times)
   -e <regex>               Restrict analysis to packages matching pattern
                            (-p and -e are exclusive)
   -P  --profile            Show profile or the file containing a package
   -R  --recursive          Traverse all dependencies recursively
   -all                     Process all classes specified in -classpath

$ jdep Notepad.jar Ensemble.jar
Notepad.jar -> D:\tools\devtools\jdk8\windows-i586\jre\lib\rt.jar
<unnamed> (Notepad.jar)
       -> java.awt
       -> java.awt.event
       -> java.beans
       -> java.io
       -> java.lang
       -> java.net
       -> java.util
       -> java.util.logging
       -> javax.swing
       -> javax.swing.border
       -> javax.swing.event
       -> javax.swing.text
       -> javax.swing.tree
       -> javax.swing.undo

Ensemble.jar -> D:\tools\devtools\jdk8\windows-i586\jre\lib\jfxrt.jar
Ensemble.jar -> D:\tools\devtools\jdk8\windows-i586\jre\lib\rt.jar
    com.javafx.main (Ensemble.jar)
       -> java.applet
       -> java.awt
       -> java.awt.event
       -> java.io
       -> java.lang
       -> java.lang.reflect
       -> java.net
       -> java.security
       -> java.util
       -> java.util.jar
       -> javax.swing
       -> sun.misc                                 JDK internal API (rt.jar)

Thema der Woche: Servlet-Filter

Was Nordkorea kann, können wir auch. Lies zur Einleitung http://www.spiegel.de/netzwelt/web/html-trick-nordkorea-macht-seinen-fuehrer-groesser-a-872291.html, um eine Idee zu bekommen, was wir vorhaben.

Lege in der IDE ein Web-Projekt an. Setze eine index.jsp in das Wurzelverzeichnis mit Text, der den Namen “Kim Jong Un” enthält (alternativ “Angela Merkel”; je nachdem, wer einem sympathischer ist). Teste die Seite.

Lies http://www.oracle.com/technetwork/java/filters-137243.html und verstehe das Konzept der Filter. Der Code ist mit den Eintragungen in die web.xml nicht mehr ganz aktuell, den letzten Teil kann man daher überspringen.

Kopiere http://www.roseindia.net/java/javaee6/webFilterExample.shtml und probiere es aus. Das Beispiel nutzt die Annotationen aus der aktuellen Servlet-Spezifikation.

Ändere den Filter, so dass er den Namen unseres gewählten Staatsoberhaupts größer setzt. Wie das realisiert ist, ist im Prinzip egal, die einfachster Lösung ist Ok (etwa mit <font size=+1>name</font>).

Java-Versionen gehen mit Unicode-Standard Hand in Hand

In den letzten Jahren hat sich der Unicode-Standard erweitert, und Java ist den Erweiterungen gefolgt.

Java-Version

Unicode-Version

1.0

1.1.5

1.1

2.0

1.1.7

2.1

1.2, 1.3

2.1

1.4

3.0

5

4.0

6

4.0

7

6.0

8

6.2

Java-Versionen und ihr unterstützter Unicode-Standard

Die Java-Versionen von 1.0 bis 1.4 nutzen einen Unicode-Standard, der für jedes Zeichen 16 Bit reserviert. So legt Java jedes Zeichen in 2 Byte ab und ermöglicht die Kodierung von mehr als 65.000 Zeichen aus dem Bereich U+0000 bis U+FFFF. Der Bereich heißt auch BMP (Basic Multilingual Plane). Java 5 unterstützt erstmalig den Unicode 4.0-Standard, der 32 Bit (also 4 Byte) für die Abbildung eines Zeichens nötig macht. Doch mit dem Wechsel auf Unicode 4 wurde nicht die interne Länge für ein Java-Zeichen angehoben, sondern es bleibt dabei, dass ein char 2 Byte groß ist. Das heißt aber auch, dass Zeichen, die größer als 65.536 sind, irgendwie anders kodiert werden müssen. Der Trick ist, ein ein »großes« Unicode-Zeichen aus zwei chars zusammenzusetzen. Dieses Pärchen aus zwei 16-Bit-Zeichen heißt Surrogate-Paar. Sie bilden in der UTF-16-Kodierung ein Unicode 4.0-Zeichen. Diese Surrogate vergrößern den Bereich der Basic Multilingual Plane.

Mit der Einführung von Unicode 4 unter Java 5 gab es an den Klassen für Zeichen- und Zeichenkettenverarbeitung einige Änderungen, sodass etwa eine Methode, die nach einem Zeichen sucht, nun nicht nur mit einem char parametrisiert ist, sondern auch mit int, und der Methode damit auch ein Surrogate-Paar übergeben werden kann. In diesem Buch spielt das aber keine Rolle, da Unicode-Zeichen aus dem höheren Bereichen, etwa für die phönizische Schrift, die im Unicode-Block U+10900 bis U+1091F liegt – also kurz hinter 65536, was durch 2 Byte abbildbar ist –, nur für eine ganz kleine Gruppe von Interessenten wichtig sind.

Statische sum(…)/max(…)/min(…) Methoden in numerischen Wrapper-Klassen

In den numerischen Wrapper-Klassen, also Byte, Short, Integer, Long, Float, Double und auch Character – obwohl Character nicht die Basisklasse Number erweitert – gibt es seit Java 8 je drei neue Methoden: sum(…)/max(…)/min(…), die genau das machen, was der Methodenname verspricht.

final class java.lang.Byte|Short|Integer|Long|Float|Double
extends Number
implements Comparable<Integer>

§ static Typ sum(Typ a, Typ b)
Bildet die Summe zweier Werte und liefert diese zurück. Es entspricht einem einfachen a + b. Die Angabe Typ steht dabei für den entsprechenden primitiven Typ byte short, int, long, float oder double, etwa in int sum(int a, int b).

§ static Typ min(Typ a, Typ b)
Liefert das Minimum der zwei Zahlen.

§ static Typ max(Typ a, Typ b)
Liefert das Maximum der zwei Zahlen.

final class java.lang.Character
implements Comparable<Character>, Serializable

§ static Typ sum(Typ a, Typ b)
Liefert (char)(a + b) zurück.

§ static Typ min(Typ a, Typ b)
Liefert das kleinere der beiden Zeichen bezüglich der Unicode-Position.

§ static Typ max(Typ a, Typ b)
Liefert das größere der beiden Zeichen.

Die Methoden sich für sich genommen nicht spannend. Für die Summe (Addition) tut es genauso gut der +-Operator – er steckt sowieso hinter den sum(…)-Methoden – und so wird keiner auf die Idee kommen i = Integer.sum(i, 1) statt i++ zu schreiben. Für das Maximum/Minimum bietet die Math-Klasse auch schon entsprechende Methoden min(a,b)/max(a,b). Der Grund für diese drei Methoden ist vielmehr, dass sie im Zusammenhang mit Lambda-Ausdrücken interessant sind – dazu später mehr.

Java 8: Division mit Rundung Richtung negativ unendlich

Die Ganzzahldivision in Java ist simpel gestrickt. Vereinfacht ausgedrückt: Konvertiere die Ganzzahlen in Fließkommazahlen, führe die Division durch und schneide alles hinter dem Komma ab. So ergeben zum Beispiel 3 / 2 = 1 und 9 / 2 = 4. Bei negativem Ergebnis, durch entweder negativen Dividenden oder Divisor, das gleiche Spiel: -9 / 2 = -4 und 9 / -2 = -4. Schauen wir uns einmal die Rundungen an.

Ist das Ergebnis einer Division positiv und mit Nachkommaanteil, so wird das Ergebnis durch das Abschneiden der Nachkommastellen ein wenig kleiner, also abgerundet. Wäre 3/2 bei Fließkommazahlen 1,5, ist es bei einer Ganzzahldivision abgerundet 1. Bei negativen Ergebnissen einer Division ist das genau anders herum. Denn durch das Abschneiden der Nachkommastellen wird die Zahl etwas größer. -3/2 ist genau genommen -1,5, aber bei der Ganzzahldivision -1. Doch -1 ist größer als -1,5. Java wendet ein Verfahren an, was gegen null rundet.

In Java 8 hat die Mathe-Klasse zwei neue Methoden bekommen, die bei negativem Ergebnis einer Division nicht gegen null runden, sondern gegen negativ unendlich, also auch in Richtung der kleineren Zahl, wie es bei den positiven Ergebnissen ist.

class java.lang.Math

– static int floorDiv(int x, int y)

– static long floorDiv(long x, long y)

Ganz praktisch heißt das: 4/3 = Math.floorDiv(4, 3) = 1, aber wo -4 / 3 = -1 ergibt, liefert Math.floorDiv(-4, 3) = -2.

Java bekommt unchecked IO-Ausnahmen und BufferedReader.lines()

Die neue Methode BuferedReader lines() liefert ein Stream von Strings, die mit den Bulk-Methoden der Lambda-Bibliothek verarbeitet werden können. Brian Goetz gibt unter http://mail.openjdk.java.net/pipermail/lambda-dev/2012-November/006545.html ein (nicht ganz fehlerfreies) Beispiel:

try (reader = new BR(new FR(file))) {
     reader.lines()
           .filter(e -> !startsWith("#"))
           .map(e -> e.toUpperCase())
           .forEach(...);
}

Der Changeset: ttp://hg.openjdk.java.net/lambda/lambda/jdk/rev/94d64473e8e6

Wie kann ein Java-Compiler in Java implementiert sein?

Der Java-Compiler von Oracle und der Java-Compiler der Entwicklungsumgebung Eclipse sind selbst in Java implementiert und generieren diesen Bytecode (es gibt aber auch Java-Compiler in C++, wie den Jikes-Compiler. Natürlich gibt es da ein Henne-Ein-Problem: wie sollte ein neuer in Java geschriebener Compiler durch Java übersetzt werden? Daher entsteht der erste Compiler immer in einer anderen Sprache, und die übersetzt eine kleine Teilmenge der Zielsprache, und dann wird ein neuer Compiler in der Minisprache entwickelt. Im nächsten Schritt wachsen und vergrößern sich Grammatik und Compiler. In der Sprache der Compilerbauer heißt der Prozess Bootstrapping. Bei Java war das ein Prozess über mehrere Stufen. Patrick Naughton schreibt im Buch The Java handbook dazu: “Arthur van Hoff rewrote the compiler in Oak itself, replacing the C version that James originally wrote.“

Thema der Woche: Thread-Kooperation und Benachrichtigung; Schere, Papier, Stein

Zwei Threads sollen auf ein Signal warten, das von einem dritten Threads jede Sekunde gesendet wird. Kommt das Signal, soll sich der erste und zweite Thread zufällig für Schere, Papier oder Stein entscheiden.

  • Welche Klassen und Datenstrukturen helfen bei der Lösung?
  • Wer wertet bei dem kleinen Spiel aus, wer gewonnen hat? Muss es hier eine weitere Benachrichtigung geben?
  • Implementiere eine Lösung.

Offtopic: tutego sucht freiberufliche Trainer

free for job, person icontutego sucht freiberufliche Trainer mit Kenntnissen aus folgenden Gebieten:

  • Java: Java EE-Experten (EJB 3, JPA, Hibernate), Liferay, JBI/Open ESB, Java Security, Java+CORBA, Grails, JBoss Portal, Struts2, IceFaces, NetBeans RCP, GlassFish und Oracle BEA Administration, Java ME, Vaadin, Android Programmierung und Android OS
  • Datenbanken: Clustering unter Oracle und DB2, Data-Warehouse, OLAP
  • Integration: XML-Signaturen und Verschlüsselung
  • Betriebssysteme: Administration und Konfiguration von Unix- (Solaris) und Windows-Systemen, Linux (Ubuntu, Suse, Red Hat/RHEL, …), z/OS, Novell
  • Server: Open-Xchange, Asterisk, OpenLDAP, LAMP-Aufbau, Virtualisierung (Xen, …)
  • Netzwerk/Security: Firewalls, Cisco, Check Point, Netzwerkdesign-/diagnose
  • Programmiersprachen und Bibliotheken: C++, STL, Boost, Threading, Delphi/Delphi.NET, COBOL, Qt, GTK+, Assembler
  • Content Management Systeme: Typo3, Zope/Plone, Mamboo
  • SAP: SAP-Module
  • Im Office-Bereich sind wir schon gut bestückt.

 

job, openings, sign iconWir erwarten Menschen mit sicherem Auftreten und mehrjähriger Berufserfahrung, die ein hohes Maß an Eigeninitiative, Organisationstalent, Verantwortung und Teamfähigkeit mitbringen und aktiv in der Community teilnehmen.

Sie erweitern Ihr Wissen ständig in der Praxis und können idealerweise Veröffentlichungen vorweisen. Ihr Einsatzort ist der gesamte deutschsprachige Raum.

Es macht Ihnen Spaß Vorträge zu halten und zu unterrichten? Sie sind schnell begeistert, wenn es um die Anwendung neuer Technologien geht? Dann sind Sie bei tutego genau richtig! Wir freuen uns auf Ihre Bewerbung per E-Mail unter info at tutego dot com.

Tiefe Objektkopien mit JAXB und JAXBSource

Die unmarshal(…)-Methoden ist überladen mit Parametern, die typische Datenquellen repräsentieren, etwa Dateien oder Eingabeströme wie ein Reader. Allerdings sind noch andere Parametertypen interessant, und es lohnt sich, hier einmal in die API-Dokumentation zu schauen. Ein spannender Typ ist javax.xml.transform.Source, beziehungsweise die Implementierung der Schnittstelle durch JAXBSource. JAXBSource ist die Quelle, aus denen JAXB seine Informationen bezieht, um ein neues Java-Objekt zu rekonstruieren.

Das nächste Beispiel nimmt sich ein Objekt room als Basis und erzeugt eine tiefe Kopie davon:

Room room = …

JAXBContext context = JAXBContext.newInstance( Room.class );

Unmarshaller unmarshaller = context.createUnmarshaller();

JAXBSource source = new JAXBSource( context, room );

Room copiedRoom = Room.class.cast( unmarshaller.unmarshal( source ) );

System.out.println( copiedRoom.getPlayers() ); // [com.tutego.insel.xml.jaxb.Player@…]

Das Beispiel zeigt somit, wie sich mit Hilfe von JAXB Objektkopien erzeugen lassen.

Wie funktioniert eigentlich invokedynamic?

Bei invokedynamic sind viel weniger Typinformationen nötig wie bei den anderen vier existierenden Bytecodes für Methodenaufrufe. Generiert wird der Bytecode zum Beispiel von Skriptsprachen, wenn Typinformationen fehlen. Die Compiler der Skriptsprachen nutzen Bytecode-Bibliotheken wie ASM (http://asm.ow2.org/) und umgehen den Java-Compiler zur Erstellung der Klassendateien.

Der neue Bytecode ist die eine Seite. Aber wenn die Typinformationen fehlen, insbesondere der wichtige Empfänger (wie PrintStream bei println()), wie kommt die JVM zur wirklichen Implementierung? Etwa bei unserem Beispiel von isEmpty(s), in dem es ein invokedynamic-Aufruf von s.length() gibt. Der Aufruf muss ja irgendwo landen.

function isEmpty(s) { return s == null || s.length() == 0; }

Zwei Dinge sind hier zusätzlich nötig. Das erste ist, dass es neben dem Aufruf von invokedynamic noch eine zusätzliche Information im Bytecode gibt, nämlich von einer Bootstrap-Methode. Findet die JVM zum ersten Mal ein invokedynamic, dann weiß sie nicht, an wen der Aufruf geht und wendet sich an die Bootstrap-Methode. Zur passenden Auswahl der Zielmethode übergibt die JVM an die Bootstrap-Methode Informationen über Aufrufer und Name, sodass alle wichtigen Informationen zur Auswahl des Ziels vorhanden sind. Hier sind wir nun in der zweiten Hälfte, denn zusätzlich zum neuen Bytecode gibt es ein neues Paket java.lang.invoke. Die Bootstrap-Methode spezifiziert mit der API des neuen Pakets die Zielmethode und gibt diese an die JVM weiter. Wenn das einmal geschehen ist, ist der Aufruf gebunden und die JVM ruft beim dynamischen Aufruf direkt die vom Bootstrap gelieferte Methode auf. Der genaue Ablauf bei den invokedynamic-Aufrufen dokumentiert das Paket.

Der neue Bytecode muss von einer Java 7-JVM unterstützt werden und wird von dynamischen Skriptsprachen generiert, um die Aufrufe schnell von der JVM ausführen zu lassen. Normale Entwickler werden den neuen Bytecode kaum brauchen, und im Quellcode ist er eh nicht sichtbar.