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