enum.values ​​() - ist eine Reihenfolge der zurückgegebenen Enums deterministisch

104

Ich habe eine Aufzählung SOME_ENUM:

public enum SOME_ENUM {
  EN_ONE,
  EN_TWO,
  EN_THREE;
}

Wird SOME_ENUM.values()immer die Aufzählungen in der Größenordnung von Enum Erklärungen zurück: EN_ONE, EN_TWO, EN_THREE? Ist dies eine Regel oder wird nicht garantiert, dass sie in den nächsten JDK-Versionen nicht geändert werden?

Skarab
quelle
1
Ich iteriere über meine Aufzählung, um eine Liste zu füllen, die ich an anderer Stelle im Code lese und über diese Aufzählung iteriere.
Skarab
11
@MitchWheat Aus dem gleichen Grund, aus dem Sie sich auf eine Listenerhaltungsreihenfolge verlassen würden: Da das JDK ein Tool ist, das Ihnen bestimmte Garantien bietet und sich auf diese Garantien verlässt, können Sie prägnanteren und besseren Code schreiben. Zugegeben, die Frage "Wird es garantiert nicht geändert?" ist unmöglich zu beantworten, darauf kann man sich sicher nicht verlassen, nichts hat diese Garantie.
Fletch

Antworten:

143

Die Java-Sprachspezifikation verwendet diese explizite Sprache:

@return ein Array mit den Konstanten dieses Aufzählungstyps in der Reihenfolge, in der sie deklariert sind [Quelle]

Ja, sie werden in der Reihenfolge der Erklärung zurückgesandt. Es ist erwähnenswert, dass sich die Reihenfolge im Laufe der Zeit ändern kann, wenn jemand die Klasse ändert. Seien Sie also sehr vorsichtig, wie Sie diese verwenden.

GaryF
quelle
1
Wenn jemand in einer späteren Codeversion einen Wert in der Mitte hinzufügt, kann dies zu Problemen führen, da dadurch der Ordnungswert anderer Elemente geändert wird (siehe die Methode Enum.ordinal ()). Aus diesem Grund ist es am besten, sich nicht auf die Ordnungsposition als Serialisierungsmechanismus zu verlassen (dh nicht in der Datenbank zu speichern).
Matt
1
Link zur Quelle für diese Spezifikation?
Dan Grahn
Java 8 doc
Drew Stephens
16

Ja, es ist garantiert, dass sie in dieser Reihenfolge zurückgegeben werden.

Sie sollten sich jedoch nicht darauf und auf den ordinal()Wert verlassen, da er sich beispielsweise nach dem Einfügen neuer Elemente ändern kann.

Bozho
quelle
+1 für den weisen Rat. Zum Thema ordinal () schlägt Effective Java vor, dem Aufzählungstyp ein Mitgliedsfeld hinzuzufügen.
Ide
9

Dies hängt von der Reihenfolge ab, in der Ihre Werte deklariert sind. Es gibt jedoch keine Garantie dafür, dass Sie (oder eine andere Person) Werte in Zukunft nicht mehr neu anordnen / einfügen / entfernen . Sie sollten sich also nicht auf die Bestellung verlassen.

Effektives Java 2nd. Die Edition widmet ihren Punkt 31 einem eng verwandten Thema: Verwenden Sie Instanzfelder anstelle von Ordnungszahlen :

Leiten Sie niemals einen Wert, der einer Aufzählung zugeordnet ist, aus ihrer Ordnungszahl ab. Speichern Sie es stattdessen in einem Instanzfeld.

