PDA

Archiv verlassen und diese Seite im Standarddesign anzeigen : Böse "Features" in Java 1.5


PH4Real
2005-01-09, 22:34:35
So... nachdem ich mich jetzt ziemlich mit Java 1.5 beschäftigen musste, finde ich die meisten Neuerungen sinnvoll und auch nötig.

Aber ein paar Sachen finde ich wirklich fürchterlich. Zum Beispiel das Autoboxing. Da kann es nämlich zu sehr "merkwürdigen" Sachen kommen:


Integer i1 = 127;
Integer i2 = 127;

// i1 == i2: true und i1.equals(i2): true, mmmh... ok das macht auch Sinn
System.out.println((i1 == i2) + " und i1.equals(i2): " + i1.equals(i2));;

Integer i3 = 128;
Integer i4 = 128;

// Arrgh... happy debugging! i3 == i4 wird zu false ausgewertet,
// aber i3.equals(i4) bleibt natürlich bei true!
System.out.println((i3 == i4) + ", aber i3.equals(i4): " + i3.equals(i4));

Dazu gibt es das Kommentar aus dem O'Reilly (Java 1.5 Tiger: A Developer's Notebook):
Remember that int values from -127 to 127 are in that range of immutable wrapper types, so the VM actually uses the same object instance (and therefore memory address) for both i1 and i2. As a result, == returns a true result. You have to watch out for this, as it can result in some very tricky, hard-to-find bugs.

Ich freu mich schon auf wirklich lustige Debug Sessions.

Dann noch ein Kommentar zu den Generics. So sinnvoll sie auch sind, wird sowohl manchmal der Code, als auch die Dokumentation sehr unübersichtlich.

Wenn man sich zum Beispiel die Dokus zu der java.util.Collections Klasse mit ihren statischen Methoden anguckt, muss man doch dann dreimal hinschauen, was denn zum Beispiel die Methode max für ein Return Wert hat:


static <T extends Object & Comparable<? super T>> T max (Collection<?extends T> coll)


Naja... ansonsten kann ich nicht meckern. Mein Favoriten sind eindeutig Enums, foreach Schleife und Annotations. Auch die Generics und die neuen concurrency Klassen finde ich gut. Keine Bereicherung der Sprache stellen für mich static imports und die gruselige Formatter Klasse da (printf).

HellHorse
2005-01-09, 23:42:11
Aber ein paar Sachen finde ich wirklich fürchterlich. Zum Beispiel das Autoboxing.
Aye, autoboxing ist pöse, besonders zusammen mit dem Vergelichsoperator. Es sollte einfach nur Referenztypen geben. Aber das hätte wohl zu viele C++ Umsteiger erschreckt.


static <T extends Object & Comparable<? super T>> T max (Collection<?extends T> coll)

Der ist zwar ziemgleich geil, aber imo nicht pöse.
Was ich beim Collection Framework allerdings pöse finde, ist dass manche Operationen optional sind. Das führt die ganze Idee von statischer Typisierung ad absurdum. Das war aber schon immer so.

Auch Spass macht:

Enum<E extends Enum<E>>


Zu generics im Collection Framework: es gibt einen kurzen Überblick mit Erklärungen von Gilad Bracha. Sehr lesenswert.

Was verwirrt:
Ich kann zwar mehrere Funktionen mit gleichem Namen aber anderer Signatur importieren (z.B Arrays.sort und Collections.sort) aber nicht Integer.toString(int). Keine Ahung ob da #toString in Object oder Integer Probleme macht.
(Ich mache das natürlich nicht, ist einem Freund von mir aufgefallen ;) )

Was mit bei annotations sauer aufstösst ist dass dort Arrays und nicht Lists verwendet werden. Das ist wie ein Schlag ins Gesicht.
Und ist pöse dass man aufpassen muss, was man auf die gleiche Zeile tut und was nicht. Hatte @Retention(RUNTIME) eine Zeile oberhalb von public @interface und mich verdammt lange gewundert warum da zur Laufzeit nix das is.
Was Sun bei @Overrides geraucht hat ist mir unklar. Warum nicht gleich @New @Abstract @Virtual :ugly:

