Errata zum Buch »Java — Der Grundkurs« (1. Auflage 2014)

Fast alle der hier aufgezählten Fehler sind in den aktuellen Nachdrucken des Buchs bereits behoben.

Die Beispieldateien zur 1. Auflage finden Sie hier: https://www.rheinwerk-verlag.de/java_3632/

Bitte beachten Sie, dass es von diesem Buch eine aktuellere Auflage gibt!

Seite 69, Casting

Bei einer Überschreitung des Zahlenbereichs bei einem erzwungenen Casting kommt es zu keiner Exception. Vielmehr enthält die Variable i im folgenden Beispiel eine total falsche Zahl.

long l = l = 17_000_000_000L;;
int  i = (int)l;       // Vorsicht: wenn der Wert in l den den
                       // int-Zahlenbereich überschreitet, enthält
                       // i einen vollkommen falschen Wert
System.out.println(i)  // Ausgabe: -179869184
Seite 72, Fließkommazahlen

Im Absatz nach der Überschrift: 1.23e4 bzw. 1.23E4 1.23e3 bzw. 1.23E3 bedeutet 1,23 x 10^3. (Die nachfolgenden Code-Beispiele sind richtig.)

Seite 75 mitte, Objektvariablen

Natürlich müssen auch Objektvariablen zuerst initialisiert werden, bevor Sie ausgelesen werden können. Nur innerhalb von Klassen werden Instanzvariablen mit 0, 0.0, false bzw. null automatisch initialisiert. Gleiches gilt für die Elemente eines Arrays.

Seite 77, clone

in der zweiten Zeile des Listings muss es lautet: p3.clone(), nicht p1.clone():

Point p3 = new Point(3, 3);
Point p4 = (Point)p3.clone();
p4.x = 4;
System.out.println(p3.x + " " + p4.x);
// Ausgabe: 3 4
Seite 82, Beispiel zu java.util.Scanner

Im Listing auf der Seitenmitte habe ich laenge und breite durcheinander gebracht. Richtig muss der Code so aussehen:

double laenge = Double.parseDouble(eingabeLaenge);
double breite = Double.parseDouble(eingabeBreite);
Seite 95, Rechnen mit Bits

0b11100 ist 28, nicht 26.

int a = 0b11100;            // 28 = 0b11100
Seite 185 bis 186, Lotto-Beispiel

Es ist mir wirklich peinlich (mea culpa!): Das Lotto-Beispiel enthält gleich drei Fehler:

  • In der Methode gewinnzahlen muss die Bedingung für die for-Schleife i<n lauten, nicht i<n-1.
  • Ebenfalls in dieser Methode sollte sich die continue-Anweisung auf die äußere do-Schleife beziehen. Deswegen muss vor der do-Schleife ein Label gesetzt werden, anstelle von continue heisst es dann continue label.
  • Schließlich muss die while-Bedingung in main mit false formuliert werden, sonst ist der erste Tipp sofort ein Treffer. Das wäre zu schön, um wahr zu sein.
public static int[] gewinnzahlen() {
  int[] ziehung = new int[6];
  int zahl;
  Random r = new Random();
  int n=0;

  // Schleife für alle sechs Zahlen
  do_label:    // <-- Korrektur
  do {
    zahl = 1 + r.nextInt(49);
    // testen, ob Doppelgänger
    for(int i=0; i<n; i++) {
      if(ziehung[i] == zahl)
        continue do_label;  // <-- Korrektur
    }
    ziehung[n]=zahl;
    n++;
  } while(n<6);

  Arrays.sort(ziehung);
  return ziehung;
}

...

// in main: Schleife; so oft Lotto spielen,
// bis die sechs Zahlen übereinstimmen
do {
    n++;
    ziehung = gewinnzahlen();
} while(Array.equals(tipp, ziehung) == false); // <--- 

Das korrigierte Beispiel können Sie hier herunterladen:

Seite 194, try-catch für Ressourcen

Die Ressourcen innerhalb von try(...) müssen durch Semikola getrennt werden, nicht durch Kommas. Also:

try(IOKlasse1 x = new IOKlasse1("dateiname1"); 
    IOKlasse2 y = new IOKlasse2("dateiname2")) { ...
Seite 208, Box zu Top-Level-Klassen

Der Text in der Box ist falsch und widerspricht der korrekten Tabelle von der Vorseite: Somit gilt für Top-Level-Klassen ohne protected, private oder public ein Mittelding zwischen protected und private. Die Klasse ist nur im Paket zugänglich, nicht aber in abgeleiteten Klassen oder gar außerhalb!

Seite 235, Methoden überschreiben

Beim Überschreiben von Methoden ist es nicht erforderlich, dass die Sichtbarkeit gleich bleibt — sie darf nur nicht eingeschränkt werden. Eine public-Methode kann also nicht durch eine private-Methode überschrieben werden. Umgekehrt ist es aber z.B. zulässig, dass eine protected-Methode durch eine public-Methode überschrieben wird.

Auch der Rückgabewert muss nicht zwingend identisch sein. Dies gilt nur für Werttypen. Bei Referenz-Typen kann die überschreibende Methode auch einen Subtypen zurückgeben. Beispiel: Methode m der Klasse K1 liefert eine Instanz von Typ A zurück. Methode m der Klasse K2 extends K1 darf eine Instanz von Typ B zurückgeben, wenn B von A abgeleitet ist (also A extends B oder A implements B, natürlich auch bei Vererbung/Schnittstellen über mehrere Schritte).

Seite 241, Generalisierung

Im Beispiel-Code auf S. 241 mitte fehlt der Casting-Operator (C1), damit der Compiler weiß, dass er obj3 als Objekt der Klasse C1 betrachten soll:

obj3.x1(); obj4.x2();            // nicht erlaubt 
C1 obj5 = (C1)obj3; obj5.x1();   // OK
          ^^^^
((C2)obj4).x2();                 // auch OK

Seite 241, Polymorphie

Die Regeln der Polymorphie gelten nur für überschriebene Methoden. Soweit Felder sichtbar sind, wird immer auf das Feld der Basisklasse zugegriffen, nicht auf ein eventuell gleichnamiges Feld der abgeleiteten Klasse.

Seite 243, Polymorphie

Im Code-Beispiel in der Seitenmitte muss es in der vierten Zeile a.anzahlSitze() anstelle von f.anzahlSitze() heißen. Das ganze Listing sieht damit so aus:

void m(Fahrzeug f) {
  if(f instanceof Auto) {
    Auto a = (Auto)f;
    int sitze = a.anzahlSitze();
  } else if (f instanceof Fahrrad) {
    Fahrrad fr = (Fahrrad)f;
    boolean federgabel = fr.hatFedergabel();
  }
  ...
}
Seite 257, implements

Mit implements verpflichten Sie sich normalerweise, alle Methoden einer Schnittstelle zu implementieren. Wenn es sich bei Ihrer Klasse um eine abstrakte Klasse handelt, können Sie diese Verpflichtung aber auch weitergeben, indem Sie die betreffende Methode abstrakt deklarieren. Die tatsächliche Implementierung erfolgt dann in der Klasse, die später von Ihrer Klasse abgeleitet wird.

Seite 271, Upper Bounded Wildcards

<? extends Xxx> gilt nicht nur für von Xxx abgeleitete Klassen, sondern auch für Xxx selbst.

Seite 272, Upper Bounded Wildcards

In der Mitte des Listings sollte statt outputTriplet natürlich sumTriplet stehen, also:

Double result = sumTriplet(t2);
Seite 290, Tabelle »Die wichtigsten Lambda-Schnittstellen«

In der vierten Zeile der Tabelle muss es nicht Consumer<T, U> heißen, sondern BiConsumer<T, U>.

Seite 291, Listing Predicate-Schnittstelle

Im Listing am Beginn der Seite ist das Wort ‚More‘ enthalten, dass dort nichts verloren hat. Das Listing sieht korrekt so aus:

@FunctionalInterface
public interface Predicate<T> {
  boolean test(T t);
  ... sowie diverse Defaultmethoden
}
Seite 309, descendingIterator-Methode

Im Listing auf S. 309 unten wird die Methode decendingIterator gezeigt, um eine Schleife in umgekehrter Reihenfolge zu durchlaufen. Diese Methode steht allerdings nicht allgemein für Sets, sondern nur für TreeSets zur Verfügung. Sie kann daher nur nach einem Cast in diesen Typ angewendet werden. Das Listing sieht korrekt so aus:

// Schleife in umgekehrter Reihenfolge
TreeSet<Point> ts = (TreeSet) set;
for(Iterator<Point> pit = ts.descendingIterator();
    pit.hasNext(); ) {
  Point p = pit.next();
  System.out.println(p.x + " " +  p.y);
}
Seite 333, Files.walk-Methode

Das Beispielprogramm kap15-io-intro führt bei der Ausführung unter Windows zu einer Exception. Diese wird durch Files.walk(...) verursacht, sobald die Methode auf eine Datei oder ein Verzeichnis stösst, das aufgrund fehlender Zugriffsrechte nicht gelesen werden kann. Aufgrund der internen Implementierung dieser Methode lässt sich die Exception nicht wie bei anderen Methoden durch try/catch abfangen. Hintergründe zum Problem können Sie hier nachlesen:

http://stackoverflow.com/questions/22867286
https://bugs.openjdk.java.net/browse/JDK-8039910

Eine mögliche Alternative besteht darin, anstelle von Files.walk die Methode Files.walkFileTree zu verwenden (Details siehe hier und hier). Diese Methode bietet mehr Flexibilität bei der Fehlerabsicherung, ist aber deutlich komplexer in ihrer Anwendung und als Beispiel für ein Java-Einführungsbuch ungeeignet.

In zukünftigen Auflagen meines Java-Buchs werde ich auf die Erwähnung von walk verzichten. Die walk-Methode ist nur auf den ersten Blick einfach zu nutzen; in ihrer aktuellen Form ist sie in der Praxis für die meisten Anwendungen ungeeignet.

Seite 335, Listing Seitenmitte

Anstelle von Files.createDirectory(v23) muss es Files.createDirectories(v23) lauten, weil ein Verzeichnis und ein darin enthaltenes Unterverzeichnis erzeugt werden. (In den Beispieldateien ist der Code korrekt.)

Seite 336, Ergebnisse des Beispiels kap15-io-change

Das Programm erzeugt die folgenden Verzeichnisse und Dateien:

verz1/
  datei1.tmp 
  datei2.tmp   (nicht datei1.tmp wie im Buch angegeben)
verz2/
  uv3-neu/
Seite 397, Lösung zu Aufgabe W2 aus Kapitel 3 (Postfix/Präfix-Notation)

Ich habe Post- und Präfix durcheinander gebracht. Die Lösung d=-25 ist zwar korrekt, aber die Erklärung ist falsch. Richtig muss die Erklärung so lauten:

Java verarbeitet die Zuweisung an d so:

d = (a--) - (b--) - c;

Da -- hier in der Postix-Notation angewendet wird, berücksichtigt Java die
ursprünglichen Inhalte von a und b, also:

d = 7 - 12 - 20;

Nach der Berechnung des Werts für d werden auch die Variablen a und b
geändert. Somit ergibt sich: a=6, b=11, c=20 und d=-25.

Letzte Änderung am 28.11.2018. Vielen Dank an alle Leser und Leserinnen für das Feedback!

29 Gedanken zu „Errata zum Buch »Java — Der Grundkurs« (1. Auflage 2014)“

  1. Seite 86, Wiederholungsaufgabe 5: Es steht bereits die Lösung in der Aufgabenstellung.
    Es müsste eigentlich in der Aufgabenstellung heissen:

    s = s + i;

  2. Seite 77, Beispielcode
    korrekt wäre:

    Point p4 = (Point)p3.clone(); //und nicht (Point)p1.clone!

    ansonsten macht das Beispiel keinen Sinn.

  3. Bitte prüfen Sie nochmals folgendes..

    Seite 235: Methoden überschreiben
    – Name und Parameterliste exakt gleich. (ok)
    – Sichtbarkeit nicht eingeschränkt
    – Rückgabenwert gleich (primitive Datentypen) oder Subtyp (bei Referenzen)

    Seite 241: Polymorphie:
    – Zur Laufzeit wird die überschriebene Methode des Objekts verwendet. (ok)
    – Falls sichtbar, dann ist es ein Feld des Referenztyps ( nicht des Objektes) auf das zugegriffen werden kann

    Seite 257: Die implements Syntax
    Es ist auch möglich eine Methode und damit auch die Klasse abstract zu deklarieren.
    Insofern ist implements keine Verpflichtung die Methoden zu implementieren

    Bitte um Feedback falls ich mich irren sollte.
    Danke!

  4. Seite 107: Absatz nach dem Beispiel
    Hier wird explizit darauf hingewiesen, dass im „obigen“ Beispiel auf die geschwungenen Klammern verzichtet worden ist. Im Beispiel sind aber die angesprochenen Klammern jedoch vorhanden.

  5. In Kapitel 11.1 Vererbung Seite 243 wird im Programmbeispiel die Methode f.anzahlSitze() aufgerufen. Sollte an dieser Stelle nicht a.anzahlSitze() aufgerufen werden, da sie ja für die Basisklasse nicht verfügbar sein sollte?

    Falls ich mich irren sollte bitte ich Sie um Rückmeldung, da ich zum ersten Mal durch Ihr Buch mit OO-Programmierung in Berührung gekommen bin.

    Danke!

  6. In Kapitel 4, 4.4 For Schleifen habe ich noch einen Fehler gefunden. Auf Seite 107 unter dem Code-Beispiel der kurzen For-Schleife steht im Text, dass auf die geschwungenen Klammern verzichtet wird, da die Anweisung nur aus einer Zeile besteht. Das Code-Beispiel enthält aber die geschwungenen Klammern.

    mfg

  7. In der Tabelle der wichtigen funktionalen Schnittstellen auf Seite 290 erscheint die Schnittstelle Consumer zweimal, einmal mit einem und einmal mit zwei Typ-Parametern. Das scheint mir nicht korrekt. Sollte die Schnittstelle mit zwei Parametern nicht BiConsumer heißen?

  8. Es wäre recht hilfreich, wenn aus der mittlerweile einigermaßen langen Liste hervorginge, für welchen Nachdruck welche Errata noch gelten. Der vorangestellte Satz „Alle hier aufgezählten …“ ist offensichtlich nicht mehr zutreffend, und selbst wenn er es wäre, würde das Besitzern des ersten und zweiten Nachdrucks wenig nützen.
    Vorschlag zu einer einfachen Lösung: Zu jedem Erratum könnte, sofern zutreffend, vermerkt werden: „korrigiert im soundsovielten Nachdruck.“

    1. … oder man sortiert – mit entsprechenden Überschriften – zuerst nach Ausgabe/Druck und erst innerhalb dieser Gruppen nach Seitenzahlen.

  9. In dem Beispiel-Listing für Upper Bounded Wildcards auf S. 272 wird eine Methode sumTriplets() zur Berechnung der Summe eines Triplets definiert, die dann aber nirgendwo aufgerufen wird. Stattdessen wird in der darüberliegenden Zeile eine Methode outputTriplet() aufgerufen, die bereits in einem früheren Listing vorkam:

    Double result = outputTriplet(t2);

    Meines Erachtens sollte in dieser Zeile eigentlich die Methode sumTriplets() stehen, also:

    Double result = sumTriplet(t2);

  10. In dem Beispiel für die Datenselektion mit der Schnittstelle Predicate auf S. 291 steht in der Definition der funktionellen Schnittstelle Predicate in der Signatur der Methode test zwischen dem Rückgabewert boolean und dem Methodennamen test das Wort „More“, das für mich an dieser Stelle syntaktisch keinen Sinn ergibt und – so meine Vermutung – nicht dorthin gehört:

    public interface Predicate {
    boolean More test(T t);

    }

    In der Java-Dokumentation von Oracle ist die Methode einfach folgendermaßen definiert:

    boolean test(T t)

  11. Am Ende von S. 309 zeigt ein Listing, wie die Elemente eines TreeSets in absteigender Reihenfolge ausgegeben werden können:

    for (Iterator pit = set.descendingIterator(); pit.hasNext();) {
        Point p = pit.next();
        System.out.println(p.x + " " + p.y);
    }
    

    Der Aufruf der Methode descendingIterator() für das Objekt set ist aber an dieser Stelle gar nicht möglich, weil set zuvor nicht als TreeSet sondern als Set deklariert wurde:

    Set set = new TreeSet<>(comp);
    

    Eclipse schlägt daher an der Stelle, an der descendingIterator aufgerufen wird, einen expliziten Cast auf TreeSet vor:

    for (Iterator pit = ((TreeSet) set).descendingIterator(); pit.hasNext();)
    
    1. Sie haben recht. In der 2. Zeile des fraglichen Listings fehlt ein Casting-Operator (C1). Ich habe es auf den Errata-Seiten beider Auflagen des Buchs vermerkt. Vielen Dank für den Hinweis!

  12. Auf S. 350 wird die Methode setOnAction für die Checkbox verwendet, diese ist jedoch in dem Paket das die Checkbox zur Verfügung stellt, nämlich java.awt, nicht enthalten. Da hat sich wohl was verändert seit 2014. Welche alternative Methode sollte nun stattdessen verwendet werden?
    Danke im Voraus für den Tip.

Schreibe einen Kommentar

Deine E-Mail-Adresse wird nicht veröffentlicht. Erforderliche Felder sind mit * markiert

Wenn Sie hier einen Kommentar absenden, erklären Sie sich mit der folgenden Datenschutzerklärung einverstanden.