0

我有一个具有以下模式的 Java 代码:

enum Foo
{
    ORANGE, APPLE, BANANA
}

Foo bar()
{
    switch(calcValue())
    {
        case "orange": return ORANGE;
        case "apple": return APPLE;
        case "banana": return BANANA;
    }
}

方法的设计calcValue确保它只返回switch 语句检查的三个字符串。如果它不能返回三个字符串中的任何一个,它就会抛出异常。这意味着缺少的default关键字可能是不必要的,并且永远不会触发默认开关行为,因此default被省略。然而,Java 自然地(并且通常如此)抱怨bar必须(总是)返回一个值。我正在考虑将异常作为默认值抛出,但如前所述,calcValue已经抛出异常。我主要是在一个简单高效(涉及最少运行时检查和代码)的设计之后解决这个小问题——我不想抛出两个异常,并且calcValue不在我的控制之下,所以我无能为力。

我希望我在这里已经很好地解释了自己,如果没有,我会尽力澄清。本质上,这是关于设计具有已知开关默认值不适用的值的方法。这也可能适用于if-then-else-if-then-else-...-then-else语句模式。

4

7 回答 7

2

你写了

calcValue 方法的设计确保它只返回 switch 语句检查的三个字符串。

但是,本合同并未以 的签名表示calcValue;它只是返回一个字符串,Java 的类型检查器无法知道只有一些字符串是可能的。我认为这是calcValue函数 API 中的一个缺陷。

底线是 Java 是正确的 - 您确实缺少default案例,因为您对内部工作原理的假设calcValue不是由类型系统强制执行的,因此它可能随时更改而编译器不会注意到。

于 2012-09-28T09:29:59.497 回答
1

在我看来,长 if/then/else 和 switch 语句是一个不好的迹象。我更喜欢尽可能以面向对象的风格写作。

就像使用 Map 一样,传入键并返回值。

您的简单示例可以而且应该是一个枚举。

于 2012-09-28T09:22:10.683 回答
1

即使calcValue()在默认情况下抛出错误,这是一个合乎逻辑的结论,Java 编译器不会理解这一点,因此抱怨没有返回的代码路径。对于默认情况,您也必须从此方法中引发异常。

于 2012-09-28T09:23:06.830 回答
1

这是有充分理由的;因为你不控制 calcValue(),你应该有代码来处理未来的变化。

但是,如果您想按上述方式继续,请将最后一种情况更改为默认值,以便在没有 ORANGE 或 APPLE 的情况下始终返回“BANANA”。

于 2012-09-28T09:24:04.147 回答
1

你说

calcValue 不在我的控制之下

然后,你不应该依赖它,它总是throw一个例外。

您应该添加default到您的switch构造中,并且如果控制到达那里应该抛出异常。

另一点是您的bar()方法本身应该是完整的。

您正试图使其与calcValue(). 的签名合同Bar()说它总是会返回 aFoo但不是这样做你依赖于calcValue()执行合同;这是错误的。

于 2012-09-28T09:24:49.940 回答
1

没有直接回答这个问题,但也许它会简化使用Enum.valueOf(). 如果calcValue()保证返回这三个值之一,您可以这样做:

enum Foo { ORANGE, APPLE, BANANA }

Foo bar() { return Foo.valueOf(calcValue().toUpperCase()); }

并将决定委托给Enum.valueOf,顺便说一下,IllegalArgumentException如果没有这样的元素,它会抛出一个。

于 2012-09-28T09:28:36.907 回答
1

一个常见的模式是让枚举知道如何正确翻译自己

public enum Foo {
    BANANA("banana"),
    ORANGE("orange"),
    APPLE("apple");

private String calculationCode;

private Foo(String calculationCode) {
    this.calculationCode=calculationCode;
}

public static Foo byCalculationCode(String code) {
    for (Foo foo : values()) {
        if (foo.calculationCode.equals(code)) {
            return foo;
        }
    }
    throw new NoSuchElementException("Unknown code:" + code);
}
于 2012-09-28T10:23:57.763 回答