Und wenn man schon endlich String eine concat Methode einbaut und extra varargs einbaut. Dann sollte diese Methode gefälligst auch varargs unterstützen.

Was irgendwie nervt ist dass immer mehr über Compilertricks gemacht wird und man selbst keine Möglichkeit hat eigene zu kreieren.

Richtig gut finde ich allerdings, dass das Typsystem gefixt wurde, Stichwort covariante Rückgabetypen.

Matrix316
2005-01-10, 00:03:21
// Arrgh... happy debugging! i3 == i4 wird zu false ausgewertet,

Hä? Warum eigentlich? False doch falsch.

// aber i3.equals(i4) bleibt natürlich bei true!

Stimmt ja auch.

Senior Sanchez
2005-01-10, 09:06:33
// Arrgh... happy debugging! i3 == i4 wird zu false ausgewertet,

Hä? Warum eigentlich? False doch falsch.

// aber i3.equals(i4) bleibt natürlich bei true!

Stimmt ja auch.


Du hast das Problem net verstanden. Die ersten beiden Integer (mit 127 als wert) da ergeben die Referenzvergleiche, als auch der Wertevergleich true, weil sofern das autoboxing richtig funzt _ein_ Objekt genutzt wird (also i1 ist an derselben speicheradresse wie i2). Der Wertevergleich mit equals geht klar, weil es ja wirklich die gleichen werte sind.

Das mit i3 und i4, da gibts überläufe weil 128 außerhalb des Wertebereichs vom int-datentyp (müsste aber eigentlich short dastehen) liegt. Da stimmen plötzlich nicht mehr die referenzen überein, d.h. es gibt zwei Objekte und somit ergibt der Vergleich per == ein false, Wertevergleich aber true, weil er dann auf -127 die Werte setzen müsste, und das ist ja bei beiden gleich.

Problem ist also, dass das Autoboxing manchmal probleme macht

mfg Senior Sanchez

Gast
2005-01-10, 09:56:20
// Arrgh... happy debugging! i3 == i4 wird zu false ausgewertet,

Hä? Warum eigentlich? False doch falsch.

// aber i3.equals(i4) bleibt natürlich bei true!

Stimmt ja auch.

Der "Gag" hier ist, dass bei der Verwendung des Operators == eben kein Deboxing stattfindet, sondern tatsächlich die Referenzen verglichen werden.
Das jedoch bei i1 und i2 ebenfalls die Referenzen übereinstimmen, liegt an einer impliziten Optimierung der VM, die scheinbar für die Werte zwischen -127 und +127 (frag mich bitte net, warum das net von -128 bis +127 geht) bereits instanziierte Objekte bereithält und damit den Fakt verschleiert, dass, wie bereits erwähnt, bei der Anwendung des Operators == eben kein Deboxing stattfindet.
Das kann natürlich zu ziemlich schwer aufspürbaren Bugs führen.

Gast
2005-01-10, 10:19:42
Hab' gerade mal nen kleinen Test gemacht. Der Operator == deboxed, falls ein beteiligter Operand ein primitiver Datentyp ist.

Matrix316
2005-01-10, 13:58:35
Das mit i3 und i4, da gibts überläufe weil 128 außerhalb des Wertebereichs vom int-datentyp (müsste aber eigentlich short dastehen) liegt. Da stimmen plötzlich nicht mehr die referenzen überein, d.h. es gibt zwei Objekte und somit ergibt der Vergleich per == ein false, Wertevergleich aber true, weil er dann auf -127 die Werte setzen müsste, und das ist ja bei beiden gleich.


Ja aber es ist doch beides Mal der gleiche Überlauf. Also müssten auch beide Objekte gleich sein (referenz und Wert), wie beim ersten Mal auch.