如何从枚举构造函数中抛出异常?

20

如何从枚举构造函数中抛出异常?例如:

public enum RLoader {
  INSTANCE;
  private RLoader() throws IOException {
   ....
  }
}

产生了错误

未处理的异常类型 IOException


7
为什么你要这样做?在我看来,这听起来像是对枚举概念的滥用。枚举值应该是常量,其创建不依赖于任何内容。即使从技术上讲你确实可以这样做(通过抛出未经检查的异常而不是已检查的异常),我建议你重新设计。如果你想通过这个枚举来实现单例,最好手动实现一个普通类来实现它。 - Péter Török
2
我正在实现一个单例模式,但是手动实现为普通类有什么好处呢?我仍然必须从静态初始化程序调用的代码中抛出异常。您可以从枚举构造函数中抛出未经检查的异常。 - tekumara
仅通过访问枚举值就抛出异常,这种情况总是让人感到有些不舒服。但如果是单例的getInstance()方法,情况就没那么糟糕了。 - Kirk Woll
1
@Péter Török,手动实现为普通类有什么好处吗?我认为使用枚举实现单例是可以的,就像<Effective Java>所说的那样。 - bylijinnan
@PéterTörök,就我理解,特别是针对这种情况,您为什么认为“如果您想通过此枚举实现单例模式,最好手动实现它作为普通类。”? - Abhishek Garg
3个回答

23

由于实例是在静态初始化程序中创建的,因此应该抛出 ExceptionInInitializerError

throw new ExceptionInInitializerError();

6
虽然那是一个可能的解决方案,但我认为用那种方式来解决问题并不合理。 - Johannes Wachter

4

我有这样一个情况,我想在一些设置类中使用枚举作为键。数据库将存储一个字符串值,允许我们更改枚举常量而无需更新数据库(有点丑陋,我知道)。我希望在枚举的构造函数中引发运行时异常,以此来限制字符串参数的长度,避免在数据库中出现约束违规,并且我可以轻松地自己检测到它。

public enum GlobalSettingKey {
    EXAMPLE("example");

    private String value;

    private GlobalSettingKey(String value) {
        if (value.length() > 200) {
            throw new IllegalArgumentException("you can't do that");
        }
        this.value = value;
    }

    @Override
    public String toString() {
        return value;
    }
}

当我为此创建了一个快速测试时,我发现抛出的异常不是我的异常,而是ExceptionInInitializerError异常。
也许这很愚蠢,但我认为在静态初始化程序中想要抛出异常是一个相当合理的情况。

3
但是原始异常与ExceptionInInitializerError链接在一起,因此如果您对它调用'getCause()',您将获得原始异常。 - shrini1000

1

这种情况行不通。

您正在尝试从构造函数中抛出已检查的异常

此构造函数由INSTANCE枚举条目声明调用,因此无法正确处理已检查的异常。

而且,在我看来,从构造函数中抛出异常是不好的风格,因为构造函数通常不应该做任何工作,尤其不应该创建错误。

另外,如果您想抛出一个IOException,我假设您想从文件初始化某些内容,因此您应该考虑阅读这篇关于动态枚举的文章。


3
如果从构造函数中抛出异常是不好的风格,那么当构造函数参数无效并且会导致类无法正常工作时该怎么办?我更喜欢通过抛出异常来快速失败,以便获得有意义的堆栈跟踪。话虽如此,我同意您的看法,即该用户不应该在枚举的构造函数中尝试抛出异常。 - Kirk Woll
@Kirk Woll:我更喜欢使用确保参数有效性的工厂方法。此外,我主要关注的是已检查异常,根据我的看法,RuntimeException是一种更好的信号验证错误的方式。 - Johannes Wachter
2
所有对象实例化都要使用工厂方法,哦可怜的、不幸的 new 操作符。 :) - Kirk Woll
@Kirk Woll:不是所有实例化都需要,只有在需要构造函数参数的特殊验证时才需要。通常我使用的原则是除了赋值之外不要在构造函数内部进行任何工作,所以我没有像你一样编程得那么快速失败 :) - Johannes Wachter
5
从工厂方法和构造函数中抛出异常,真的有什么区别吗?你说番茄我说西红柿。 - matt b
关于工厂方法,有些人更喜欢它们而不是构造函数。来自《Effective Java》一书中的“第1条:考虑使用静态工厂方法代替构造函数”。当然,并非总是如此,也不是显式地使用异常处理,这是另一回事。 - Anddo

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接