2

JAVA-枚举使用

 1 year ago
source link: https://blog.51cto.com/u_13146445/5936656
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.

在本教程中,我们将了解什么是 Java 枚举、它们解决的问题以及它们的一些设计模式如何在实践中使用。

Java 5 首先引入了 enum 关键字。它表示一种特殊类型的类,它总是扩展 java.lang.Enum 类。有关使用的官方文档,我们可以转到​ ​文档​​。 以这种方式定义的常量使代码更具可读性,允许进行编译时检查,预先记录可接受值的列表,并避免由于传入无效值而导致的意外行为。

最简单的定义一个枚举类。

public enum WeekDay {
MONDAY,
TUESDAY,
WEDNESDAY,
THURSDAY,
FRIDAY,
SATURDAY,
SUNDAY
}

3. 自定义枚举方法

下面这个方法,会根据参数local进行判断,如果是"CN"返回值就加1,如果不是就直接返回序数。

int daysOrderInWeek(String local) {
if (local.equals("CN")) {
return ordinal() + 1;
}
return ordinal();
}
public static void main(String[] args) {
System.out.println(WeekDay.MONDAY.daysOrderInWeek("CN"));
System.out.println(WeekDay.MONDAY.daysOrderInWeek("EN"));
}

// 结果
// 1
// 0

可以看到上面的方法是使用枚举中定义的值来访问,如果需要定义枚举类访问的方法,要用static修饰,定义一个静态方法。比如:

static WeekDay firstDayInWeek(String local) {
if (local.equals("CN")) {
return MONDAY;
}
return SUNDAY;
}

// 测试
System.out.println(WeekDay.firstDayInWeek("CN"));
System.out.println(WeekDay.firstDayInWeek("US"));
// 结果
// MONDAY
// SUNDAY

4. 使用“==”比较枚举

由于枚举类型确保JVM中只有一个常量实例,因此我们可以安全地使用“==”运算符来比较两个变量。此外,“==”运算符提供编译时和运行时安全性。

WeekDay firstDayUS = WeekDay.firstDayInWeek("US");
if (firstDayUS == WeekDay.SUNDAY) {
System.out.println("对的,就是这样。");
}

5. 在switch中使用

非常方便和简单。

public void tellItLikeItIs() {
switch (day) {
case MONDAY -> System.out.println("周一很糟糕。");
case FRIDAY -> System.out.println("周五非常好。");
case SATURDAY, SUNDAY -> System.out.println("周末是最好的。");
default -> System.out.println("周中的日子一般般。");
}
}

6. 枚举的字段、方法以及构造函数

public class Pizza {

private PizzaStatus status;
public enum PizzaStatus {
ORDERED (5){
@Override
public boolean isOrdered() {
return true;
}
},
READY (2){
@Override
public boolean isReady() {
return true;
}
},
DELIVERED (0){
@Override
public boolean isDelivered() {
return true;
}
};

private int timeToDelivery;

public boolean isOrdered() {return false;}

public boolean isReady() {return false;}

public boolean isDelivered(){return false;}

public int getTimeToDelivery() {
return timeToDelivery;
}

PizzaStatus (int timeToDelivery) {
this.timeToDelivery = timeToDelivery;
}
}

public boolean isDeliverable() {
return this.status.isReady();
}

public void printTimeToDeliver() {
System.out.println("Time to delivery is " +
this.getStatus().getTimeToDelivery());
}

// Methods that set and get the status variable.
}

测试上面的代码。

@Test
public void givenPizaOrder_whenReady_thenDeliverable() {
Pizza testPz = new Pizza();
testPz.setStatus(Pizza.PizzaStatus.READY);
assertTrue(testPz.isDeliverable());
}

7. EnumSet和EnunMap

7.1 EnumSet

EnumSet 是专门用于 Enum 类型的 Set 实现。

EnumSet<WeekDay> weekends = EnumSet.of(WeekDay.SATURDAY, WeekDay.SUNDAY);
for (WeekDay weekend : weekends) {
System.out.printf("今天是周末:%s\n", weekend.name());
}

List<WeekDay> weekDays = Arrays.stream(WeekDay.values()).filter(WeekDay::isWeekends).toList();
System.out.println(weekDays.size() == weekends.size());

7.2 EnumMap

EnumMap 是一种专门的 Map 实现,旨在与枚举常量一起用作键。与其对应的 HashMap 相比,它是一种高效且紧凑的实现,在内部表示为数组。

定义的时候需要指定keyType

EnumMap<WeekDay, String> nameMap = new EnumMap<>(WeekDay.class);
nameMap.put(WeekDay.MONDAY, "周一");
nameMap.put(WeekDay.TUESDAY, "周二");
nameMap.put(WeekDay.WEDNESDAY, "周三");
nameMap.put(WeekDay.THURSDAY, "周四");

System.out.println(nameMap.get(WeekDay.MONDAY));

8. 使用枚举实现单例模式

通常,使用单例模式实现一个类是非常重要的。枚举提供了一种实现单例的快速简便的方法。

此外,由于枚举类在底层实现了 Serializable 接口,因此 JVM 保证该类是单例。这与传统实现不同,在传统实现中,我们必须确保在反序列化期间不创建新实例。

public enum EnumSingleton {
INSTANCE;

public static EnumSingleton getInstance() {
return INSTANCE;
}

private final WeekDay weekDay = WeekDay.SUNDAY;

public String sundayName() {
return weekDay.name();
}
}

9. 使用枚举实现策略模式

通常,策略模式是通过具有由不同类实现的接口来编写的。 添加新策略意味着添加新的实现类。

使用枚举,我们可以更轻松地实现这一目标,添加新的实现意味着只需定义另一个具有某种实现的实例。

public enum CalculatorEnum {
ADD("+") {
@Override
public int exec(int a, int b) {
return a + b;
}
},
SUB("-") {
@Override
public int exec(int a, int b) {
return a - b;
}
},
MUL("*") {
@Override
public int exec(int a, int b) {
return a * b;
}
};

private final String value;

CalculatorEnum(String value) {
this.value = value;
}

public String getValue() {
return this.value;
}

public abstract int exec(int a, int b);

}

测试一下运行结果:

JAVA-枚举使用_枚举类
public class StrategyTest {
public static void main(String[] args) {
int a = 2;
int b = 3;

System.out.println("两数相加等于:" + exec("+", a, b));
System.out.println("两数相减等于:" + exec("-", a, b));
System.out.println("两数相乘等于:" + exec("*", a, b));
}

private static int exec(String symbol, int a, int b) {
if (symbol.equals(CalculatorEnum.ADD.getValue())) {
return CalculatorEnum.ADD.exec(a, b);
} else if (symbol.equals(CalculatorEnum.SUB.getValue())) {
return CalculatorEnum.SUB.exec(a, b);
} else if (symbol.equals(CalculatorEnum.MUL.getValue())) {
return CalculatorEnum.MUL.exec(a, b);
}
return -1;
}
}

策略枚举是一个非常优秀和方便的模式,但是它受到枚举类型的限制,每个枚举项都是public、final、static的,扩展性收到了一定的约束,因此在系统开发中,策略枚举一般担当不经常发生变化的角色。——《设计模式之禅》

10. 枚举的JSON表示

使用 Jackson 库,可以使用 JSON 表示枚举类型,就好像它们是 POJO 一样。

// 使用注释 修饰枚举类
@JsonFormat(shape = JsonFormat.Shape.OBJECT)

// 修饰字段
@JsonProperty("fieldName")

有关枚举类型的 JSON 序列化/反序列化(包括自定义)的更多信息,我们可以参考 ​ ​Jackson​​。


About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK