当前位置: 首页 > 图灵资讯 > 技术篇> 使Java枚举兼容

使Java枚举兼容

来源:图灵教育
时间:2025-02-18 20:56:44

使java枚举兼容

软件SDK版本与服务器端API版本不一致是很常见的。优秀的SDK可以优雅地处理这种版本差异,并与潜在的API变更兼容。

在Android应用中使用的Java 对于SDK来说,版本兼容性尤为重要,因为用户更新应用程序的速度往往很慢。应用程序不应因使用旧版本的SDK而崩溃。

Java枚举的动态兼容性并不理想。以下是宠物店API的例子:

假设我们设计了代表订单状态的Java枚举:

立即学习“Java免费学习笔记(深入);

enum PetOrderStatus {
    PLACED,
    APPROVED,
    DELIVERED,
}

用户发现枚举比字符串更方便,因为它可以清楚地指示所有可能的状态,并且可以使用switch表达式处理:

String displayText = switch (petOrderStatus) {
    case PLACED -> "Your order was placed and is being reviewed.";
    case APPROVED -> "Your order was approved.";
    case DELIVERED -> "Your order was delivered!";
};

但是,如何将API响应中的字符串转换为枚举常量呢?最常见的方法是使用valueOf():

PetOrderStatus petOrderStatus = PetOrderStatus.valueOf(statusString.toUpperCase());

该方法存在潜在问题:API变更。

假设产品经理要求增加“运输”状态。我们更新SDK:

enum PetOrderStatus {
    PLACED,
    APPROVED,
    IN_TRANSIT,
    DELIVERED,
}

String displayText = switch (petOrderStatus) {
    case PLACED -> "Your order was placed and is being reviewed.";
    case APPROVED -> "Your order was approved.";
    case IN_TRANSIT -> "Your order is on the way!";
    case DELIVERED -> "Your order was delivered!";
};

部署后,我们收到了崩溃报告:

Exception in thread "main" java.lang.IllegalArgumentException: No enum constant PetOrderStatus.IN_TRANSIT
    at java.lang.Enum.valueOf(Enum.java)
    at PetOrderStatus.valueOf(PetOrderStatus.java)

这是因为旧SDK无法识别IN__TRANSIT。valueOf()遇到未知值时,方法会抛出异常。

解决方案

如何避免这种情况?使用Optional的方案是一个方案,未知值返回Optional.empty()。但这并不理想,因为我们无法区分“无状态”和“未知状态”。

更强大的解决方案是存储原始API值,并访问原始值和枚举:

public final class PetOrderStatus {
    private final String value;

    private PetOrderStatus(String value) {
        this.value = value;
    }

    public static PetOrderStatus of(String value) {
        return new PetOrderStatus(value);
    }

    public String _value() {
        return value;
    }

    public Value value() {
        return switch (value) {
            case "PLACED" -> Value.PLACED;
            case "APPROVED" -> Value.APPROVED;
            case "DELIVERED" -> Value.DELIVERED;
            default -> Value._UNKNOWN;
        };
    }

    public enum Value {
        PLACED,
        APPROVED,
        DELIVERED,
        _UNKNOWN,
    }
}

用户可以这样使用:

String displayText = switch (petOrderStatus.value()) {
    case PLACED -> "Your order was placed and is being reviewed.";
    case APPROVED -> "Your order was approved.";
    case DELIVERED -> "Your order was delivered!";
    case _UNKNOWN -> "Your order status is: " + petOrderStatus._value();
};

该设计的优点:

  • 保留了包括详细性检查在内的枚举优势。
  • 能够处理未知状态,并使用原始API值。

API变更:第二部分:

API变更后,使用新的SDK设计不会崩溃。旧版本的应用程序将显示“Your order status is: IN_TRANSIT”。如果我们更新SDK和应用程序,并将IN_TRANSIT添加到枚举中,用户可以在下次更新后看到正确的文本。

以上是Java枚举兼容的详细内容。请关注图灵教育的其他相关文章!