Java 字段初始化中未处理的异常

Java 字段初始化中未处理的异常,java,exception,initialization,Java,Exception,Initialization,Java是否有任何语法来管理在声明和初始化类的成员变量时可能引发的异常 public class MyClass { // Doesn't compile because constructor can throw IOException private static MyFileWriter x = new MyFileWriter("foo.txt"); ... } 或者,这样的初始化是否总是必须移动到一个方法中,我们可以在该方法中声明抛出IOException或将初始化包装

Java是否有任何语法来管理在声明和初始化类的成员变量时可能引发的异常

public class MyClass
{
  // Doesn't compile because constructor can throw IOException
  private static MyFileWriter x = new MyFileWriter("foo.txt"); 
  ...
}

或者,这样的初始化是否总是必须移动到一个方法中,我们可以在该方法中声明
抛出IOException
或将初始化包装到一个try-catch块中?

最好将这些类型的初始化移动到可以属性处理异常的方法中。

使用静态初始化块

public class MyClass
{
  private static MyFileWriter x;

  static {
    try {
      x = new MyFileWriter("foo.txt"); 
    } catch (Exception e) {
      logging_and _stuff_you_might_want_to_terminate_the_app_here_blah();
    } // end try-catch
  } // end static init block
  ...
}

正如你所发现的,这种建筑是非法的。除非在允许异常处理的上下文中(例如构造函数、实例初始值设定项或(对于静态成员)静态初始值设定项),否则无法构造其构造函数引发选中异常的成员

因此,这将是一种合法的方式:

public class MyClass {
    MyFileWriter x;
    {
        try {
            x = new MyFileWriter("foo.txt");
        } catch (IOException ex) {
            ex.printStackTrace();
        }
    }
    ...
}
合法,但相当丑陋。我宁愿在构造函数中初始化它并在那里声明异常,或者让用户调用一个方法来显式初始化它。但是,如果用户必须初始化它,那么您必须在任何依赖方法中考虑对象无效的可能性

如果您正在编写
MyClass
作为
MyFileWriter
的包装,我会说在构造函数中进行初始化。否则,我首先会问是否有必要在对象的整个生命周期中打开一个writer。有可能重构掉这个

编辑:当我写这篇文章时,“
static
”没有添加到字段中。这改变了很多事情:我现在想知道为什么你想让一个编写器在类加载器的整个生命周期中都处于打开状态。它怎么可能关闭呢


这是某种国产的测井系统吗?如果是这样的话,我建议您看看或看看周围许多优秀的第三方日志框架中的任何一个。

如果类只有一个构造函数,我通常会将此类初始值设定项移动到该构造函数中

如果类有多个构造函数,我将使用初始化块:

public class MyClass {
   private static MyFileWriter x;

   // initialization block start here
   {
       try {
          x = new MyFileWriter("..");
       } catch(Exception e) {
         // exception handling goes here
       }
   }

   public MyClass() { 
    // ctor #1
   }

   public MyClass(int n) { 
     // ctor #2
   }
}

init的好处是。块是指它被“注入”到每个构造函数的开头。因此,您不需要复制初始值设定项。

我建议使用工厂方法:

  public class MyClass{
      private static MyFileWriter fileWriter = MyFileWriter.getFileWriter("foo.txt");

  }

  public class MyFileWriter {
     /*
      * Factory method. Opens files, etc etc 
      * @throws IOException.
      */
     public static MyFileWriter getFileWriter(String path) throws IOException{

        MyFileWriter writer  = new FileWriter();

       //stuff that can throw IOException here.

       return writer;
     }

   /*protected constructor*/
    protected MyFileWriter(){

     //build object here.

    } 
  }

静态初始化器引发的异常可能表示存在设计问题。实际上,您不应该尝试将文件加载到静态中。通常,静态也不应该是可变的

例如,使用JUnit3.8.1,您几乎可以从applet/WebStart使用它,但由于一个静态初始化器进行文件访问,它失败了。所涉及的类的其余部分很好地适应了上下文,只是这一点静态不适合上下文,并将整个框架吹走了

在一些合法的情况下,会抛出异常。如果环境没有特定的功能,比如说,因为它是一个旧的JDK,那么您可能需要替换实现,并且没有什么不寻常的。如果类真的损坏了,抛出一个未检查的异常,而不是允许一个损坏的类存在

根据您的偏好和手头的问题,有两种常见的解决方法:显式静态初始化器和静态方法。(我,我认为大多数人更喜欢前者;我相信乔希·布洛赫更喜欢后者。)

注意:静态应该是最终的(并且通常是不可变的)。作为最终结果,正确的单个赋值将由友好的编译器检查。明确的分配意味着它可能捕获中断的异常处理-包装和抛出,不打印/记录。奇怪的是,您不能使用类名在静态初始化器中使用类名来限定初始化(我相信这是有原因的)


实例初始化器是类似的,尽管您可以使构造函数抛出,也可以将初始化器放在构造函数中。

还有另一种方法来处理字段初始化中的异常。让我们考虑您的情况,MyFieWrror构造函数抛出异常。考虑此示例代码以供参考。

import java.io.IOException;
public class MyFileWriter {
    public MyFileWriter(String file) throws IOException{
         throw new IOException("welcome to [java-latte.blogpspot.in][1]");
    }
}
如果我们尝试像这样初始化文件

public class ExceptionFields{
    MyFileWriter f = new MyFileWriter("Hello");

}
编译器不允许我们对此进行初始化。您可以这样做,而不是在静态块中进行初始化

声明引发IOException的默认构造函数

import java.io.IOException;
public class ExceptionFields{
    MyFileWriter f = new MyFileWriter("Hello");
    public ExceptionFields() throws IOException{    

    }    
}

这将初始化MyFileWriter对象

akf的答案是正确的,但如果您不喜欢声明新方法,也可以使用静态块初始化静态变量;您可以在静态块中使用try/catch,以免其他人将我的上一条评论误读为对静态块方法的认可:我更喜欢创建新方法。我只是为那些不喜欢的人建议了一个替代方案对不起,我忘了将字段标记为静态。建议是否仍然适用?或者您可以使用非静态(即实例)初始化块初始化非静态字段。试着/抓紧工作也一样。(有些人认为这是一个“隐藏的特性”)如果你想在你的处理之后传播,你也可以选择抛出一个RunTimeExchange。如果你有不止一个MyFreWrror成员的类,这不是问题吗?你必须在每个类中重写你的静态块。因为它是一个类成员,这不就是领域吗?如果必须初始化MyFileWriter才能使类正常工作,那么应该抛出RuntimeException,这将阻止类被加载。这将有效地使任何试图使用该类的代码注定失败,如果该类对应用程序的运行至关重要,那么这可能是期望的行为。不这样做的日志记录可能会导致对MyClass方法的每次调用都失败。我在回答中实现了一个工厂方法。这并不能解决问题,在对getFileWriter()的调用中没有异常处理,要添加它,需要添加一个sta
public class ExceptionFields{
    MyFileWriter f = new MyFileWriter("Hello");

}
import java.io.IOException;
public class ExceptionFields{
    MyFileWriter f = new MyFileWriter("Hello");
    public ExceptionFields() throws IOException{    

    }    
}