【问题标题】:Why can I catch multiple Exceptions on a catch block, but not put in multiple parameters in a method?为什么我可以在一个 catch 块上捕获多个异常,但不能在一个方法中放入多个参数?
【发布时间】:2013-10-19 19:34:09
【问题描述】:

从 Java 7 开始,以下代码是可能的:

    try{
        ...
    }
    catch(FileNotFoundException | SomeOtherException e){
        e.printStackTrace();
    }

但在方法中模拟语法不是:

    public int test(int |double d){
        ...
    }

而必须这样做

    public int test(int d){
        ...
    }
    public int test(double d){
        ...
    }

或者这个:

    public class Foo<E>{
        ...
        public int test(E something){
            ...
        }
    }

为什么我不能在像 catch 块这样的方法中做这么简单的事情?是什么让 catch 块与众不同(除了捕获异常和它是一个块的事实)?

感谢您的帮助。

【问题讨论】:

  • 因为这就是语言的设计方式。 :)
  • 一个方法可以根据不同的参数类型有不同的功能。
  • 在这种情况下,“只是因为”是一个有效的答案。如果我发了你会接受吗? ;-P
  • 认为这还有更多。
  • 您不需要 int | double,因为 double 可以存储所有可能的 int 值。如果您需要能够参加任何一个,请使用test(Number n),您可以通过任何一个。

标签: java parameter-passing


【解决方案1】:

新的catch 子句中的语法并非完全偏离 OOP 标准。

e 变量的编译器类型是您声明的所有异常的公共超类。因此,如果您声明这样的内容,

catch (IllegalArgumentException | OutOfMemoryError e)

那么e 的实际类型是Throwable,这确实有些道理。因此,在 catch 块内,您不能调用特定于两个异常中的任何一个的方法,而只能调用 Throwable 类中存在的方法。

在你的例子中,

public int test(int | double d)

d 的编译类型是什么? Java 是静态类型的,所以这个声明没有任何意义。

所以我认为在try...catch 的情况下,您可以通过继承静态键入变量;在你的例子中这是不可能的,这就是它被禁止的原因。

【讨论】:

  • 我尝试了类似于class A{} class B{} 的方法,但是当我尝试执行public int test(A|B d) 时,它仍然无法编译,但class Aclass B 都是Objects。那为什么会被禁止呢,还是“仅仅因为 Java 那样工作”?
  • 我认为如果你觉得需要声明public int test(A|B d),但可以或不想声明public int test(Object d),那么你的类设计有问题 - 因为在函数内部你可以在这两种情况下,仅将 d 视为 Object
  • 谢谢,我只是好奇。所以我将其解释为“只是因为 Java 是这样工作的。”
  • 我的意思是“因为它没有意义”:)
  • FWIW 它“没有意义”只是因为 Java 的设计者选择不实现 sum 类型。它在许多其他语言中都具有美丽和优雅的意义。只是说。
【解决方案2】:
try{
        ...
    }
    catch(FileNotFoundException | IOException e){
        e.printStackTrace();
    }

您也不能这样做,因为 FileNotFoundExceptionIOException 的子类:multi-catch 语句中的替代项不能通过子类化关联

【讨论】:

    【解决方案3】:

    当您捕获多个异常时,变量e 具有最接近的公共超类的类型,通常是Exceptionint|double 不能这样做,因为它们没有共同的超类(它们是原语)。

    你可以用方法做类似的事情:

    // Instead of 
    public void test(IOException | NullPointerException e) {...
    // Just write
    public void test(Exception e) { ...
    

    这当然会接受所有例外情况。为了防止这种情况,你可以写:

    public void test(IOException e) {test2(e);}
    public void test(NullPointerException e) {test2(e);}
    private void test2(Exception e) { ...
    

    您可能会争辩说,使用| 运算符作为它的简写会很有用,但碰巧您在现实世界中很少这样做。所以没有实现这个的愿望。

    另一方面,您在捕获异常时经常这样做。在 java 中引入 multi-catch 之前,你经常会看到这样的东西:

    } catch(FileNotFoundException e){
        handleException(e);
    } catch(IllegalArgumentException e){
        handleException(e);
    } catch(SomeOtherException e){
        handleException(e);
    } 
    

    【讨论】:

    • 不是所有类都是对象的子类吗?那么这可以用任何两个类来完成吗?
    • 没错。 intdouble 是原语,所以这是行不通的。您当然可以转换值,但随后您可能会丢失信息。
    • 但是你很少想要这样做。您要么接受超类型(及其子类)的所有实例,要么希望以不同的方式处理子类,例如访问他们声明的一些方法。
    • 我同意,感谢您的回答。我确实尝试过class A{}, class B{} 之类的东西,但是当我尝试public int test(A|B d) 时,它仍然无法编译。
    • 考虑创建一个接口interface MyInterface {..,让AB实现它,然后使用它作为参数类型test(MyInterface aOrB)
    猜你喜欢
    • 2011-03-30
    • 2012-01-16
    • 2011-07-30
    • 1970-01-01
    • 1970-01-01
    • 2012-06-28
    • 2011-09-22
    • 1970-01-01
    相关资源
    最近更新 更多