Hannes: einen Vector auslesen

hi all,

ich belege den Vector mit Strings  und will ihn anschließend auslesen.
Wenn ich println benutze geht alles, aber wenn ich den Vectorinhalt in eine Variable vom Typ String schreibe geht es nicht.

Ihr habt bestimmt ne IDEE ...

private Vector  fErrorLog = new Vector();

if (fErrorLog.size() > 0) {
   System.out.println("------------------------------------------ ERRORS ------------------------------------------");

for (int i = 0; i < fErrorLog.size(); i++) {
               System.out.println(fErrorLog.get(i));
   }

System.out.println("--------------------------------------------------------------------------------------------");
        }

  1. Hallo,

    ich belege den Vector mit Strings  und will ihn anschließend auslesen.
    Wenn ich println benutze geht alles, aber wenn ich den Vectorinhalt in eine Variable vom Typ String schreibe geht es nicht.

    private Vector  fErrorLog = new Vector();

    if (fErrorLog.size() > 0) {
       System.out.println("------------------------------------------ ERRORS ------------------------------------------");

    for (int i = 0; i < fErrorLog.size(); i++) {
                   System.out.println(fErrorLog.get(i));
       }

    System.out.println("--------------------------------------------------------------------------------------------");
            }

    Es wäre zwar besser gewesen, Du hättest den Code gepostet, der _nicht_ funktioniert, aber ich denke mal, Du hast nicht beachtet, dass in Collections nur Elemente der Klasse Object abgelegt werden. Die Methode get(int index) gibt deshalb ein Object zurück. Du musst es in einen String casten.

    String str = new String();
    for (int i = 0; i < fErrorLog.size(); i++) {
             str = str.concat((String)fErrorLog.get(i));
    }

    Gruß

    Axel

    1. hi Axel,

      danke für Deine Hilfe!

      Gruß Hannes

    2. Hi,

      Es wäre zwar besser gewesen, Du hättest den Code gepostet, der _nicht_ funktioniert, aber ich denke mal, Du hast nicht beachtet, dass in Collections nur Elemente der Klasse Object abgelegt werden. Die Methode get(int index) gibt deshalb ein Object zurück. Du musst es in einen String casten.

      1. Sollte man aus Performancegründen in diesem Falle einen StringBuffer (dieser ist im Gegensatz zu String-Objekten mutable) verwenden.

      2. Sollte auch der direkte Aufruf von toString() funktionieren, da dieser immer einen String zurückgibt und man sich den Cast erspart - im Falle der Klasse String eine Referenz auf das String-Objekt selbst ('return this'):

      Beispiel:
       StringBuffer buf = new StringBuffer();
       for (int i = 0; i < fErrorLog.size(); i++) {
                buf.append((fErrorLog.get(i).toString());
       }

      Gruß

      Axel

      Viele Grüße,
      Martin Jung

      1. Hallo,

        1. Sollte man aus Performancegründen in diesem Falle einen StringBuffer (dieser ist im Gegensatz zu String-Objekten mutable) verwenden.

        Nein! Wieso? Will er den String ändern? Nein. Wieso sollte er dann
        StringBuffer verwenden?

        1. Sollte auch der direkte Aufruf von toString() funktionieren, da dieser immer einen String zurückgibt und man sich den Cast erspart - im Falle der Klasse String eine Referenz auf das String-Objekt selbst ('return this'):

        Nein, man sollte das ganz sicher nicht so tun! Was ist, wenn er
        irgendwo einen Programmierfehler hat und nun statt einem String
        weißnicht ein Integer-Objekt in den Vector geschrieben hat. Ein
        toString() würde für den Integer funktionieren.
        Bei einem Cast würde - wie gewünscht - eine ClassCastException geworfen.
        Du erkaufst dir mit deinem toString() eine schwer auffindbare
        Fehlerquelle!

        Übrigens ist die toString()-Version sogar langsamer als die Version
        mit dem Cast, wie folgender Code beweist:

        Vector v = new Vector();
            v.add("Hubbabubba");
            String s;

        System.out.println(System.currentTimeMillis());
            for (int i = 0; i < 1000000000; i++) {
                s = (String)v.get(0);
            }

        System.out.println(System.currentTimeMillis());

        for (int i = 0; i < 1000000000; i++) {
                s = v.get(0).toString();
            }

        System.out.println(System.currentTimeMillis());

        Die Schleife mit dem Cast benötigt ca. 25 Sekunden. Die Schleife mit
        dem toString()-Aufruf dagegen ca. 33 Sekunden. Damit ist deine als
        besser propagierte Lösung fehleranfälliger und 33%(!) langsamer!

        Gruß
        Slyh

        --
        Es gibt 10 Arten von Menschen. Solche, die das Binärsystem verstehen, und solche, die es nicht verstehen.
        1. Hi,

          Nein! Wieso? Will er den String ändern? Nein. Wieso sollte er dann StringBuffer verwenden?

          Aus Performancegründen (wie ich begründet habe) - Beispiel:

          import java.util.Vector;

          /**  * @version  0.1  *  * @history   17.01.2003    Martin Jung    created  *  * @author   <a href="mailto:junmar@web.de">Martin Jung</a>  */ public class StringPerformance {

          static int length = 100000;     static String[] arr = new String[length];     static String result = "";     static long begin, lap;     static String NL = System.getProperty("line.separator");

          static {         for (int i = 0; i < arr.length; i++) {             arr[i] = new String("a");             // assure to have disctinct String objects             if (i > 0) {                 if (arr[0] == arr[i]) {                     System.out.println("Exit because no distinct String object" +                                        " at position:" +i);                     System.exit(1);                 }             }         }         System.out.println("created object of type " +StringPerformance.class+                             " with " +length+ " String objects" +NL);     }

          public static void main(String[] arguments) {         concat();         stringBuffer();         cast();         instanceOf();     }

          public static void concat() {

          System.out.println("entering concat()...");         // for-Schleife entfaltet         result = arr[0]                     .concat(arr[1]) // 1. temporäres String Object                     .concat(arr[2]) // 2. temporäres String Object                     .concat(arr[3]);         /* das bedeutet: für n Konkatenierungen mit .concat() werden            (unnötigerweise) n-1 temporäre String Objekte kreiert,            die dann wieder 'GC'-ed werden (müssen)!            Darunter dürfte sowohl die Performance leiden als auch das            Speicherprofil */

          // test         begin = System.currentTimeMillis();         for (int i = 0; i < arr.length; i++) {             result = result.concat(arr[i]);         }         lap = System.currentTimeMillis() - begin;         System.out.println("concat(): " +lap+ " msec" +NL);     }

          public static void stringBuffer() {

          System.out.println("entering stringBuffer()...");         StringBuffer buf = new StringBuffer();

          // test         begin = System.currentTimeMillis();         for (int i = 0; i < arr.length; i++) {             buf = buf.append(arr[i]);         }         result = buf.toString();         lap = System.currentTimeMillis() - begin;         System.out.println("stringBuffer(): " +lap+ " msec" +NL);     }

          public static void cast() {

          System.out.println("entering cast()");         Vector v = new Vector();         v.add("Hubbabubba");         int max = length * 100;         String s;         System.out.println("now using " +max+ " String objects...");

          begin = System.currentTimeMillis();         for (int i = 0; i < max; i++) {             s = v.get(0).toString();         }         lap = System.currentTimeMillis() - begin;         System.out.println("toString: " +lap+ " msec");

          begin = System.currentTimeMillis();         for (int i = 0; i < max; i++) {             s = (String)v.get(0);         }         lap = System.currentTimeMillis() - begin;         System.out.println("cast: " +lap+ " msec" +NL);         /* Du hast Recht (mit JDK 1.3.1) - allerdings dürfte dieser          * Performanceeffekt besonders von der VM-Implementierung abhängen.          */     }

          public static void instanceOf() {

          System.out.println("entering instanceOf()");         Vector v = new Vector();         v.add("Hubbabubba");         int max = length * 100;         String s;         System.out.println("now using " +max+ " String objects...");

          begin = System.currentTimeMillis();         for (int i = 0; i < max; i++) {             s = (String)v.get(0);         }         lap = System.currentTimeMillis() - begin;         System.out.println("cast ohne type check: " +lap+ " msec");

          Object obj;         begin = System.currentTimeMillis();         for (int i = 0; i < max; i++) {             obj = v.get(0);             if (obj instanceof String) {                 s = (String) obj;             }         }         lap = System.currentTimeMillis() - begin;         System.out.println("cast mit type check: " +lap+ " msec");         /* Du hast Recht (mit JDK 1.3.1) - allerdings dürfte dieser          * Performanceeffekt besonders von der VM-Implementierung abhängen.          */     } }

          Nein, man sollte das ganz sicher nicht so tun! Was ist, wenn er irgendwo einen Programmierfehler hat und nun statt einem String weißnicht ein Integer-Objekt in den Vector geschrieben hat. Ein toString() würde für den Integer funktionieren.

          Hannes deklarierte:     private Vector fErrorLog = new Vector();

          Daraus schloss ich spekulativ, der Programmierer beabsichtigt dem Vektor werden ausschließlich String Objekte hinzuzufügen und macht dies auch (der 'private' access modifier ließ mich zusätzlich vermuten, der Vektor stellt ein internes Member dar).

          Bei einem Cast würde - wie gewünscht - eine ClassCastException geworfen.

          Wieso ist das erwünscht? Ob eine ClassCastException geworfen werden soll, ist eine Designentscheidung. Diese würde ich variabel treffen:

          Entwicklung: Ein expliziter Cast hilft, um Programmierfehler aufzudecken. Sollte es sich weiterhin um einen gänzlich privaten Member halten (ohne Getter/Setter), wäre der cast - wie von Dir gezeigt - die performantere Lösung (zumindest mit JDK 1.3.1). Anmmerkung: wenn der (private) Vector hingegen über eine publizierte API (Getter/Setter) zugänglich gemacht wird/werden soll, ist der cast zwar immer noch performanter, verhindert aber nicht, dass irgendjemand folgendes in seinem Code folgendes schreibt:

          BesagtesObjekt obj = new BesagterObjekt(); Vector v = obj.gibMirErrorLogVector(); v.add(Integer.toString(5));

          1. Produktivversion: Sagen wir spekulativ, der Code-Ausschnitt ist Teil einer Logging-Funktionalität. Unabhängig, ob das Logging 'nur' für Debug-Monitoring verwendet wird oder Teil der dem Benutzer angebotenen Programmfunktionalität werden/sein soll (z.B. ein Log bei einem Backup-Programm) würde ich definitiv keine ClassCastException zulassen. Warum: a) eine RuntimeException führt zum Programmabbruch (- sofern sie nicht abgefangen wird) b) Das unbeabsichtigte Loggen von Informationen (irgendwelchen String-Objekten) rechtfertigt in keinem Falle einen Programmabbruch. c) Aufgrund der Performancetests würde ich dieses dann durch einen cast mit vorangegangener Typprüfung gewährleisten.

          Du erkaufst dir mit deinem toString() eine schwer auffindbare Fehlerquelle!

          Warum schwer auffindbar? Ich sollte die Stelle meines Codes kennen, an dem die Log-Infos assembliert werden. Also weiß ich, wo ich einen Breakpunkt zu setzen habe, starte den Debugger und sollte die Fehlerursache (relativ - diese Einschränkung gilt beim Entwanzen ja prinzipiell ;-)) ) schnell gefunden haben.

          Übrigens ist die toString()-Version sogar langsamer als die Version mit dem Cast, wie folgender Code beweist:

          Du hast Recht - siehe Beispielcode. Ich denke allerdings, dass dieser Performanceunterschied von der Implementierung der VM abhängt (während der Performanceunterschied wzischen String.concat() und StringBuffer.append() primär durch die Spezifikation begründet ist - wobei eine VM-Implementierung natürlich genau diesbezüglich besonders optimiert sein könnte)

          Viele Grüße, Martin Jung

          1. Hallo,

            Wieso sollte er dann StringBuffer verwenden?
            Aus Performancegründen (wie ich begründet habe)

            Ja, aber der Performancevorteil tritt ja nur dann auf, wenn der
            String selbst verändert wird. (Wie ich begründet habe.)
            Dann darfst du gerne StringBuffer verwenden. Aber wieso hier? Macht
            die Sache doch nur viel aufwendiger. Außerdem hat man nicht den
            schönen Vorteil, daß Strings intern effizient verwaltet werden.

            Beispiel:
                int      count = 500000;
                String[] sa = new String[count];

            System.out.println(System.currentTimeMillis());
                for (int i = 0; i < count; i++) {
                    sa[i] = new String("Hubbabubba");
                }

            System.out.println(System.currentTimeMillis());

            StringBuffer[] sb = new StringBuffer[count];
                for (int i = 0; i < count; i++) {
                    sb[i] = new StringBuffer("Hubbabubba");
                }
                System.out.println(System.currentTimeMillis());

            Das Anlegen der String-Objekte ist ca. um den Faktor 4 schneller.
            Ich würde außerdem behaupten, daß in diesem - zugegebenermaßen
            sehr spezialisiertem Beispiel - weit weniger Speicher verbraucht wird.
            Aber das konnte ich jetzt leider nicht nachweisen.

            public static void concat() {

            System.out.println("entering concat()...");
                    // for-Schleife entfaltet
                    result = arr[0]
                                .concat(arr[1]) // 1. temporäres String Object
                                .concat(arr[2]) // 2. temporäres String Object
                                .concat(arr[3]);
                    /* das bedeutet: für n Konkatenierungen mit .concat() werden
                       (unnötigerweise) n-1 temporäre String Objekte kreiert,
                       die dann wieder 'GC'-ed werden (müssen)!
                       Darunter dürfte sowohl die Performance leiden als auch das
                       Speicherprofil */

            Richtig. Allerdings änderst du hier wieder einen String. In diesem Fall
            verwendet man - wie du und ich ja korrekt gesagt festgestellt haben -
            besser einen StringBuffer. Genau dafür ist er ja da.
            Darum ging's aber ja nicht.

            public static void cast() {

            [...]

            /* Du hast Recht (mit JDK 1.3.1) - allerdings dürfte dieser
                     * Performanceeffekt besonders von der VM-Implementierung abhängen.
                     */
                }

            Auch mit JDK 1.4.1 und vermutlich allen vorangegangenen JVMs. :-)
            Der Grund ist vermutlich einfach der, daß ein Cast viel weniger
            Overhead erzeugt als ein Methodenaufruf (->toString). Natürlich hängt
            das von der VM-Implementierung ab. Aber was hängt nicht von der
            Implementierung ab? Wenn du Leute beim Implementieren eines Casts
            Schrott programmieren, wird das natürlich langsam. Wenn die Leute
            beim Implementieren von StringBuffer.append() Schrott bauen und
            beispielsweise temporäre String-Objekte verwenden würden, wäre append()
            auch langsamer. ;-)

            Nein, man sollte das ganz sicher nicht so tun! Was ist, wenn er
            irgendwo einen Programmierfehler hat und nun statt einem String
            weißnicht ein Integer-Objekt in den Vector geschrieben hat. Ein
            toString() würde für den Integer funktionieren.
            Hannes deklarierte:
                private Vector fErrorLog = new Vector();

            Daraus schloss ich spekulativ, der Programmierer beabsichtigt dem Vektor werden ausschließlich String Objekte
            hinzuzufügen und macht dies auch

            Zweifellos.

            (der 'private' access modifier ließ mich zusätzlich
            vermuten, der Vektor stellt ein internes Member dar).

            Naja, mich nicht. Möglich wär's aber. :-)

            Darum ging es mir aber nicht. Es ging mir allgemein um die Verwendung
            von toString statt einem explizitem Cast. Wenn das Programm ne Nummer
            größer ist, etwas komplexer und evtl. sogar von fremden Programmierern
            verwendet wird, könnte es passieren - und das halte ich nicht für zu
            praxisfern - daß statt einem String eben irgend ein anderer Objekt-
            Typ versehentlich(!) zum Vector geaddet wird. Vielleicht aus Unacht-
            samkeit. Vielleicht weil die Namen ähnlich sind. Jedenfalls funktioniert
            die toString()-Variante anschließend noch, obwohl sie das nicht
            sollte, weil eben kein Cast erfolgt, sondern weil toString() für
            jedes Objekt exisiert.

            Beispiel:
            Ich habe eine Klasse XmlParser. Diese hat eine Methode "getError()".
            Nun ist ein Fehler aufgetreten und ich möchte diesen loggen, will
            also
              fErrorLog.add(xmlParser.getError());
            schreiben, schreibe aber versehentlich
              fErrorLog.add(xmlParser);
            stattdessen.

            Später gebe ich den ErrorLog aus oder verarbeite ihn (oder wasauchimmer)
            und wundere mich, wieso da nun irgendwelcher Schrott ausgegen wird.
            Ich muß die Fehlerstelle suchen usw.
            Würde ich einen expliziten Cast durchführen, würde ich zur Laufzeit
            eine Exception an der entsprechenden Stelle erhalten, könnte dort
            Debuggen (intelligente IDEs können sogar einen Breakpoint auf
            beliebige Exceptions setzen) und würde sofort den Fehler bemerken.
            (Zugegebenermaßen ist das Beispiel an den Haaren herbeigezogen. Aber
            ich hoffe, es wurde klar was ich sagen wollte.)

            Bei einem Cast würde - wie gewünscht - eine ClassCastException geworfen.
            Wieso ist das erwünscht? Ob eine ClassCastException geworfen werden soll, ist eine Designentscheidung.

            Richtig. Es wäre ein besserers Design wenn der Fehler nicht einfach
            geschluckt wird, indem ein toString() verwendet wird, das (wie gesagt)
            noch dazu langsamer ist. :-)

            Entwicklung:
            Ein expliziter Cast hilft, um Programmierfehler aufzudecken.

            Meine Rede.

            Anmmerkung: wenn der (private) Vector hingegen über eine
            publizierte API (Getter/Setter) zugänglich
            gemacht wird/werden soll, ist der cast zwar immer noch
            performanter, verhindert aber nicht, dass irgendjemand folgendes
            in seinem Code folgendes schreibt:

            BesagtesObjekt obj = new BesagterObjekt();
            Vector v = obj.gibMirErrorLogVector();
            v.add(Integer.toString(5));

            Ich habe auch nicht gesagt, daß es das verhindert. Ich habe nur gesagt,
            daß das Programm dadurch schlechter wartbar und langsamer wird.

            Wenn du einen Setter verwendest, kann sowas natürlich nicht mehr
            passieren. Hier würde sogar ein Fehler während des Kompilierens auf-
            treten. -> Beste Lösung.

            Ich fasse nochmal zusammen:
             * Deine Lösung: Keine Fehlermeldung
             * Meine Lösung: Fehlermeldung bei Laufzeit
             * Mit Setter:   Fehlermeldung beim Kompilieren

            1. Produktivversion:
              [...] definitiv _keine_ ClassCastException zulassen.
              Warum:
              a) eine RuntimeException führt zum Programmabbruch (- sofern sie nicht abgefangen wird)
              b) Das unbeabsichtigte Loggen von Informationen (irgendwelchen String-Objekten) rechtfertigt in keinem Falle einen Programmabbruch.
              c) Aufgrund der Performancetests würde ich dieses dann durch einen cast mit vorangegangener Typprüfung gewährleisten.

            Hier gebe ich dir in allen Punkten recht. In einer Produktversion
            wäre ein toString() (bzw. die instanceof-Sache) besser, da nur
            harmloser Schrott geloggt wird, dafür kein Programmabbruch erfolgt.
            Dafür erfolgt während des Testens keine Exception. Der Fehler würde
            damit beim Testen tendenziell weniger wahrscheinlich gefunden werden,
            als wenn eine Exception auftritt.

            Du erkaufst dir mit deinem toString() eine schwer auffindbare
            Fehlerquelle!
            Warum schwer auffindbar? Ich sollte die Stelle meines Codes kennen, an dem die Log-Infos assembliert werden.

            Jein. Das trifft auf kleine Programme zu. Sobald das Projekt etwas
            größer wird, weißt du das evtl. nicht mehr so ohne weiteres.
            Wie oben beschrieben, bist du mit einer Exception auf jeden Fall
            schneller am Ziel. Vermutlich brauchst du nicht mal einen Debugger.
            Aber ich gebe dir recht. Es dürfte sich vom Aufwand nicht zu sehr
            unterscheiden.

            Fazit: Der Cast ist schneller und während der Entwicklung hilfreich -
            auch beim Testen. toString() ist für das fertige Produkt wünschenswert,
            weil damit (harmloser) Schrott geloggt wird, das Programm aber nicht
            gleich stirbt. Dafür übersieht man den Fehler evtl. beim Testen.

            Besser wäre natürlich die konsequente Verwendung von Properties.
            Dann könnte sowas gleich gar nicht passieren.

            Solange aber hier keine verwendet werden, halte ich meinen Ansatz
            persönlich für besser, kann aber auch gut verstehen und nachvollziehen, wenn du deinen für besser hälst. :-)

            Gruß
            Slyh

            1. Hi Slyh,

              bin etwas in Hektik...

              Ja, aber der Performancevorteil tritt ja nur dann auf, wenn der
              String selbst verändert wird. (Wie ich begründet habe.)
              Dann darfst du gerne StringBuffer verwenden. Aber wieso hier? Macht
              die Sache doch nur viel aufwendiger. Außerdem hat man nicht den
              schönen Vorteil, daß Strings intern effizient verwaltet werden.

              Da hätte ich in  meiner Antwort evtl nochmals betonen sollen, dass ich mich nicht auf Hannes' ursprüngliches Beispiel (System.out.println(v.get(.....),) sondern auf auf Axel's Antwort/Vorschlag bezog.
              Mein Ansatz bestand darin, in der Iteration zunächst mit Hilfe eines StringBuffers den gesamten Ausgabestring zu assemblieren und dann mit einer println-Anweisung auszugeben.

              Das Anlegen der String-Objekte ist ca. um den Faktor 4 schneller.
              Ich würde außerdem behaupten, daß in diesem - zugegebenermaßen
              sehr spezialisiertem Beispiel - weit weniger Speicher verbraucht wird.

              Siehe obige Bemerkung meiner ursprünglichen Intention,

              Aber das konnte ich jetzt leider nicht nachweisen.

              Das geht ohne Profiler (die direkten Zugriff auf die VM haben) leider nicht wirklich.

              Richtig. Allerdings änderst du hier wieder einen String. In diesem Fall
              verwendet man - wie du und ich ja korrekt gesagt festgestellt haben -
              besser einen StringBuffer. Genau dafür ist er ja da.
              Darum ging's aber ja nicht.

              Siehe oben.

              Auch mit JDK 1.4.1 und vermutlich allen vorangegangenen JVMs. :-)
              Der Grund ist vermutlich einfach der, daß ein Cast viel weniger
              Overhead erzeugt als ein Methodenaufruf (->toString).

              Offensichtlich.

              Natürlich hängt
              das von der VM-Implementierung ab. Aber was hängt nicht von der
              Implementierung ab?

              Die Tatsache, dass eine Stringverkettung mit .concat() (nochmals: darauf bezog ich mich ;-))) ) unnötige
              String-Objekte erzeugt, da es durch die Spezifikation/Core APIs ja vorgegeben ist. Deswegen schrieb ich auch ' ... _besonders_ von der VM-Implementierung abhängen...'.

              Wenn du Leute beim Implementieren eines Casts
              Schrott programmieren, wird das natürlich langsam. Wenn die Leute
              beim Implementieren von StringBuffer.append() Schrott bauen und
              beispielsweise temporäre String-Objekte verwenden würden, wäre append()
              auch langsamer. ;-)

              Dieses Argument schlug mich nun zu Tode.... ;-)

              Darum ging es mir aber nicht. Es ging mir allgemein um die Verwendung
              von toString statt einem explizitem Cast. Wenn das Programm ne Nummer
              größer ist, etwas komplexer und evtl. sogar von fremden Programmierern
              verwendet wird, könnte es passieren - und das halte ich nicht für zu
              praxisfern - daß statt einem String eben irgend ein anderer Objekt-
              Typ versehentlich(!)

              Das ist ja die Krux an der Generizität. Kann man das hinzufügen eines Objects zu einem Vector
              als versehentlich bezeichen? ;-) Ich bin wirklich gespannt, ob die 'Generics' diesbezüglich insgesamt eine Erleichterung bringen werden oder nicht.

              zum Vector geaddet wird. Vielleicht aus Unacht-
              samkeit. Vielleicht weil die Namen ähnlich sind. Jedenfalls funktioniert
              die toString()-Variante anschließend noch, obwohl sie das nicht
              sollte, weil eben kein Cast erfolgt, sondern weil toString() für
              jedes Objekt exisiert.

              Genau das war ja meine Überlegung - ist so schön OO-isch ;-))

              .... das Beispiel an den Haaren herbeigezogen. Aber
              ich hoffe, es wurde klar was ich sagen wollte.)

              Das war mir von Beginn an klar..

              Wenn du einen Setter verwendest, kann sowas natürlich nicht mehr
              passieren.

              Bei .setVector(Vector a Vector) oder .setErrMsg(String aMsg)?
              In der Praxis verwendet man ja sowieso Log4j.....

              Jein. Das trifft auf kleine Programme zu. Sobald das Projekt etwas
              größer wird, weißt du das evtl. nicht mehr so ohne weiteres.

              Theorie: Auch im Team veröffentlichte APIs sollten diesbezüglich wasserdicht sein. Um bei unserem Beispiel zu bleiben: Es darf einfach keine Möglichkiet geben, außerhalb der Klasse etwas anderes als einen String dem Log-Container hinzuzufügen (im Kreise dreh...)

              Fazit: Der Cast ist schneller und während der Entwicklung hilfreich -
              auch beim Testen. toString() ist für das fertige Produkt wünschenswert,
              weil damit (harmloser) Schrott geloggt wird, das Programm aber nicht
              gleich stirbt. Dafür übersieht man den Fehler evtl. beim Testen.

              Einspruch: Auf meiner Kiste var Typprüfung + cast schneller las .toString() alleine.
              also:

              private static final NO_MATCH_MESSAGE = "found non-String object in log vector: ";
              ..//..
              if(obj instanceof String) {
                  msg = (String) v.get(i);
                  System.ou.println(msg); // wahlweise: buf.append(msg); ;-))
              } else {
                  Object misMatch = v.remove(i);
                  v.add(i, NO_MATCH_MESSAGE + misMatch.class.getName());
                  i--;
              }
              Kleiner Scherz....

              Besser wäre natürlich die konsequente Verwendung von Properties.
              Dann könnte sowas gleich gar nicht passieren.

              Yep.

              Solange aber hier keine verwendet werden, halte ich meinen Ansatz
              persönlich für besser, kann aber auch gut verstehen und nachvollziehen, wenn du deinen für besser hälst. :-)

              Siehe vorher, ich _hatte_ meinen Ansatz ja bereits zu Gunsten eines performanteren verworfen...

              Viele Grüße,
              Martin Jung

              1. Hallo Martin,

                bin etwas in Hektik...

                Dito. :-)

                Mein Ansatz bestand darin, in der Iteration zunächst mit Hilfe eines StringBuffers den gesamten Ausgabestring zu assemblieren und dann mit einer println-Anweisung auszugeben.

                Ooh, tatsächlich, da war ein concat() drin. Das habe ich total über-
                sehen. Ups, mein Fehler.

                Das ist ja die Krux an der Generizität. Kann man das hinzufügen
                eines Objects zu einem Vector als versehentlich bezeichen? ;-)

                Naja, in diesem speziellen Fall ja schon irgendwie.

                Ich bin wirklich gespannt, ob die 'Generics' diesbezüglich
                insgesamt eine Erleichterung bringen werden oder nicht.

                Bisher habe ich Templates/Generics noch nie vermisst und mich deshalb
                nicht damit beschäftigt (außer in C++). Mir wurde allerdings schon
                von Menschen berichtet, die geflucht haben, daß es sowas in Java
                nicht gibt. Naja, man wird sehen...

                sollte, weil eben kein Cast erfolgt, sondern weil toString() für
                jedes Objekt exisiert.
                Genau das war ja meine Überlegung - ist so schön OO-isch ;-))

                Findest du? Mmh, ich persönlich würde toString() höchstens für
                Debug-Ausgabe (bzw. evtl. Logging) verwenden, niemals aber zur
                Umsetzung von Funktionalität.
                Andererseits ist natürlich richtig, daß toString() irgendwie mehr
                mit Objektorientierung zu tun hat, als ein Cast.

                Theorie: Auch im Team veröffentlichte APIs sollten diesbezüglich wasserdicht sein. Um bei unserem Beispiel zu bleiben: Es darf einfach keine Möglichkiet geben, außerhalb der Klasse etwas anderes als einen String dem Log-Container hinzuzufügen (im Kreise dreh...)

                ACK!

                Gruß
                Slyh

                --
                Es gibt 10 Arten von Menschen. Solche, die das Binärsystem verstehen, und solche, die es nicht verstehen.