Marcus Wiederstein, Marco Skulschus, Mark Donnermeyer, Dirk Brodersen, Benjamin Rusch. Addison-Wesley. ISBN 3-8273-2059-3. 2003. 858 Seiten
Programmabschnitte, sog. Snippets, gibt es im Internet genug (wir wäre es alternativ mit dem Java-Almanac?) und wer eine Suchmaschine bedienen kann, wird immer, ja immer, die Bibliothek oder den Quellcode-Schnippsel finden, die er sucht. Um so erstaunlicher finde ich es, wenn Verlage Quellcode-Kochbücher veröffentlichen, ob sie nun Codebook oder Cookbook heißen. Ernsthaft: Wer eine Klasse zur Bruchrechnung sucht oder ein Beispielprogramm zum Aufbau eines Swing-Fensters, geht sicherlich nicht zum Regal, sucht im Index nach „Bruch“ und holt sich dann die Klasse von der CD. Daher die Frage – ist ein Buch wie „Das Java Codebook“ notwendig? Das Positive zuerst: Die Kapitel über reguläre Ausdrücke und Applets (Daten im Cookie speichern, Uploads, Applet-Konverter für Tags), die kleinen Beispielprogramme, in denen man etwa über ein BufferedImageOp.filter Bilder heller/dunkler macht, sowie Hinweise zur Transparenz und der Index finde ich prima. Eigentlich sind Bücher mit Quellcode gut, denn Software-Entwickler lesen im Allgemeinen zu wenig. Das Studium von Quellcode hilft jedem Entwickler, neue Idiome zu lernen und seine Fähigkeiten zu verbessern. Je nach Schwerpunkt des Buches lernt man weitere Möglichkeiten der Standardbibliothek kennen oder neue Open-Source-Bibliotheken. Soweit die Möglichkeiten guter Codebooks. Leider hat das Java Codebook dann doch die eine oder andere Schwachstelle, so dass man Software-Entwicklern vielleicht doch besser direkt zur Google-Suche raten sollte. (Immerhin gibt es das Buch als PDF.) Die Probleme im Detail: Die Klasse
public class CalcExample {
static final BigDecimal ZERO = new BigDecimal(0);
static final BigDecimal ONE = new BigDecimal(1);
static final BigDecimal FOUR = new BigDecimal(4);
deklariert drei Variablen (Sichtbarkeit könnte auch anders sein), doch vergisst, dass es ZERO, ONE, TEN schon in BigDecimal gibt. In anderen Beispielen gefällt mir die Schreibweise der Felder nicht. Einiges ist nach der Bauart String []array, also Typ, Leerzeichen, Variablenname aufgebaut. Das habe ich nach 11 Jahren Java hier zum ersten Mal gelesen. Zumal sich die Autoren hier uneins zu sein scheinen, denn sie verwenden auch String[]. Die fünf Autoren des Buchs folgen demnach keiner einheitlichen Coding-Konvention. Ein weiteres Thema betrifft die Methodennamen: Überwiegend werden englische Bezeichner (setNumber, less100, …) gebraucht, doch lassen sich innerhalb eines Beispiels Vermischungen mit deutschen Variablennamen entdecken, wie das Feld ZEHN. Einige Autoren mögen (immer noch) die Klassen Hashtable und Vector, andere nutzen doch besser List und Map – hat denn keiner der Autoren die anderen Kapitel gelesen und kommentiert? Bei den Datenstrukturen frage ich mich wirklich, was denn arrayList.add(new String(new java.util.Date().toString())); für eine Anweisung sein soll. Und warum wird ein Stack noch mal neu implementiert? OK, der Original-Stack erbt von Vector, was vom Design total verpfuscht wurde, aber dann könnte man doch immer noch den neuen Stack so implementieren, das er an den alten Stack delegiert, anstatt alle Operationen komplett mit einer ArrayList neu zu implementieren. (Und dann noch die fragwürdige Methode search() zu übernehmen.) Eine weitere Schwachstelle, die ich in der Insel weitestgehend versuche zu vermieden, sind Windows-spezifische Pfadangaben, wie etwa bei new FileOutputStream(„c:\\buecher.ser“). Bei IO-Beispielen fehlt oft das close() im finally. Vor allem bei HTTP-Servern ist das kritisch. Im JSP-Kapitel findet sich plötzlich ein JDBC-Close im finally; also hat es nicht jeder der Autoren vergessen. Frage: Was gibt dieses Programm bei Argumenten auf der Kommandozeile aus?
package javacodebook.io.stdout;
public class StdOut {
public static void main(String[] args) {
String text = "Hallo Welt";
//Wenn Text angegeben, dann diesen ausgeben
if(args.length < 1)
for(int i = 0; i < args.length; i++)
System.out.println(args[i]);
else
System.out.println(text);
}
}
Dass ist wohl eher eine Zertifizierungsfrage statt eines sinnvollen Codebeispiels, denn ist die Anzahl der Argumente kleiner 1, gibt es keine Argumente und die Schleife ist nutzlos. Genauso falsch ist der Satz „JDBC benutzt dabei die Interfaces Connection, Driver und DriverManager.“ Schade, denn DriverManager ist eine Klasse. Sollte es auch, denn aus dieser Zentrale erhält man durch die statische Methode getConnection() eine Verbindung. Im Anhang finden sich dann noch ein paar Dreher in der Groß-/Kleinschreibung. Z. B. beginnen einige Bezeichner in der Tabelle „Java Native Interface Typen“ mit Großbuchstaben. Besser wären „int“ statt „Int“ sowie „void“ statt „Void“ usw. Ähnliches gilt für JscrollPane, was zu JScrollPane werden sollte. Unter „Relationale Operatoren“ findet sich folgender Satz bei ==-Operator: „a == b ergibt true, wenn a gleich b ist. Handelt es sich bei a und b um Referenztypen, so ist der Rückgabewert dann true, wenn beide auf dasselbe Objekt zeigen.“ Wir sollten den Sonderfall a = b = NaN aber nicht Außeracht lassen, denn gerade dann ist a = b, aber das Ergebnis nicht true. In der Tabelle „Klassenobjekte für den primitiven Datentyp“ sollte Void besser nicht auftauchen, da es sich nicht um einen primitiven Datentyp handelt. Oder Void stehen lassen, aber die Überschrift anpassen. Einige Kritikpunkte betreffen die Auswahl der Klassen. Die Klasse Fraction sollte vielleicht besser einer bekannten Open-Source-Bibliothek entstammen und die Matrizen sowie der umfangreiche Quellcode nicht unbedingt abgebildet werden. Für CSV-Dateien wären populäre Standard-Klassen sinnvoller. Der Tipp 186 für Timer sollte diesen nicht selbst implementieren, sondern die zwei (!) Timer-Klassen der Java-Lib vorstellen. Da ein Codebook grundsätzlich eine unendliche Sache ist, könnten weitere Snippets eingebracht werden. Bei den Zufallszahlen wäre z. B. SecureRandom gut untergebracht. Das Beispiel FindInFile, was händisch nach einem String in einer Datei sucht, lässt sich viel effektiver mit NIO (mit Standard-Beispiel von Sun) lösen. Das NIO-Kapitel kommt mit nur zwei Beispielen daher (Datei kopieren und File-Lock). Das ist eine magere Ausbeute. Später kommt noch ein NIO-Server dazu. Der Verweis auf eine einfache NIO-Bibliothek (wie xSocket) wäre dann wünschenswert. Um ein Fenster mittig zu positionieren, muss man nicht rechnen, hier reicht eine Java-Funktion. Wenn es sich schon um ein Java 1.4 Buch handelt, dann sollte ImageIO Grafiken laden. Die Swing-Beispiele sind relativ unspektakulär. Hier wäre es wohl sinnvoller statt „wie erzeuge ich einen Button“ oder „wie etwas mehr mit den Modellen zu machen“, einen Dateibaum in ein JTree zu setzen. Und stilistisch wertvoll ist der Hinweis mit der JDBC-Verbindung in einem JSP-Tag sicher nicht. Und wo sind die DAOs? Bei JMS stimmt es zwar grundsätzlich, dass in einer Tabelle bei Programmiersprachenunabhängigkeit „Nein“ steht und bei HTTP „Ja“, doch allgemeingültig ist das nicht. Für ActiveMQ gibt es ein standardisiertes Protokollformat (OpenWire) und APIs für diverse andere Programmiersprachen. Das gleiche gilt auch für IBMs WebSphere MQ (früher MQSeries) – sicherlich eines der besten MOMs -, das heterogene Plattformen verbindet. Einen XML-Parser über die Anweisung org.apache.xerces.parsers.DOMParser parser = new org.apache.xerces.parsers.DOMParser(); statt über JAXP zu erfragen ist nicht schön sondern fast grob fahrlässig. Zudem haben auch die JAXP-Parser Features, obwohl die String-Kennungen dann immer ein wenig anders aussehen. Zu Tipp 196: Wann immer man sich mit getGraphics() einen Grafik-Kontext holt, sollte man ihn auch wieder freigeben. Dieser Hinweis fehlt leider in den Beispielen. Farbkonstanten sollten groß geschrieben sein, also Color.WHITE, statt Color.white, zumindest seitdem Sun diese Konvention in Java 1.4 eingeführt hat.
Erst wenn der letzte Programmierer eingesperrt und die letzte Idee patentiert ist, werdet ihr merken, dass Anwälte nicht programmieren können.
Ähnliche Beiträge
- Rundungsmodus BigDecimal
- java.io.File und NIO.2-Path: wo beide zusammenpassen und wo nicht
- Inselraus: identityHashCode() ist für eine System-eindeutige Objekt-IDs nicht geeignet
- null/NullPointerException in anderen Programmiersprachen: Ruby, nil, Scala, Option, None, Some
- Buchkritik: Wicked Cool Java: Code Bits, Open-Source Libraries, and Project Ideas