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";  
    };  
}  

优势

  • 返回值更直观,无需 breakreturn
  • 可直接作为表达式嵌入其他逻辑。

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() { /* ... */ }  
    // 其他方法同理  
}  

优势分析

  1. 类型安全:避免因拼写错误(如 PENDING 写成 PENDINGG)导致的运行时问题。
  2. 可维护性:新增状态时,只需修改 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 的协同价值

通过本文的讲解,我们可以总结以下几点:

  1. enum 的核心价值:将一组固定值类型化,提升代码安全性和可维护性。
  2. switch 的核心作用:根据枚举值执行分支逻辑,替代冗长的 if-else 链。
  3. 两者的结合场景:订单状态处理、权限控制、配置选项管理等需要多分支判断的场景。

延伸思考

  • 在 Java 17 及更高版本中,switch 可以直接返回值,无需 breakreturn
  • 枚举的 values() 方法可以获取所有常量数组,用于遍历或验证输入值。

掌握 enum 和 switch 的组合技巧,不仅能写出更优雅的代码,还能为学习更复杂的 Java 特性(如注解、策略模式)奠定基础。希望本文的实例和分析,能帮助你在实际开发中游刃有余!

最新发布