Should I instantiate instance variables on declara

2018-12-31 09:06发布

Is there any advantage for either approach?

Example 1:

class A {
    B b = new B();
}

Example 2:

class A {
    B b;

    A() {
         b = new B();
    }
}

13条回答
旧时光的记忆
2楼-- · 2018-12-31 09:49

Example 2 is less flexible. If you add another constructor, you need to remember to instantiate the field in that constructor as well. Just instantiate the field directly, or introduce lazy loading somewhere in a getter.

If instantiation requires more than just a simple new, use an initializer block. This will be run regardless of the constructor used. E.g.

public class A {
    private Properties properties;

    {
        try {
            properties = new Properties();
            properties.load(Thread.currentThread().getContextClassLoader().getResourceAsStream("file.properties"));
        } catch (IOException e) {
            throw new ConfigurationException("Failed to load properties file.", e); // It's a subclass of RuntimeException.
        }
    }

    // ...

}
查看更多
不再属于我。
3楼-- · 2018-12-31 09:53

my personal "rule" (hardly ever broken) is to:

  • declare all variables at the start of a block
  • make all variables final unless they cannot be
  • declare one variable per line
  • never initialize a variable where declared
  • only initialize something in a constructor when it needs data from the constructor to do the initialization

So I would have code like:

public class X
{
    public static final int USED_AS_A_CASE_LABEL = 1; // only exception - the compiler makes me
    private static final int A;
    private final int b;
    private int c;

    static 
    { 
        A = 42; 
    }

    {
        b = 7;
    }

    public X(final int val)
    {
        c = val;
    }

    public void foo(final boolean f)
    {
        final int d;
        final int e;

        d = 7;

        // I will eat my own eyes before using ?: - personal taste.
        if(f)
        {
            e = 1;
        }
        else
        {
            e = 2;
        }
    }
}

This way I am always 100% certain where to look for variables declarations (at the start of a block), and their assignments (as soon as it makes sense after the declaration). This winds up potentially being more efficient as well since you never initialize a variable with a value that is not used (for example declare and init vars and then throw an exception before half of those vars needed to have a value). You also do not wind up doing pointless initialization (like int i = 0; and then later on, before "i" is used, do i = 5;.

I value consistency very much, so following this "rule" is something I do all the time, and it makes it much easier to work with the code since you don't have to hunt around to find things.

Your mileage may vary.

查看更多
十年一品温如言
4楼-- · 2018-12-31 09:53

I think Example 2 is preferable. I think the best practice is to declare outside the constructor and initialize in the constructor.

查看更多
不再属于我。
5楼-- · 2018-12-31 09:55

I take it is almost just a matter of taste, as long as initialization is simple and doesn't need any logic.

The constructor approach is a bit more fragile if you don't use an initializer block, because if you later on add a second constructor and forget to initialize b there, you'll get a null b only when using that last constructor.

See http://java.sun.com/docs/books/tutorial/java/javaOO/initial.html for more details about initialization in Java (and for explanations on initalizer blocks and other not well known initialization features).

查看更多
浪荡孟婆
6楼-- · 2018-12-31 09:56

The second is an example of lazy initialization. First one is more simple initialization, they are essentially same.

查看更多
永恒的永恒
7楼-- · 2018-12-31 09:56

There is one more subtle reason to initialize outside the constructor that no one has mentioned before (very specific I must say). If you are using UML tools to generate class diagrams from the code (reverse engineering), most of the tools I believe will note the initialization of Example 1 and will transfer it to a diagram (if you prefer it to show the initial values, like I do). They will not take these initial values from Example 2. Again, this is a very specific reason - if you are working with UML tools, but once I learned that, I am trying to take all my default values outside of constructor unless, as was mentioned before, there is an issue of possible exception throwing or complicated logic.

查看更多
登录 后发表回答