Java Language
enums
Zoeken…
Invoering
enum
trefwoord) zijn steno-syntaxis voor aanzienlijke hoeveelheden constanten van een enkele klasse.
Syntaxis
- [public / protected / private] enum Enum_name {// Declareer een nieuw enum.
- ENUM_CONSTANT_1 [, ENUM_CONSTANT_2 ...]; // Verklaar de enum-constanten. Dit moet de eerste regel binnen het opsommingsteken zijn en moet worden gescheiden door komma's, met een puntkomma aan het einde.
- ENUM_CONSTANT_1 (param) [, ENUM_CONSTANT_2 (param) ...]; // Vermeld enum-constanten met parameters. De parametertypen moeten overeenkomen met de constructor.
- ENUM_CONSTANT_1 {...} [, ENUM_CONSTANT_2 {...} ...]; // Vermeld enum-constanten met overschreven methoden. Dit moet worden gedaan als het opsomming abstracte methoden bevat; al dergelijke methoden moeten worden geïmplementeerd.
- ENUM_CONSTANT.name () // Retourneert een tekenreeks met de naam van de enum-constante.
- ENUM_CONSTANT.ordinal () // Retourneert de rangtelwoord van deze opsommingsconstante, zijn positie in de opsommingsdeclaratie, waarbij aan de beginconstante een rangtelwoord van nul wordt toegewezen.
- Enum_name.values () // Retourneert een nieuwe array (van het type Enum_name []) die elke constante van dat enum bevat telkens wanneer deze wordt aangeroepen.
- Enum_name.valueOf ("ENUM_CONSTANT") // De inverse van ENUM_CONSTANT.name () - retourneert de enum-constante met de opgegeven naam.
- Enum.valueOf (Enum_name.class, "ENUM_CONSTANT") // Een synoniem van de vorige: Het omgekeerde van ENUM_CONSTANT.name () - retourneert de enum-constante met de opgegeven naam.
Opmerkingen
beperkingen
Enums breiden java.lang.Enum
altijd uit, dus het is onmogelijk voor een enum om een klasse uit te breiden. Ze kunnen echter veel interfaces implementeren.
tips & trucs
Vanwege hun gespecialiseerde weergave zijn er efficiëntere kaarten en sets die kunnen worden gebruikt met enums als sleutels. Deze zullen vaak sneller werken dan hun niet-gespecialiseerde tegenhangers.
Verklaar en gebruik een basisoverzicht
Enum kan worden beschouwd als syntaxisuiker voor een verzegelde klasse die slechts een aantal keren bij het compileren bekend wordt gemaakt om een set constanten te definiëren.
Een eenvoudig overzicht van de verschillende seizoenen zou als volgt worden verklaard:
public enum Season {
WINTER,
SPRING,
SUMMER,
FALL
}
Hoewel de enum-constanten niet noodzakelijk in hoofdletters hoeven te staan, is het volgens de Java-conventie dat namen van constanten volledig uit hoofdletters bestaan, met woorden gescheiden door onderstrepingstekens.
U kunt een Enum in zijn eigen bestand declareren:
/**
* This enum is declared in the Season.java file.
*/
public enum Season {
WINTER,
SPRING,
SUMMER,
FALL
}
Maar je kunt het ook binnen een andere klasse verklaren:
public class Day {
private Season season;
public String getSeason() {
return season.name();
}
public void setSeason(String season) {
this.season = Season.valueOf(season);
}
/**
* This enum is declared inside the Day.java file and
* cannot be accessed outside because it's declared as private.
*/
private enum Season {
WINTER,
SPRING,
SUMMER,
FALL
}
}
Ten slotte kunt u een Enum niet declareren in een body of constructor van een methode:
public class Day {
/**
* Constructor
*/
public Day() {
// Illegal. Compilation error
enum Season {
WINTER,
SPRING,
SUMMER,
FALL
}
}
public void aSimpleMethod() {
// Legal. You can declare a primitive (or an Object) inside a method. Compile!
int primitiveInt = 42;
// Illegal. Compilation error.
enum Season {
WINTER,
SPRING,
SUMMER,
FALL
}
Season season = Season.SPRING;
}
}
Dubbele enum-constanten zijn niet toegestaan:
public enum Season {
WINTER,
WINTER, //Compile Time Error : Duplicate Constants
SPRING,
SUMMER,
FALL
}
Elke constante van Enum is standaard public
, static
en final
. Omdat elke constante static
, zijn ze rechtstreeks toegankelijk met de enum-naam.
Enum-constanten kunnen worden doorgegeven als methodeparameters:
public static void display(Season s) {
System.out.println(s.name()); // name() is a built-in method that gets the exact name of the enum constant
}
display(Season.WINTER); // Prints out "WINTER"
U kunt een array van de enum-constanten krijgen met de methode values()
. De waarden zijn gegarandeerd in aangiftevolgorde in de geretourneerde array:
Season[] seasons = Season.values();
Opmerking: deze methode wijst een nieuwe reeks waarden toe telkens wanneer deze wordt aangeroepen.
Om de enum-constanten te herhalen:
public static void enumIterate() {
for (Season s : Season.values()) {
System.out.println(s.name());
}
}
U kunt enums gebruiken in een switch
:
public static void enumSwitchExample(Season s) {
switch(s) {
case WINTER:
System.out.println("It's pretty cold");
break;
case SPRING:
System.out.println("It's warming up");
break;
case SUMMER:
System.out.println("It's pretty hot");
break;
case FALL:
System.out.println("It's cooling down");
break;
}
}
Je kunt ook enum-constanten vergelijken met ==
:
Season.FALL == Season.WINTER // false
Season.SPRING == Season.SPRING // true
Een andere manier om enum-constanten te vergelijken is door equals()
zoals hieronder, wat als een slechte gewoonte wordt beschouwd, omdat je als volgt gemakkelijk in valkuilen kunt vallen:
Season.FALL.equals(Season.FALL); // true
Season.FALL.equals(Season.WINTER); // false
Season.FALL.equals("FALL"); // false and no compiler error
Bovendien, hoewel de set instanties in het enum
niet kan worden gewijzigd tijdens runtime, zijn de instanties zelf niet inherent onveranderlijk omdat een enum
zoals elke andere klasse, veranderlijke velden kan bevatten, zoals hieronder wordt aangetoond.
public enum MutableExample {
A,
B;
private int count = 0;
public void increment() {
count++;
}
public void print() {
System.out.println("The count of " + name() + " is " + count);
}
}
// Usage:
MutableExample.A.print(); // Outputs 0
MutableExample.A.increment();
MutableExample.A.print(); // Outputs 1 -- we've changed a field
MutableExample.B.print(); // Outputs 0 -- another instance remains unchanged
Het is echter een goede gewoonte om enum
instanties onveranderlijk te maken, dat wil zeggen wanneer ze geen extra velden hebben of al dergelijke velden als final
zijn gemarkeerd en zelf onveranderlijk zijn. Dit zorgt ervoor dat een enum
gedurende de hele levensduur van het programma geen geheugen lekt en dat het veilig is om zijn instanties over alle threads te gebruiken.
Enums implementeert impliciet Serializable
en Comparable
omdat de Enum
klasse doet:
public abstract class Enum<E extends Enum<E>>
extends Object
implements Comparable<E>, Serializable
Enums met constructeurs
Een enum
kan geen openbare aannemer hebben; privéconstructors zijn echter acceptabel (constructors voor enums zijn standaard pakket-privaat ):
public enum Coin {
PENNY(1), NICKEL(5), DIME(10), QUARTER(25); // usual names for US coins
// note that the above parentheses and the constructor arguments match
private int value;
Coin(int value) {
this.value = value;
}
public int getValue() {
return value;
}
}
int p = Coin.NICKEL.getValue(); // the int value will be 5
Het wordt aanbevolen om alle velden privé te houden en getter-methoden te bieden, omdat er een eindig aantal instanties voor een opsomming is.
Als je in plaats daarvan een Enum
als een class
zou implementeren, zou het er als volgt uitzien:
public class Coin<T extends Coin<T>> implements Comparable<T>, Serializable{
public static final Coin PENNY = new Coin(1);
public static final Coin NICKEL = new Coin(5);
public static final Coin DIME = new Coin(10);
public static final Coin QUARTER = new Coin(25);
private int value;
private Coin(int value){
this.value = value;
}
public int getValue() {
return value;
}
}
int p = Coin.NICKEL.getValue(); // the int value will be 5
Enum-constanten zijn technisch veranderlijk, dus een setter kan worden toegevoegd om de interne structuur van een enum-constante te wijzigen. Dit wordt echter als een zeer slechte praktijk beschouwd en moet worden vermeden.
De beste praktijk is om Enum-velden onveranderlijk te maken, met final
:
public enum Coin {
PENNY(1), NICKEL(5), DIME(10), QUARTER(25);
private final int value;
Coin(int value){
this.value = value;
}
...
}
U kunt meerdere constructors in hetzelfde overzicht definiëren. Als u dat doet, bepalen de argumenten die u in uw opsomming doorgeeft welke constructor wordt genoemd:
public enum Coin {
PENNY(1, true), NICKEL(5, false), DIME(10), QUARTER(25);
private final int value;
private final boolean isCopperColored;
Coin(int value){
this(value, false);
}
Coin(int value, boolean isCopperColored){
this.value = value;
this.isCopperColored = isCopperColored;
}
...
}
Opmerking: Alle niet-primitieve enum-velden moeten Serializable
implementeren, omdat de Enum
klasse dat doet.
Methoden en statische blokken gebruiken
Een opsomming kan een methode bevatten, net als elke klasse. Om te zien hoe dit werkt, verklaren we een opsomming als deze:
public enum Direction {
NORTH, SOUTH, EAST, WEST;
}
Laten we een methode hebben die het getal in de tegenovergestelde richting retourneert:
public enum Direction {
NORTH, SOUTH, EAST, WEST;
public Direction getOpposite(){
switch (this){
case NORTH:
return SOUTH;
case SOUTH:
return NORTH;
case WEST:
return EAST;
case EAST:
return WEST;
default: //This will never happen
return null;
}
}
}
Dit kan verder worden verbeterd door het gebruik van velden en statische initialisatieblokken:
public enum Direction {
NORTH, SOUTH, EAST, WEST;
private Direction opposite;
public Direction getOpposite(){
return opposite;
}
static {
NORTH.opposite = SOUTH;
SOUTH.opposite = NORTH;
WEST.opposite = EAST;
EAST.opposite = WEST;
}
}
In dit voorbeeld wordt de tegenovergestelde richting opgeslagen in een opposite
privéinstantie-veld, dat statisch wordt geïnitialiseerd de eerste keer dat een Direction
wordt gebruikt. In dit specifieke geval (omdat NORTH
verwijst naar SOUTH
en omgekeerd), kunnen we Enums hier niet gebruiken met constructeurs (Constructors NORTH(SOUTH), SOUTH(NORTH), EAST(WEST), WEST(EAST)
zouden eleganter zijn en het opposite
toestaan aan final
worden verklaard, maar zelfreferent zijn en daarom niet zijn toegestaan).
Implementeert interface
Dit is een enum
die ook een opvraagbare functie is die String
test op vooraf gecompileerde reguliere expressiepatronen.
import java.util.function.Predicate;
import java.util.regex.Pattern;
enum RegEx implements Predicate<String> {
UPPER("[A-Z]+"), LOWER("[a-z]+"), NUMERIC("[+-]?[0-9]+");
private final Pattern pattern;
private RegEx(final String pattern) {
this.pattern = Pattern.compile(pattern);
}
@Override
public boolean test(final String input) {
return this.pattern.matcher(input).matches();
}
}
public class Main {
public static void main(String[] args) {
System.out.println(RegEx.UPPER.test("ABC"));
System.out.println(RegEx.LOWER.test("abc"));
System.out.println(RegEx.NUMERIC.test("+111"));
}
}
Elk lid van het overzicht kan ook de methode implementeren:
import java.util.function.Predicate;
enum Acceptor implements Predicate<String> {
NULL {
@Override
public boolean test(String s) { return s == null; }
},
EMPTY {
@Override
public boolean test(String s) { return s.equals(""); }
},
NULL_OR_EMPTY {
@Override
public boolean test(String s) { return NULL.test(s) || EMPTY.test(s); }
};
}
public class Main {
public static void main(String[] args) {
System.out.println(Acceptor.NULL.test(null)); // true
System.out.println(Acceptor.EMPTY.test("")); // true
System.out.println(Acceptor.NULL_OR_EMPTY.test(" ")); // false
}
}
Enum-polymorfismepatroon
Wanneer een methode een "uitbreidbare" reeks enum
moet accepteren, kan de programmeur polymorfisme toepassen zoals op een normale class
door een interface te maken die overal wordt gebruikt waar de enum
s worden gebruikt:
public interface ExtensibleEnum {
String name();
}
Op deze manier kan elke enum
getagd door (de implementatie van) de interface als een parameter worden gebruikt, waardoor de programmeur een variabele hoeveelheid enum
kan creëren die door de methode wordt geaccepteerd. Dit kan bijvoorbeeld handig zijn in API's waar er een standaard (niet te wijzigen) enum
en de gebruiker van deze API's het enum
met meer waarden wil "uitbreiden".
Een set standaard opsommingswaarden kan als volgt worden gedefinieerd:
public enum DefaultValues implements ExtensibleEnum {
VALUE_ONE, VALUE_TWO;
}
Extra waarden kunnen vervolgens als volgt worden gedefinieerd:
public enum ExtendedValues implements ExtensibleEnum {
VALUE_THREE, VALUE_FOUR;
}
Voorbeeld dat laat zien hoe de enums te gebruiken - merk op hoe printEnum()
waarden van beide enum
typen accepteert:
private void printEnum(ExtensibleEnum val) {
System.out.println(val.name());
}
printEnum(DefaultValues.VALUE_ONE); // VALUE_ONE
printEnum(DefaultValues.VALUE_TWO); // VALUE_TWO
printEnum(ExtendedValues.VALUE_THREE); // VALUE_THREE
printEnum(ExtendedValues.VALUE_FOUR); // VALUE_FOUR
Opmerking: Dit patroon verhindert niet dat u opsommingswaarden, die al in de ene opsomming zijn gedefinieerd, in een andere opsomming opnieuw kunt definiëren. Deze opsommingswaarden zouden dan verschillende instanties zijn. Het is ook niet mogelijk om switch-on-enum te gebruiken, omdat we alleen de interface hebben, niet de echte enum
.
Enums met abstracte methoden
Enums kunnen abstracte methoden definiëren, die elk enum
lid moet implementeren.
enum Action {
DODGE {
public boolean execute(Player player) {
return player.isAttacking();
}
},
ATTACK {
public boolean execute(Player player) {
return player.hasWeapon();
}
},
JUMP {
public boolean execute(Player player) {
return player.getCoordinates().equals(new Coordinates(0, 0));
}
};
public abstract boolean execute(Player player);
}
Hierdoor kan elk opsommingslid zijn eigen gedrag voor een bepaalde bewerking definiëren, zonder typen in een methode in de definitie op het hoogste niveau in te schakelen.
Merk op dat dit patroon een korte vorm is van wat typisch wordt bereikt met behulp van polymorfisme en / of implementatie van interfaces.
Enums documenteren
Niet altijd is de enum
naam duidelijk genoeg om te worden begrepen. Gebruik standaard javadoc om een enum
te documenteren:
/**
* United States coins
*/
public enum Coins {
/**
* One-cent coin, commonly known as a penny,
* is a unit of currency equaling one-hundredth
* of a United States dollar
*/
PENNY(1),
/**
* A nickel is a five-cent coin equaling
* five-hundredth of a United States dollar
*/
NICKEL(5),
/**
* The dime is a ten-cent coin refers to
* one tenth of a United States dollar
*/
DIME(10),
/**
* The quarter is a US coin worth 25 cents,
* one-fourth of a United States dollar
*/
QUARTER(25);
private int value;
Coins(int value){
this.value = value;
}
public int getValue(){
return value;
}
}
De waarden van een opsomming verkrijgen
Elke enum-klasse bevat een impliciete statische methode met de naam values()
. Deze methode retourneert een array met alle waarden van dat getal. U kunt deze methode gebruiken om de waarden te herhalen. Het is echter belangrijk op te merken dat deze methode elke keer een nieuwe array retourneert.
public enum Day {
MONDAY, TUESDAY, WEDNESDAY, THURSDAY, FRIDAY, SATURDAY, SUNDAY;
/**
* Print out all the values in this enum.
*/
public static void printAllDays() {
for(Day day : Day.values()) {
System.out.println(day.name());
}
}
}
Als u een Set
hebt, kunt u ook EnumSet.allOf(Day.class)
.
Enum als parameter van het begrensde type
Bij het schrijven van een klasse met generieke geneesmiddelen in Java, is het mogelijk om ervoor te zorgen dat de parameter type een opsomming is. Omdat alle enums de Enum
klasse uitbreiden, kan de volgende syntaxis worden gebruikt.
public class Holder<T extends Enum<T>> {
public final T value;
public Holder(T init) {
this.value = init;
}
}
In dit voorbeeld, het type T
moet een opsomming zijn.
Krijg enum constant op naam
Stel dat we een enum DayOfWeek
:
enum DayOfWeek {
SUNDAY, MONDAY, TUESDAY, WEDNESDAY, THURSDAY, FRIDAY, SATURDAY;
}
Een opsomming is gecompileerd met een ingebouwde statische waarde van valueOf()
methode die kan worden gebruikt om een constante op te zoeken met zijn naam:
String dayName = DayOfWeek.SUNDAY.name();
assert dayName.equals("SUNDAY");
DayOfWeek day = DayOfWeek.valueOf(dayName);
assert day == DayOfWeek.SUNDAY;
Dit is ook mogelijk met een dynamisch opsommingstype:
Class<DayOfWeek> enumType = DayOfWeek.class;
DayOfWeek day = Enum.valueOf(enumType, "SUNDAY");
assert day == DayOfWeek.SUNDAY;
Beide methoden IllegalArgumentException
valueOf()
IllegalArgumentException
een IllegalArgumentException
als het opgegeven enum geen constante heeft met een overeenkomende naam.
De Guava-bibliotheek biedt een Enums.getIfPresent()
die een Guava Optional
retourneert om expliciete uitzonderingsafhandeling te elimineren:
DayOfWeek defaultDay = DayOfWeek.SUNDAY;
DayOfWeek day = Enums.valueOf(DayOfWeek.class, "INVALID").or(defaultDay);
assert day == DayOfWeek.SUNDAY;
Implementeer Singleton-patroon met een opsomming met één element
Enum-constanten worden geïnstantieerd wanneer voor de eerste keer naar een enum wordt verwezen. Daarom is het mogelijk om het Singleton software-ontwerppatroon te implementeren met een enkel element.
public enum Attendant {
INSTANCE;
private Attendant() {
// perform some initialization routine
}
public void sayHello() {
System.out.println("Hello!");
}
}
public class Main {
public static void main(String... args) {
Attendant.INSTANCE.sayHello();// instantiated at this point
}
}
Volgens het boek "Effective Java" van Joshua Bloch is een opsomming met één element de beste manier om een singleton te implementeren. Deze aanpak heeft de volgende voordelen:
- draad veiligheid
- garantie voor enkele instantiatie
- kant-en-klare serialisatie
En zoals getoond in de sectie implementeert interface, kan deze singleton ook een of meer interfaces implementeren.
Enum met eigenschappen (velden)
In het geval dat we enum
met meer informatie willen gebruiken en niet alleen als constante waarden, en we willen twee enums kunnen vergelijken.
Overweeg het volgende voorbeeld:
public enum Coin {
PENNY(1), NICKEL(5), DIME(10), QUARTER(25);
private final int value;
Coin(int value){
this.value = value;
}
public boolean isGreaterThan(Coin other){
return this.value > other.value;
}
}
Hier hebben we een Enum
genaamd Coin
gedefinieerd die de waarde ervan vertegenwoordigt. Met de werkwijze isGreaterThan
kunnen we vergelijken met twee enum
s:
Coin penny = Coin.PENNY;
Coin dime = Coin.DIME;
System.out.println(penny.isGreaterThan(dime)); // prints: false
System.out.println(dime.isGreaterThan(penny)); // prints: true
Converteer enum naar String
Soms wil je je opsomming omzetten in een string, er zijn twee manieren om dat te doen.
Stel dat we hebben:
public enum Fruit {
APPLE, ORANGE, STRAWBERRY, BANANA, LEMON, GRAPE_FRUIT;
}
Dus hoe converteren we zoiets als Fruit.APPLE
naar "APPLE"
?
Converteren met name()
name()
is een interne methode in enum
die de String
representatie van het enum retourneert, de return String
geeft precies aan hoe de enum-waarde is gedefinieerd.
Bijvoorbeeld:
System.out.println(Fruit.BANANA.name()); // "BANANA"
System.out.println(Fruit.GRAPE_FRUIT.name()); // "GRAPE_FRUIT"
Converteer naar toString()
toString()
wordt standaard genegeerd om hetzelfde gedrag te hebben als name()
toString()
wordt echter waarschijnlijk overschreven door ontwikkelaars om het een gebruiksvriendelijkere String
te laten afdrukken
Gebruik
toString()
als u uw code wilt inchecken,name()
is daarvoor veel stabieler. Gebruik alleentoString()
als u de waarde wilt uitvoeren naar logs of stdout of zoiets
Standaard:
System.out.println(Fruit.BANANA.toString()); // "BANANA"
System.out.println(Fruit.GRAPE_FRUIT.toString()); // "GRAPE_FRUIT"
Voorbeeld van overschreven worden
System.out.println(Fruit.BANANA.toString()); // "Banana"
System.out.println(Fruit.GRAPE_FRUIT.toString()); // "Grape Fruit"
Enum constant specifiek lichaam
In een enum
is het mogelijk om een specifiek gedrag te definiëren voor een bepaalde constante van de enum
die het standaardgedrag van de enum
, deze techniek staat bekend als constant specifiek lichaam .
Stel dat drie pianostudenten - John, Ben en Luke - als volgt zijn gedefinieerd in een enum
naam PianoClass
:
enum PianoClass {
JOHN, BEN, LUKE;
public String getSex() {
return "Male";
}
public String getLevel() {
return "Beginner";
}
}
En op een dag arriveren twee andere studenten - Rita en Tom - met een sekse (Vrouw) en niveau (Gemiddeld) die niet overeenkomen met de vorige:
enum PianoClass2 {
JOHN, BEN, LUKE, RITA, TOM;
public String getSex() {
return "Male"; // issue, Rita is a female
}
public String getLevel() {
return "Beginner"; // issue, Tom is an intermediate student
}
}
zodat het eenvoudigweg niet correct is om de nieuwe studenten als volgt aan de constante aangifte toe te voegen:
PianoClass2 tom = PianoClass2.TOM;
PianoClass2 rita = PianoClass2.RITA;
System.out.println(tom.getLevel()); // prints Beginner -> wrong Tom's not a beginner
System.out.println(rita.getSex()); // prints Male -> wrong Rita's not a male
Het is mogelijk om een specifiek gedrag te definiëren voor elk van de constante, Rita en Tom, die het standaardgedrag van PianoClass2
als volgt PianoClass2
:
enum PianoClass3 {
JOHN, BEN, LUKE,
RITA {
@Override
public String getSex() {
return "Female";
}
},
TOM {
@Override
public String getLevel() {
return "Intermediate";
}
};
public String getSex() {
return "Male";
}
public String getLevel() {
return "Beginner";
}
}
en nu zijn Tom's niveau en Rita's seks zoals ze zouden moeten zijn:
PianoClass3 tom = PianoClass3.TOM;
PianoClass3 rita = PianoClass3.RITA;
System.out.println(tom.getLevel()); // prints Intermediate
System.out.println(rita.getSex()); // prints Female
Een andere manier om een inhoudspecifiek hoofdgedeelte te definiëren, is door constructor te gebruiken, bijvoorbeeld:
enum Friend {
MAT("Male"),
JOHN("Male"),
JANE("Female");
private String gender;
Friend(String gender) {
this.gender = gender;
}
public String getGender() {
return this.gender;
}
}
en gebruik:
Friend mat = Friend.MAT;
Friend john = Friend.JOHN;
Friend jane = Friend.JANE;
System.out.println(mat.getGender()); // Male
System.out.println(john.getGender()); // Male
System.out.println(jane.getGender()); // Female
Geen instantie enum
enum Util {
/* No instances */;
public static int clamp(int min, int max, int i) {
return Math.min(Math.max(i, min), max);
}
// other utility methods...
}
Net zoals enum
kan worden gebruikt voor singletons (klassen van 1 instantie), kan het worden gebruikt voor gebruiksklassen (klassen van 0 instanties). Zorg er wel voor dat je de (lege) lijst met enum-constanten afsluit met een ;
.
Zie de vraag Zero instance enum vs private constructors voor het voorkomen van instantiatie voor een discussie over voor- en nadelen in vergelijking met private constructeurs.
Enums met statische velden
Als uw enum-klasse statische velden moet hebben, houd er dan rekening mee dat ze worden gemaakt na de enum-waarden zelf. Dat betekent dat de volgende code resulteert in een NullPointerException
:
enum Example {
ONE(1), TWO(2);
static Map<String, Integer> integers = new HashMap<>();
private Example(int value) {
integers.put(this.name(), value);
}
}
Een mogelijke manier om dit op te lossen:
enum Example {
ONE(1), TWO(2);
static Map<String, Integer> integers;
private Example(int value) {
putValue(this.name(), value);
}
private static void putValue(String name, int value) {
if (integers == null)
integers = new HashMap<>();
integers.put(name, value);
}
}
Initialiseer het statische veld niet:
enum Example {
ONE(1), TWO(2);
// after initialisisation integers is null!!
static Map<String, Integer> integers = null;
private Example(int value) {
putValue(this.name(), value);
}
private static void putValue(String name, int value) {
if (integers == null)
integers = new HashMap<>();
integers.put(name, value);
}
// !!this may lead to null poiner exception!!
public int getValue(){
return (Example.integers.get(this.name()));
}
}
initialisisation:
- maak de opsommingswaarden
- als bijwerking putValue () genoemd die gehele getallen initialiseert
- de statische waarden zijn ingesteld
- gehele getallen = null; // wordt uitgevoerd na de enums, zodat de inhoud van gehele getallen verloren gaat
Vergelijk en bevat voor Enum-waarden
Enums bevat alleen constanten en kan direct worden vergeleken met ==
. Er is dus alleen referentiecontrole nodig, u hoeft de methode .equals
niet te gebruiken. Bovendien, als .equals
verkeerd gebruikt, kan de NullPointerException
terwijl dat niet het geval is met ==
check.
enum Day {
GOOD, AVERAGE, WORST;
}
public class Test {
public static void main(String[] args) {
Day day = null;
if (day.equals(Day.GOOD)) {//NullPointerException!
System.out.println("Good Day!");
}
if (day == Day.GOOD) {//Always use == to compare enum
System.out.println("Good Day!");
}
}
}
Om de enum-waarden te groeperen, aan te vullen, te variëren, hebben we de EnumSet
klasse die verschillende methoden bevat.
EnumSet#range
: om een subset van enum te krijgen op bereik gedefinieerd door twee eindpuntenEnumSet#of
: Set van specifieke enums zonder bereik. Meerdere overladenof
methoden zijn er.EnumSet#complementOf
: set van enum die een aanvulling is op enum-waarden in de parameter parameterenum Page { A1, A2, A3, A4, A5, A6, A7, A8, A9, A10 } public class Test { public static void main(String[] args) { EnumSet<Page> range = EnumSet.range(Page.A1, Page.A5); if (range.contains(Page.A4)) { System.out.println("Range contains A4"); } EnumSet<Page> of = EnumSet.of(Page.A1, Page.A5, Page.A3); if (of.contains(Page.A1)) { System.out.println("Of contains A1"); } } }