Péter Török
quelle
3
"Keine Garantie, dass jemand in Zukunft keine Werte neu ordnet" - aber genau deshalb möchte ich mich auf die Bestellung verlassen :-)! Ich möchte in der Lage sein, die Artikel in Zukunft nachzubestellen und dadurch das Verhalten meines Programms zu ändern. Bloch hat Recht damit, sich nicht auf die Ordnungszahl zu verlassen, und wenn das Beispiel des Fragestellers wirklich Aufzählungen wie EN_TWO beinhaltet, dann verlässt er sich auf die Ordnungszahl und sollte dies nicht tun. Aber sich auf die Bestellung zu verlassen ist vollkommen in Ordnung. Da die Reihenfolge garantiert ist, würde das Erstellen eines Felds speziell für die Bestellung das Schreiben von redundantem Code bedeuten. In Büchern wie Effective Java wird davon abgeraten, dies zu tun.
Fletch
@Fletch, sorry, ich folge dir nicht ganz. Für mich klingt das so, als würden Sie versuchen, es enumfür einen Zweck zu verwenden, für den es nicht gedacht war.
Péter Török
Nehmen wir an, Sie haben die berühmte Aufzählung "Planet". In Ihrer Benutzeroberfläche möchten Sie die Planeten in der Reihenfolge ihrer Entfernung von der Sonne auflisten. Wie können Sie dies am besten erreichen? Ich würde die Planetenkonstanten in der richtigen Reihenfolge innerhalb der Aufzählungsklasse ordnen und dann einfach die Aufzählung in der Benutzeroberfläche aufzählen. Da die Reihenfolge zuverlässig ist, funktioniert dies. Das ist die Art von Sache, über die ich spreche. Wenn sich die Erde eines Tages näher an die Sonne als an den Mars bewegt, ist es in einem solchen Moment natürlich das erste, was Sie im Kopf haben, Ihren Code beizubehalten! Also gehst du zu deiner Planetenklasse und bewegst ERDE vor MARS.
Fletch
@Fletch, die Erde ist schon näher an der Sonne als am Mars ;-) aber ich verstehe was du meinst. In diesem Fall ist die Reihenfolge der Planeten jedoch tatsächlich eine Funktion ihrer mittleren Entfernung von der Sonne, was keine einfache Ordnungszahl ist. Daher sollte sie meiner Meinung nach besser als eigenständiges Feld für jeden Planeten gespeichert werden. Dann können Sie einen trivialen Komparator Planeten anhand ihrer mittleren Entfernung von der Sonne vergleichen lassen und sie mit diesem Komparator bestellen. Dies ist meiner Meinung nach eine saubere und kinderleichte Lösung. Während Ihre Lösung bricht, sobald z. B. ein neuer Kollege entscheidet, dass Planeten offensichtlich in alphabetischer Reihenfolge aufgeführt werden sollen ;-)
Péter Török
1
Hahaha ähm ja gut, es ist alles eine Verschwörung, es gibt keinen Mars. Anfangs wollte ich Saturn benutzen, konnte mich aber nicht erinnern, auf welchen Planeten es sich befindet, aber der Marsplan scheint nach hinten losgegangen zu sein :-). Wie auch immer ... in diesem Fall wäre ein Komparator gut, hat aber natürlich den Nachteil, dass mehr Code erforderlich ist. Ich denke, wenn Sie sich auf die Reihenfolge des Quellcodes verlassen, wäre es eine gute Sache, dies in den Klassenkommentaren zu dokumentieren. Ihr Kollege könnte es sogar lesen.
Fletch
7

Die anderen Antworten sind gut, aber kommentieren Sie dies nicht:

"Ist es eine Regel oder wird nicht garantiert, dass sie in den nächsten Jdk-Versionen nicht geändert werden?"

Ich glaube nicht, dass es Garantien für zukünftige JDKs gibt, deshalb sollten Sie sich nicht einmal darum kümmern. Es würde keine Möglichkeit geben, sie durchzusetzen. Zukünftige JDK-Leads könnten sich einfach dazu entschließen, auf solche Garantien zu verzichten. Es ist wie im Westminster-System des Parlaments: "Kein Parlament kann ein zukünftiges Parlament binden."

Die Geschichte des JDK zeigt jedoch eine hervorragende Konsistenz. Sie nehmen nicht viele wichtige Änderungen vor, sodass Sie ziemlich sicher sein können, dass das aktuell festgelegte (nicht nur beobachtete) Verhalten erhalten bleibt.

Befiedern
quelle