Java 实例 – enum 和 switch 语句使用(长文讲解)
💡一则或许对你有用的小广告
欢迎加入小哈的星球 ,你将获得:专属的项目实战 / 1v1 提问 / Java 学习路线 / 学习打卡 / 每月赠书 / 社群讨论
- 新项目:《从零手撸:仿小红书(微服务架构)》 正在持续爆肝中,基于
Spring Cloud Alibaba + Spring Boot 3.x + JDK 17...
,点击查看项目介绍 ;- 《从零手撸:前后端分离博客项目(全栈开发)》 2 期已完结,演示链接: http://116.62.199.48/ ;
截止目前, 星球 内专栏累计输出 82w+ 字,讲解图 3441+ 张,还在持续爆肝中.. 后续还会上新更多项目,目标是将 Java 领域典型的项目都整一波,如秒杀系统, 在线商城, IM 即时通讯,权限管理,Spring Cloud Alibaba 微服务等等,已有 2900+ 小伙伴加入学习 ,欢迎点击围观
在 Java 编程中,enum(枚举类型) 和 switch 语句 是两个看似基础却极其强大的工具。它们像是一对默契的搭档:enum 可以将一组固定的、可枚举的值类型化,而 switch 则能根据这些值执行不同的逻辑分支。这对组合不仅简化了代码的复杂度,还提升了程序的可读性和安全性。对于编程初学者和中级开发者来说,掌握它们的用法和结合技巧,能显著提升日常开发效率。
本文将通过循序渐进的方式,结合具体实例,深入讲解如何在 Java 中使用 enum 和 switch,并展示它们在实际场景中的协作方式。
2.1 Enum 类型的基础用法
什么是 enum?
Enum(枚举类型) 是 Java 5 引入的一种特殊类,用于定义一组固定且有限的常量。例如,一周有七天,一年有四季,订单状态可能有“待支付”“已发货”“已完成”等。使用 enum 能将这些值类型化,避免使用字符串或整数带来的混乱。
示例:定义一个表示星期的枚举
public enum Day {
MONDAY,
TUESDAY,
WEDNESDAY,
THURSDAY,
FRIDAY,
SATURDAY,
SUNDAY
}
形象比喻:
可以把 enum 理解为一个“值的保险箱”。它将所有可能的值明确列出,就像一个商店的货架,每个位置只能放置特定的商品,确保不会出现“意外”的值。
2.2 Enum 的实例化与使用
直接使用 enum 常量
public class Main {
public static void main(String[] args) {
Day today = Day.MONDAY;
System.out.println("Today is " + today); // 输出:Today is MONDAY
}
}
枚举的隐式功能
Java 的 enum 默认继承自 java.lang.Enum
,因此它具备以下特性:
- 每个 enum 常量都是唯一的实例。
- 可以通过
.name()
获取名称字符串,通过.ordinal()
获取声明顺序的索引(从 0 开始)。
System.out.println(Day.MONDAY.name()); // 输出:MONDAY
System.out.println(Day.MONDAY.ordinal()); // 输出:0
2.3 Switch 语句的语法与进化
传统 switch 的用法
Switch 语句 根据变量的值选择执行不同的代码块。在 Java 12 之前,switch 的参数只能是 byte, short, int, char, String
或 enum 类型。
示例:根据星期判断是否是周末
public static void checkWeekend(Day day) {
switch (day) {
case SATURDAY:
case SUNDAY:
System.out.println("It's a weekend!");
break;
default:
System.out.println("It's a weekday.");
break;
}
}
注意点:
- 必须使用
break
避免“穿透”(fall-through)到下一个 case。 - 未处理的枚举值会进入
default
分支。
2.4 Switch 的箭头语法(Java 12+)
从 Java 12 开始,switch 支持“箭头语法”(也称“表达式模式”),允许更简洁的写法:
public static String getDayName(Day day) {
return switch (day) {
case MONDAY -> "Monday";
case TUESDAY -> "Tuesday";
// ... 其他情况
default -> "Unknown day";
};
}
优势:
- 返回值更直观,无需
break
或return
。 - 可直接作为表达式嵌入其他逻辑。
2.5 Enum 和 Switch 的经典组合:订单状态处理
实例背景
假设我们有一个电商系统,订单状态包括 PENDING
, SHIPPED
, DELIVERED
, CANCELLED
。需要根据状态执行不同的操作,例如:
PENDING
:发送催付提醒。SHIPPED
:更新物流信息。DELIVERED
:关闭订单。CANCELLED
:退款处理。
定义订单状态枚举
public enum OrderStatus {
PENDING,
SHIPPED,
DELIVERED,
CANCELLED
}
使用 switch 处理状态逻辑
public class OrderProcessor {
public static void processOrder(OrderStatus status) {
switch (status) {
case PENDING:
sendPaymentReminder();
break;
case SHIPPED:
updateShippingInfo();
break;
case DELIVERED:
closeOrder();
break;
case CANCELLED:
processRefund();
break;
default:
System.out.println("Unknown status!");
}
}
// 假设这些方法已实现
private static void sendPaymentReminder() { /* ... */ }
// 其他方法同理
}
优势分析:
- 类型安全:避免因拼写错误(如
PENDING
写成PENDINGG
)导致的运行时问题。 - 可维护性:新增状态时,只需修改 enum 和 switch 的 case 分支,无需改动其他代码。
2.6 进阶技巧:为 Enum 添加方法和字段
2.6.1 枚举的构造方法与字段
枚举可以拥有自己的构造方法、字段和方法,使其功能更强大。例如,扩展订单状态枚举,添加状态描述和对应的 HTTP 状态码:
public enum OrderStatus {
PENDING("待支付", 200),
SHIPPED("已发货", 201),
DELIVERED("已完成", 204),
CANCELLED("已取消", 410);
private final String description;
private final int httpStatusCode;
OrderStatus(String description, int httpStatusCode) {
this.description = description;
this.httpStatusCode = httpStatusCode;
}
public String getDescription() {
return description;
}
public int getHttpStatusCode() {
return httpStatusCode;
}
}
使用示例
public static void main(String[] args) {
OrderStatus status = OrderStatus.SHIPPED;
System.out.println(status.getDescription()); // 输出:已发货
System.out.println(status.getHttpStatusCode()); // 输出:201
}
2.6.2 枚举的抽象方法与具体实现
枚举常量可以实现抽象方法,让每个状态拥有独特的行为。例如,为订单状态添加 handle()
方法:
public enum OrderStatus {
PENDING("待支付", 200) {
@Override
void handle() {
sendPaymentReminder();
}
},
SHIPPED("已发货", 201) {
@Override
void handle() {
updateShippingInfo();
}
},
// ... 其他状态同理
private final String description;
private final int httpStatusCode;
// 构造方法、getter 方法省略
// 声明抽象方法
abstract void handle();
}
调用方式
public static void processOrder(OrderStatus status) {
status.handle(); // 直接调用对应状态的方法
}
优势:
- 消除 switch 依赖:通过多态实现行为分离,避免复杂的条件判断。
- 代码更优雅:每个状态自己“知道”如何处理,符合面向对象的设计原则。
2.7 实战案例:天气查询系统
场景描述
开发一个根据天气类型(晴天、雨天、雪天)返回不同建议的系统。
定义天气枚举
public enum WeatherType {
SUNNY("晴天", "建议外出活动!"),
RAINY("雨天", "记得带伞!"),
SNOWY("雪天", "注意防滑!");
private final String description;
private final String advice;
WeatherType(String description, String advice) {
this.description = description;
this.advice = advice;
}
public String getAdvice() {
return advice;
}
}
使用 switch 输出建议
public class WeatherAdvisor {
public static void getAdvice(WeatherType weather) {
switch (weather) {
case SUNNY:
System.out.println("今天是 " + weather.getDescription() + "," + weather.getAdvice());
break;
case RAINY:
System.out.println("今天是 " + weather.getDescription() + "," + weather.getAdvice());
break;
case SNOWY:
SystemOut.println("今天是 " + weather.getDescription() + "," + weather.getAdvice());
break;
}
}
}
进阶优化:利用枚举的 handle() 方法
public enum WeatherType {
SUNNY("晴天", "建议外出活动!") {
@Override
void showAdvice() {
System.out.println("今天是 " + description + "," + advice);
}
},
// 其他枚举常量同理
private final String description;
private final String advice;
WeatherType(String description, String advice) {
this.description = description;
this.advice = advice;
}
abstract void showAdvice();
}
// 调用时只需一行代码
public static void getAdvice(WeatherType weather) {
weather.showAdvice();
}
2.8 常见问题与注意事项
2.8.1 枚举的不可变性
枚举类默认是 final
的,且实例一旦创建便不可变。因此,字段必须声明为 final,且构造方法只能在声明常量时调用。
2.8.2 Switch 的 case 分支顺序
在 switch 中,case 的顺序不影响功能,但建议按逻辑或枚举的定义顺序排列,以提高可读性。
2.8.3 避免遗漏枚举值
如果新增一个 enum 常量,但未在 switch 中处理,编译器会发出警告(EnumSwitchStatementClassifier
)。务必确保所有可能的 case 都被覆盖,或添加 default
处理。
2.9 总结:enum 和 switch 的协同价值
通过本文的讲解,我们可以总结以下几点:
- enum 的核心价值:将一组固定值类型化,提升代码安全性和可维护性。
- switch 的核心作用:根据枚举值执行分支逻辑,替代冗长的 if-else 链。
- 两者的结合场景:订单状态处理、权限控制、配置选项管理等需要多分支判断的场景。
延伸思考:
- 在 Java 17 及更高版本中,switch 可以直接返回值,无需
break
或return
。 - 枚举的
values()
方法可以获取所有常量数组,用于遍历或验证输入值。
掌握 enum 和 switch 的组合技巧,不仅能写出更优雅的代码,还能为学习更复杂的 Java 特性(如注解、策略模式)奠定基础。希望本文的实例和分析,能帮助你在实际开发中游刃有余!