Kleines Quellcode-Gruselkabinett II

Weil es so lustig war und ich neues Material gesammelt habe, denke ich, dass es an der Zeit ist, das Quellcode-Gruselkabinett mit einem zweiten Artikel fortzusetzen, womöglich zu beenden. Der (nicht näher definierte) Praktikant aus dem ersten Teil hat wieder zugeschlagen und hocheffizienten und extrem sinnvollen Java-Code produziert. Diese Glanzleistung moderner Softwareentwicklerkunst wollte ich denjenigen meiner Leser, die über Programmierkenntnisse (und Englischkenntnisse) verfügen, auf keinen Fall vorenthalten. Wer von Programmieren überhaupt nichts versteht, der wird an diesem Artikel wie gewohnt leider nichts finden können.

Der Praktikant ist offenbar ein großer Fan davon, toString() auf String-Objekten aufzurufen, vielleicht erhofft er sich dadurch noch stärkere Typsicherheit mit Netz und doppeltem Boden oder sowas. Jedenfalls Code wie der obige begegnet mir leider immer häufiger. Solchen Murks mache ich bei Sichtung auch sofort wieder raus.

Ebenfalls ein ständiger Begleiter in seinem Code: Die Angst, dass eine neu (=leer) angelegte Collection vielleicht doch nicht so leer ist, wie sie vorgibt zu sein. Anders kann ich mir nicht erklären, wieso der Praktikant gleich nach dem Erstellen einer leeren Collection diese leert. Womöglich hat er sich hierbei etwas gedacht, ist aber völlig unnützer Code. Ein damit sehr verwandtes Problem ist das folgende:

Aus der API-Dokumentation der oberen Methode: „The Calendar returned is based on the current time in the default time zone with the default locale.„. Der Knackpunkt ist, dass das zurückgegebene Kalender-Objekt immer bereits mit der gegenwärtigen Uhrzeit initialisiert ist. Hier (zur Sicherheit oder aus Unkenntnis) nochmals Uhrzeit und Datum zu setzen und dafür extra ein neues Date-Objekt zu erstellen, ist kompletter Unfug. Überhaupt: Wieso geht er davon aus, dass der parameterlose Konstruktor von Date() die aktuelle Uhrzeit liefert, aber bei Calendar soll selbiges System nicht funktionieren? Nett auch die Wahl des Variablennamens „actCal“ für den Kalender. Er dachte wohl, „actual calendar“ sei eine brauchbare Übersetzung für das, was er ausdrückten wollte. Ich lese da aber irgendwie immer nur „Aktkalender“.

Auch so ein Codekonstrukt, worüber man diskutieren sollte: die Getter-Methode für private Konstanten. Wieso nicht gleich die Konstante als public deklarieren, dann kann man sich das Rumgeeiere sparen. Bei Konstanten durchaus sinnvoll. Aber als verwandtes Problem sei angemerkt, dass der Praktikant zum Beispiel ganz gerne auch mal simple Getter-Methoden innerhalb derselben Klasse aufruft, in der sie definiert werden – anstelle der sichtbaren Variable. Kapselung schön und gut, aber damit ist doch eigentlich Kapselung von der Außenwelt gemeint. Das scheint jemand nicht so richtig verstanden zu haben.

Namenskonventionen für Methoden sind auch so ein Problem für den Praktikanten. Der Name der Methode sagt leider nichts darüber aus, was der Rückgabetyp sein könnte. Im Fall von „componentParser“ ist noch nicht einmal eine Tätigkeit erkennbar. Da meldet die als Frage formulierte Methode „isActive“ eine komplexe Hashmap zurück, und die etwas umständlich benannte Methode „getTheParsedSysInfoComp“ liefert nicht etwa „die kompletten Systeminformationen“ zurück, sondern einen Wahrheitswert – was auch immer dieser aussagen soll. Immer wieder lustig mitanzusehen sind Methodennamen, die erkennen lassen, dass sich dabei wohl jemand beim Ausdenken einen abbrechen musste, etwa „isLoadTimeFromOneSystemOverTime“.

Englisch scheint ohnehin nicht so seine ultimative Stärke zu sein, vor allem wenn die (netterweise konsequent, wenn auch unnötigerweise) im Englischen gehaltenen Kommentarzeilen nur so vor Denglisch triefen. Da wird aus „Pfade herausfiltern“ schonmal „filter the path outside“, oder das weibliche Possessivpronomen „her“ wird auf Systeme und _ihre_ Eigenschaften angewandt. Wenn man kein Englisch kann, sollte man vielleicht nicht unbedingt versuchen, alles immer englisch schreiben zu wollen, oder zumindest mal ein paar Vokabeln nachschlagen, bevor man in die Tasten haut.

