在紧凑结构中抛出异常时的“未处理的异常类型”StringConverter 情况

问题描述

我相信这一定是我对语法的无知。

我想创建一个方法来创建并返回一个 StringConverter 对象。问题是该对象必须在其方法之一中抛出异常。我相信我一直失败是因为语法。

我有两个例子,最后一个编译得很好。

查看第一种方法,Eclipse 说“未处理的异常类型 CharConversionException”:

public static StringConverter<String> creditoDebito() {
        return new StringConverter<String>() {
            @Override
            public String fromString(String arg0) {
                switch(arg0.charat(0)) {
                case 'D':
                case 'd':
                    return "Débito";
                default:
                    throw new CharConversionException();
                }
            }
        }; 
    }

看看一个成功的例子,它编译得很好:

public static StringConverter<BigDecimal> numberCellConverter(){
    return new StringConverter<BigDecimal>() {
        @Override
        public BigDecimal fromString(String arg0) {
            Pattern patternDefault = Pattern.compile("\\d*");
            Matcher matcher = patternDefault.matcher(arg0);
            if(matcher.find()) {
                return new BigDecimal(arg0);
            }else {
                throw new NumberFormatException();
            }
        }
    };
}

这两种情况有什么区别?为什么 NumberFormatException 会编译而另一个不编译?

解决方法

例外不仅仅是一个有趣的名字。您不应该仅仅因为名称听起来模糊相关而使用异常。 CharConversionException 是关于字符集编码的问题,例如XML读取;关键是,它扩展了 IOException,所以它是一种“输入/输出通道的问题”,它在这里并不适用。制作您自己的异常类型,或者使用一种更通用的异常类型(通过阅读 javadoc 并检查继承)有意设计的更模糊一些。例如,可以在此处使用 IllegalArgumentException(如果参数不以 D 或 d 开头,这显然是非法的?有点奇怪的方法)。

区别在于它是哪种异常。

在 Java 中,throwables 被检查,这意味着,一个方法需要捕获它抛出的所有异常,除非它明确规定它自己抛出这个。因此,这不会编译:

public void test() {
    throw new IOException();
}

而这样做:

public void test() throws IOException {
   throw new IOException();
}

请注意,通过调用一个声明它抛出某些东西的方法,你继承了这个“捕获它或声明你重新抛出它”。因此,这不会编译:

public void test2() {
   test(); // declared to `throws IOException`
}

而这样做:

public void test2() throws IOException {
   test();
}

请注意,public static void main(String[] args) 允许(并且通常应该!)仅声明为 throws Exception

Java 有另一条规则可以解释 NumberFormatException 获得通过的原因:所有方法都假定为 throws RuntimeException,Error(例如,可以抛出 RuntimeException 和 Error 实例),无论您是否编写。

检查 NumberFormatException 的层次结构:它是 RuntimeException 的特化,因此,本质上所有方法都声明为 throws 是。 CharConversionException extends IOException extends Exception extends Throwable - 该列表中没有任何内容是 RuntimeException 或 Error,因此不允许通过。

更糟糕的是,如果您要从超类型实现方法(例如这里;您正在覆盖 public String fromString(String arg) 方法),则不能只在声明中添加新方法。毕竟,您正在编写一种 StringConverter,这意味着任何人都可以将您新定义的类的实例视为 StringConverter,而 StringConverter 的 fromString 方法没有声明它,因此,您被卡住了。

幸运的是,正如我所说,CharConversionException 是不合适的,但 IllegalArgumentException 可能是,并且 IllegalArgumentException 是未经检查的(它扩展了 RuntimeException,因此,您可以随意抛出它,因为所有方法都被默默地假定为这样做)。