3

考虑这段代码:

final MyClass myObject;
try {
    myObject = new MyClass(...)
} catch (MyClassException){
    // terminate
    System.exit(1);
}

myObject.doSomething();

问题是 Netbeans 编辑器/解析器认为.doSomething()可以在一个未初始化的对象上调用它,当然事实并非如此。

是否有规避这种情况的正常/标准模式?我可以调用一个函数,但不想那样做。我也不想将整个块包含在 try catch 块中,因为没有其他东西会抛出MyClassException

我还不是(还 ;-) )Java 语法和模式方面的专家,所以希望我遗漏了一些明显的东西。

4

6 回答 6

5

您在try块中初始化对象,这可能会引发异常,使对象未初始化。

在您的代码catch块中,您停止程序,但System.exit(1)不会停止方法执行,相反,它会终止当前正在运行的 JVM - 对于编译器,它只是在引发异常时调用的另一种方法。

return实际上停止了方法的执行 - 所以没有超出代码return;catch您可以按如下方式修改您的块:

catch (MyClassException){
    // terminate
    System.exit(1);
    return;
}

编译器不会抱怨myObject没有以这种方式初始化。

编辑

注意:如果你放入myObject.doSomething();finally编译器会抱怨,因为finally即使在return.

finally {
    // compiler error
    myObject.doSomething();
}
于 2013-05-29T08:49:06.463 回答
1

Netbeans 编辑器/解析器认为 .doSomething() 可以在一个未初始化的对象上调用,当然,情况并非如此。

你在这里错了。您实际上是在尝试初始化变量。编译器不“信任”初始化,原因很简单:它可能会抛出异常,您可以捕获但不能抛出newRuntimeException()或 make a System.exit(1). 例如:

try {
    myObject = new MyClass(...)
} catch (MyClassException e){
    // hey I catch this but do nothing lmao yolo
    e.printStackTrace();
}

myObject.doSomething();

您可以捕获异常,打印堆栈跟踪并继续程序,结果将是NullPointerException.

于 2013-05-29T08:45:45.080 回答
1

这是我能做的最好的:

final MyClass myObject;
{
    MyClass local = null;
    try {
        local = new MyClass(...)
    } catch (MyClassException){
        // terminate
        System.exit(1);
    }
    myObject = local;
}

myObject.doSomething();
于 2013-05-29T08:46:04.900 回答
1

问题是 Netbeans 编辑器/解析器认为 .doSomething() 可以在一个未初始化的对象上调用,当然事实并非如此。

就是这样:没有什么能阻止您使用SecurityManager将禁止System.exit()退出 JVM 的。在这种情况下,可以执行下一条语句。

myObject从 Java 语法的角度来看,编译器需要证明当你调用myObject.doSomething();.

JLS指定了可以执行此操作的情况。特别是,唯一可以用来确定下一条指令不会被执行的语句是breakcontinuereturnthrow。所以编译器不允许考虑这System.exit(1);会阻止下一条语句的执行。

于 2013-05-29T09:03:03.627 回答
1

情况是在 try/catch 块之外,您尝试在可能未实例化的对象上调用方法。doSomething()这是因为 try/catch 块可能会抛出异常,因此不会创建对象,因此在这种情况下,当您尝试对其调用方法时,您将没有对象。

如果在 try/catch 块中包含方法调用,它将起作用。

您可以在此处找到相关信息: Java 教程:课程:异常

于 2013-05-29T08:40:19.687 回答
1

变量和成员的要点final是始终被初始化。尽管您的代码永远不会调用doSomething,但它会使最终字段未定义。如果您finally向 try-catch 块添加子句,这将成为一个问题 - 您可以finally在发生异常时输入该子句并且该子句myObject将不可用,编译器必须避免这种情况。

final MyClass myObject;
try {
    myObject = new MyClass(...); // constructor may throw exception
} catch (MyClassException){
    // terminate
    System.exit(1);
} finally {
    // what does myObject point to now, if the constructor threw exception?
}

myObject.doSomething();

一个快速的解决方案是将doSomething调用移动到 try 块中:

final MyClass myObject;
try {
    myObject = new MyClass(...);
    myObject.doSomething();
} catch (MyClassException){
    // terminate
    System.exit(1);
}

只要doSomething不抛出MyClassException. 如果它抛出这样的异常,你可能需要区分它是来自构造函数还是方法(如果这对你的逻辑很重要)。

于 2013-05-29T08:48:04.610 回答