14 Gedanken zu „Kleines Quellcode-Gruselkabinett II

  1. Marius

    Hi Vince,

    Der arme Praktikant :(
    Ich hoffe du stellst nicht nur seine Missgeschicke hier zur Schau, sondern hilfst ihm auch ein bisschen sich zu verbessern.

    Die Sache mit dem toString ist echt unverständlich für mich.

    Abgesehen davon, das die Funktion der Methode schon deutlich im Namen steht, macht man doch zu Beginn seiner Ausbildung und Studiums doch eh nichts anderes als toString-Methoden zu überschreiben.

    Na hoffentlich wird das noch besser!

    Viele Grüße Marius

    Antworten
    1. Vince Beitragsautor

      Hallo Marius,

      selbstredend habe ich ihm viele seiner „Ideen“ auch im persönlichen Gespräch ausgeredet, sofern ich die Gelegenheit hatte. Die Codezeilen, die ich hier präsentiere, sind mir allesamt erst viel später aufgefallen. Allerdings ist es ja nicht meine Absicht, jemanden bloßzustellen, sondern kuriose Quellcodeschnipsel zu zeigen und zu kommentieren, da ich davon ausgehe, dass das vielen anderen Anfängern auch mal passiert. Hätte ich meine allerersten Java-Programme noch, dann würde ich zur Not sogar diese als Negativbeispiel nehmen.

      Deine Tutorial-Seite ist sehr interessant und passt sogar zum Thema. Da du dir auch die Mühe gemacht hast, dich auf den Inhalt des Artikels zu beziehen, kann ich den Backlink gerne so stehen lassen ;-)

      Vielleicht kannst du mir sogar verraten, wie dein Syntax Highlighting Script für WP heißt.

      Antworten
  2. Marius

    Du hast ja auch niemanden bloßgestellt, sollte auch kein Vorwurf sein ;)
    Klar verrate ich dir welches Plugin ich verwende und zwar Crayon. Unterstützt eigentlich alle aktuellen Sprachen.

    Antworten
  3. Marius

    Ach ja und danke natürlich für den Backlink ;).

    Hab dich mal zu meinen Kreisen in G+ hinzugefügt.

    Wenn du gerade noch den Link des 2. Kommentars entfernen könntest, einmal reicht nämlich. Danke dir.

    Antworten
  4. Diskutant

    „Aber als verwandtes Problem sei angemerkt, dass der Praktikant zum Beispiel ganz gerne auch mal simple Getter-Methoden innerhalb derselben Klasse aufruft, in der sie definiert werden – anstelle der sichtbaren Variable. Kapselung schön und gut, aber damit ist doch eigentlich Kapselung von der Außenwelt gemeint. Das scheint jemand nicht so richtig verstanden zu haben.“

    An diesem Punkt muss ich dir vehement widersprechen. Ich (und auch mein Kollegen) benutzen grundsätzlich die getter/setter Methoden. Man kann ja theoretisch im getter/setter noch etwas mehr machen, z. B. den vorherigen Wert speichern. Wenn ich ab und an diese direkten aufrufe sehe zucke ich zusammen und ändere das ganz schnell. :)

    Antworten
    1. Vince Beitragsautor

      Du widersprichst mir nicht, du hast nur meine Formulierung nicht richtig gelesen/verstanden.

      Ich habe ganz bewusst geschrieben simple Getter-Methoden, also der Form public int getValue(){ return value; }

      Ein Getter, in dem ich noch mehr mache (z.B. rechnen), ist mindestens kein simpler Getter mehr, und wenn der Getter auch noch Nebeneffekte hat (Werte speichern/verändern), ist auch die Bezeichnung „Getter“ auf jeden Fall fragwürdig. Bei einem Setter dürfen selbstverständlich Werte verändert werden, da ist die Situation etwas anders gelagert. Insofern bin ich der Ansicht, dass, wenn man im Getter nichts anderes macht, als eine Variable auszulesen, es ein unnötiger Methodenaufruf ist (der Performance kostet), da die Variable sowieso sichtbar ist, besonders wenn ich es selbst bin, der die Klasse geschrieben hat.

      Aber du darfst da selbstverständlich anderer Meinung sein.

      Antworten
      1. Diskutant

        Ich weiß ja nicht ob in Zukunft der simple getter mal ein komplexer getter wird. ;)
        Ich finds einfach schöner die entsprechende Methode zu benutzen, dafür sind sie da. Der Compiler sollte schon in der Lage sein das ordentlich zu optimieren so dass kein Unterschied zu merken ist.

        Antworten
        1. Vince Beitragsautor

          Also ich weiß nicht, ob wir dasselbe meinen, aber wenn ich beispielsweise einen Getter habe, der einen bestimmten Wert berechnen muss, dann gibt es dazu in der Regel aber doch auch keine Variable, auf die man zugreifen könnte. Zum Beispiel so:

          private double laenge;
          private double breite;
          public double getLaenge(){return laenge;}
          public double getBreite(){return breite;}
          public double getFlaeche(){
          return laenge * breite;
          }

          Hier habe ich keine Variable „flaeche“, weil das sinnlos wäre, wenn die Fläche sich sowieso nur aus Länge und Breite zusammensetzt, oder? Bei einem komplexen Getter, wenn wir dasselbe meinen, besteht also kaum die Gefahr, dass man da die Variable benutzt. Und ja, im Beispiel habe ich NICHT die anderen Getter benutzt ;)

          Übrigens, beinahe dasselbe Beispiel mit dem Getter für die Fläche kam in meiner Oracle-Prüfung vor. Da wurde dann eine Klasse u.a. mit einer updateFlaeche()-Methode, die jeweils in den Settern für Laenge und Breite aufgerufen wird, dargestellt. Man sollte dann 2 von 4 Möglichkeiten wählen, eine korrekte Kapselung für die Klasse herzustellen. Leider erfährt man nicht, ob man richtig lag.

          Antworten
          1. Diskutant

            Ja wir meinen schon das selbe, also simpler getter wäre in dem Fall getLaenge und getBreite. Aber man in so einem getter ja Beispielsweise einen Zähler einführen oder was weiß ich.

            Spielt aber auch keine Rolle, sind einfach zwei Verschiedene Arten damit umzugehen, und keine von beiden ist jetzt falsch oder richtig.

            Wenn aber genau das in so einer Prüfung abgefragt wird, würd mich das schon sehr interessieren was die nun als richtig ansehen. :/

            Antworten
  5. Diskutant

    Grad hier auch eine super Java Zeile gefunden:

    for(;this.iterator.hasNext();){
    ...
    }

    Da musste ich erstmal prüfen ob es sich wirklich immer genauso wie ein while verhält. Hätte ich sehr merkwürdig gefunden wenn nicht, aber ja es ist so, also direkt durch ein while ersetzt. :D

    Antworten
    1. Vince Beitragsautor

      Ja stimmt, daran wäre ich auch hängengeblieben. Vor etwa zwei Jahren hatte ich einen völlig falschen Gedankengang bei einem sehr ähnlichen Beispiel, ich kriege es leider nicht mehr zusammen.
      Ich war damals der Meinung, dass, wenn man im Schleifenkopf sowas wie list.iterator().hasNext() stehen hat, dass bei jeder erneuten Auswertung des Schleifenkopfes wieder ein ganz neuer Iterator erzeugt wird, wegen dem erneuten Methodenaufruf von iterator(). Aber ich bin mir jetzt gar nicht mehr sicher, ob ich mich richtig erinnere *

      *Edit: Ich glaube ich hab ein Beispiel so wie ich es meinte: Wenn man sowas hat: for(String s : someObj.getSomeStringList()){, also einen Methodenaufruf im Kopf einer for-each-Schleife, dann – so DACHTE ich – wird die Methode bei jeder Iteration erneut aufgerufen, daher habe ich den Methodenaufruf vorsichtshalber immer vor die Schleife gezogen und die Liste zwischengespeichert. Aber die Schleife macht das natürlich schon richtig.

      Dieser Tage habe ich sogar die try-finally-Blöcke für mich entdeckt. Hätte ich vorher auch nie benutzt, aber ich hab gemerkt, es ist irgendwie sinnvoller als ein catch+rethrow. Man lernt zum Glück nie aus.

      Antworten
      1. Diskutant

        Oh man, ich glaub ich penn noch. :D
        Deine for Schleife in diesem Beispiel hat mich völlig verwirrt. Dachte was macht denn der Doppelpunkt, was ist das ganze? Hab das nachgestellt und gesehen dass das tatsächlich funktioniert, bis ich dann mal deinen Text weitergelesen habe und bei „foreach“ ist der Groschen dann gefallen, argh. Schreib das nie händisch, das macht die IDE immer automatisch wenn man“ fore“ ctrl+space tippt. :D

        Dass die Methode nicht ständig aufgerufen wird ist eigentlich schon logisch, habe ich beim ersten mal aber einfach ausprobiert um sicher zu gehen.

        finally ist schon wichtig um offene Ressourcen wie Dateien oder DB Verbindungen zu schließen. Aber was meinst du mit catch+rethrow?

        Antworten
        1. Vince Beitragsautor

          Ich weiß schon wofür ein finally-Block da ist, aber bislang habe ich dafür immer try-catch-finally verwendet, auch wenn ich mit der Exception an der Stelle gar nichts anfangen konnte, daher habe ich die Exception immer weitergeworfen (rethrow):

          try {
          num = Integer.parseInt(text);
          } catch(NumberFormatException nfe){
          // Exception direkt an die aufrufende Klasse weiterreichen...
          throw nfe;
          } finally {
          // XY-Verbindung muss aber genau hier geschlossen werden
          connection.close()
          }

          Und das nur, damit ich den finally-Block haben kann. Neuerdings weiß ich eben, dass ich mir in so einem Fall einfach den catch-Block sparen kann (try-finally), dann kommt die Exception genau da an, wo ich sie haben will, und der finally-Block wird trotzdem hier ausgeführt.

          Antworten

Schreibe einen Kommentar

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