猿问

Java强制使用枚举开关的方法的默认返回语句,涵盖所有枚举值

我有以下示例情况:


public void shouldReturnStringForEnum() {

    MessageType myType = getType();

    System.out.println(getMessageForType(myType));

}


String getMessageForType(MessageType myType) {

    switch(myType) {

        case error:

            return "Error type";

        case warning:

            return "Warning type";

        case info:

            return "Info type";

    }

} // <= error: missing return statement


MessageType getType() {

    Random random = new Random();

    return MessageType.values()[random.nextInt(3)];

}


enum MessageType {error, warning, info }

我无法弄清楚getMessageForType从switch语句主体以外的其他方式从方法返回的可能性。我在想:


从 I/O 数据反序列化 - 但java.lang.IllegalArgumentException: No enum constant在调用之前很久就发生了getMessageForType

可能的 null 方法参数 - 但它会在switch(myType)评估时失败java.lang.NullPointerException

在这种情况下,强制使用默认的 return 语句是不舒服的,因为我不知道在这里返回什么。在这种情况下抛出异常在这里也没有意义。这种行为背后的设计决策是什么?


请帮忙,我在这里错过了什么?


收到一只叮咚
浏览 165回答 3
3回答

白猪掌柜的

Java强制使用枚举开关的方法的默认返回语句覆盖所有枚举值......这种行为背后的设计决策是什么?这是语言做出的一个非常重要(且正确)的决定。尽管您当前的代码处理了枚举的所有当前值,但这并不意味着在您的代码编译后很长时间内枚举类可能会发生变化。您可能会升级第 3 方库,它可能会添加另一个枚举值,导致您的代码在没有默认值的情况下在运行时无效。即使您控制了枚举代码,也不意味着其他开发人员(或未来的您)可能会向枚举添加另一个值并且无法更新 switch 语句。以这种方式编写向前兼容的代码通常是最佳实践,在这种情况下,对于语言强制行为至关重要。我不知道回到这里做什么。然后问题归结为是否抛出异常。如何处理无效的枚举值或其他异常情况是我们程序员每天都在努力的事情。在这种情况下,你需要问问自己你想要发生什么?这是不应该抛出的烦恼还是更严重的错误?调用者应该处理异常还是可以RuntimeException?这些是您需要在应用程序上下文中回答的问题。最后,我不了解您,但我认识的大多数程序员都剪切并粘贴了大量代码。虽然这个枚举可能永远不会被扩展,但未来的枚举将会被扩展,做出正确的决定可能会受益于适当处理这种情况。在这种情况下,强制使用默认的 return 语句是不舒服的......"Unknown type" 可能是个不错的选择。case ...:&nbsp; &nbsp; &nbsp;return ...;default:&nbsp; &nbsp; &nbsp;// here in case someone updates the enum and forgets to update this code&nbsp; &nbsp; &nbsp;return "Unknown type";在这种情况下抛出异常在这里也没有意义。这在一定程度上取决于返回默认"unknown"字符串的交易有多大。如果有一个缺少 case 条目的新枚举,您是否希望它抛出异常?对于例外情况,您可能需要使用:case ...:&nbsp; &nbsp; &nbsp;return ...;default:&nbsp; &nbsp; &nbsp;throw new IllegalStateException("unknown enum type found for" + mType);或者也许IllegalArgumentException。

繁星点点滴滴

如果稍后编辑枚举,添加新常量,而不重新编译开关,会发生什么情况?这就是要防范的情况。写 是完全正常的default: throw new AssertionError();。

慕码人2483693

在这种情况下抛出异常在这里也没有意义。这是有道理的,因为即使您知道/认为您永远不会进入这里,您也必须处理这种情况,以使您的代码符合 Java 编译规则,即期望该方法String在任何情况下都返回 a 。您可以避免异常抛出,但它会使您的代码不那么健壮:String getMessageForType(MessageType myType) {&nbsp; &nbsp;switch(myType) {&nbsp; &nbsp; &nbsp;case error:&nbsp; &nbsp; &nbsp; &nbsp; return "Error type";&nbsp; &nbsp; &nbsp;case warning:&nbsp; &nbsp; &nbsp; &nbsp; return "Warning type";&nbsp; &nbsp; &nbsp; &nbsp;&nbsp; &nbsp;}&nbsp; &nbsp;return "Info type";&nbsp;}假设fine添加了一个枚举值并且您没有更新,getMessageForType()您将返回“信息类型”而不是。所以这是一个很好的方法:String getMessageForType(MessageType myType) {&nbsp; &nbsp;switch(myType) {&nbsp; &nbsp; &nbsp; case error:&nbsp; &nbsp; &nbsp; &nbsp; return "Error type";&nbsp; &nbsp; case warning:&nbsp; &nbsp; &nbsp; &nbsp; return "Warning type";&nbsp; &nbsp; case info:&nbsp; &nbsp; &nbsp; &nbsp; return "Info type";&nbsp; &nbsp;}&nbsp; &nbsp;throw new RuntimeException("Should not happen here ! We get the enum value " + myType);&nbsp;}更好的方法是将String关联添加到每个枚举作为枚举的实例字段:enum MessageType {&nbsp;ERROR("Error type"), WARNING("Warning type"), INFO("Info type");&nbsp; private String msg;&nbsp; MessageType(String msg){&nbsp;&nbsp; &nbsp; this.msg = msg;&nbsp; }&nbsp; public String getMsg(){&nbsp; &nbsp; &nbsp;return msg;&nbsp; }}通过这种方式,您不再需要 theswitch以及getMessageForType()方法。该shouldReturnStringForEnum()方法可以很简单:@Testpublic void shouldReturnStringForEnum() {&nbsp; &nbsp; System.out.println(getType().getMsg());}
随时随地看视频慕课网APP

相关分类

Java
我要回答