views:

325

answers:

11
+2  Q: 

Constructor (Java)

Hi,

I wonder if it's a big error (in small one class Java program) when I define variable in a class level rather that using the constructor? Can we do that?

The method body will be the same in both cases.

Many thanks!

eg.

public class test{

    static int column1 = 0;
    static int column2 = 1;

    public static void main(String[] args){
    // do something with variables, no return
    }

    /...../

}
+2  A: 

Do you mean doing something like this?

public class MyClass
{
    private int _someInt = 13;
    private String _someString = "I'm a string.";
}

If that's what you mean, I see nothing wrong with doing that, it's equivalent to initializing it in the constructor.

nasufara
+5  A: 

You mean

public class Foo {
    private String test = "Hello";
    ...
}

instead of

public class Foo {
    private String test;

    public Foo() {
        test = "Hello";
    }
}

I actually prefer the first method, it is much cleaner. If you know the value ahead of time and it's a constant, you should set the value as you define it. No reason not to from a technical standpoint, and it looks much cleaner.

Update

Given the code sample you add, what you're doing is fine. One thing to consider is that your constants should be final. In your case they should likely be private static final int.

jcm
And if the value does not change, it's best to mark it as final. Immutable objects have lots of benefits.
Esko Luontola
If the value doesn't change, best to mark it *static* final.
T.J. Crowder
@Esko: marking a field final does not make it immutable - there's more to it than that. E.g. `private final HashMap = ...` does not make the enclosing class immutable. Possibly you are mixing terms up. You are right to mark it final if it doesn't change though, if only from a design documentation standpoint.
Grundlefleck
+3  A: 

If you mean (as jcm said):

public class Foo {
    private String test = "Hello";
    ...
}

instead of (small edit here):

public class Foo {
    private String test;

    public Foo() {
        this.test = "Hello";
    }
}

If it's a constant, then make it a constant. If it isn't, then its value is dependent on the runtime sequence, and I'd plump for the second of those, not the first. I'm not a fan of initializing at declaration-time, it means I have to look at too many places for values. As a matter of style (and this is style, not substance, for the most part), I prefer to declare declarations and assign assignments, not inter-mix the two. Constants are a different thing.

But in a small one-class application, it's not like it matters much.

Edit: Allowing for your updated code example, which uses class fields rather than instance fields, I probably wouldn't do that at all. (And the question kind of doesn't make sense any more; constructors have nothing to do with static fields.) FWIW, I would generally initialize static fields at declaration time because anything else is very uncommon, even though there are things called "static initializers" you can use when order is important:

static int foo;
static int bar;

// Static initializer
static {
    foo = 7;
    bar = foo + 1;
}

But in my experience, their use is rare enough that the least surprising thing is just to initialize the statics at declaration time.

T.J. Crowder
+3  A: 

It doesn't make any difference.

Chad Okere
+3  A: 

Actually,

if these attributes should have a default value, and your class have more than one constructor, may be a good idea do initiate these variables in "class level", since you may forget to set value of some of these variables.

Of course, you could create a method to start these varibles, but even so, you could forget to call this method from some of your constructors.

So, in this sense, this could be considered a good practice.

Kico Lobo
Actually, if you have complicated initialization and want to have default values, the Builder pattern is a more recognized Java idiom (instead of using many constructors for setting different variables).
Tom
Yeah, builder or have the various constructors all chain to the no-args constructor by starting with `this()`.
T.J. Crowder
+2  A: 

Based on your edits, looks like you are really asking about whether it is OK to use static variables. (I note with @T.J. that you don't have a constructor at all in your example program!)

My answer to that is:

  • In general, static variables are bad style and a bad idea.

  • In a small application consisting of a single class, it won't make much difference ... unless you later decide to reuse the class in something larger.

On the other hand, static constants are not bad style; e.g.

static final int COLUMN_1 = 0;
static final int COLUMN_2 = 1;

A rewrite of your example that eliminates the static variables would look something like this:

public class Test2 {

    private int column1 = 0;
    private int column2 = 1;

    public static void main(String[] args) {
        new Test2.run(args);
    }

    private void run(String[] args) {
        /* do something with the variables */
    }

    /* ... */
}

The advantage of this over the original version is that you can now safely reuse the Test2 class in other contexts. For example this will work:

for (int i = 1; i < 10; i++) {
    // call "new Test2().run(args)" in a new thread
}

where this is likely to be buggy due to static coupling:

for (int i = 1; i < 10; i++) {
    // call "test.main(args)" in a new thread
}
Stephen C
+1  A: 

As a style note, if you're talking about instance variables and where you should initialize those - if in the constructor or in the declaration, I usually prefer initializing in the constructor only what's passed to the constructor (or that are dependent of those parameters), and initializing in the declaration what is not. I think it's cleaner that way.

Ravi Wallau
A: 

an one-off little program of only main() method? why not.

but a better way is to put it inside main

public class test{
  public static void main(String[] args){
    int column1 = 0;
    int column2 = 1;
    // do something with variables, no return
  }
}
irreputable
+1  A: 

Here is how I do variables in Java:

  1. everything is final unless it proves that it cannot be.
  2. nothing is initialized when it is declared unless it has to be (only those used in switch are done differently)
  3. every variable has as small a scope (this includes visibility) as possible

Given that you have the following cases:

public class Foo 
{
    // constants must always be immutable (no changeable state)
    public static final String EXTERNAL_CONSTANT;
    private static final String INTERNAL_CONSTANT;

    public static final int EXTERNAL_CONSTANT_USED_IN_SWITCH = 1;
    private static final int INTERNAL_CONSTANT_USED_IN_SWITCH = 2; 

     // no public variables that can be modified
     private static int internalClassVariable;

     static
     {
         EXTERNAL_CONSTANT = "Hello";
         INTERNAL_CONSTANT = "World";
     }

     private final List<String> constantsMustBeStaticAndFinal;
     private int instanceVariable;

     {
         constantsMustBeStaticAndFinal = new ArrayList<String>();
     }

     public Foo(final int parametersAreAlwaysFinal)
     {
         final int localVariable;

         locatlVariable   = parameterAreALwaysFinal * 10;
         instanceVariable = localVariable;
     } 
}

To summarize:

  • constants are always UPPER_CASE
  • class variables are always mixedCase
  • constants are always initialized in a static block unless they are used in a switch (compiler requirement)
  • class variables are always initialized in a static block
  • instance variables are always mixedCase
  • instance variables where the value is known at compile time are initialized in an instance block
  • instance variables where the value is not known at compile time are initialized in the constructors

The has the benefits of:

  • can read values from a file (say properties file) since the initialization happens in the static ore
  • instance block where you can do things like open the file
  • since they are mostly final the compiler will let you know when you forget to initialize them
  • since they are mostly final you have a better chance of having immutable classes which is a safer way to code
  • you have a few well defined places to look for where variables get their values
  • you can more easily make changes to variable initialization later without screwing it up

For that lost point, consider the following code:

{
    int x = 0;    

    // this line added later
    x = 7;
}

Why set x to 0 and then to 7 without ever using the 0 (this is a simple case, some are more expensive at runtime). If x was marked as final the person changing it to 7 would realize that they have to get rid of setting it to the pointless 0.

I have been programming in this sort of way since using C/C++ professionally starting in about 1993 (for Java since 1995), and it has served me well.

TofuBeer
+1  A: 

I'm assuming your question is essentially whether it is more proper to assign a default/initial value at the class variable's declaration or in a constructor. If that's the case, as most of the responses have indicated, it mostly boils down to a style preference.

In my experience, I've found that assigning a default value at the class-level declaration makes the code generally more readable and makes the management of the class's constructors a little more manageable. (i.e. you don't have to a) worry about setting the value in multiple places if your class as multiple constructors or b) worry about creating a generic initialization method that must be called from each constructor).

There is really no harm in setting the default/initial value of a class variable in the constructor and for small single-constructor classes, the merits of either choice are more or less equal. However if your anticipate the class may grow over time, I would find assigning the value at the declaration would make enhancement of the class a little easier.

Mark
+2  A: 

There's some good advice in other comments about scoping of variables. I have another related remark. I often notice developers getting confused with instance/static variables due to starting off with the main(String arg) method. Because this method is static, one tends to not bother with creating an instance, and ends up with only static methods and fields. This is no problem for a tiny piece of test code, but as soon as you need multiple classes and an Object-Oriented design, it becomes a nuisance very quickly.

A useful way to avoid this would be to not start off with the main method, but with a unit test:

import junit.framework.Assert;
import junit.framework.TestCase;

public class MyAppTest extends TestCase {

    public void testCreateMessage() {

        MyApp myApp = new MyApp("Always write a Te");            
        String message= myApp.createMessage("stackoverflow");   
        assertEquals("Always write a Test", message); 
    }
}

Remember to put tests in a separate source directory, i.e. src/test/java vs src/main/java for your application code. This makes it easier to run and deploy your application code separately and follows the Maven 2 default layout.

Then your class could look like this (slightly modified to suit my explanation):

public class MyApp {

    // constants always like this
    private static final int COLUMN_ONE = 0;
    private static final int COLUMN_TWO = 1;

    // make instance variables final if possible
    private final String name;

    public MyApp(String name) {
        this.name = name;
    }

    public void String createMessage(String arg) {
        return name + arg.charAt(COLUMN_ONE) + arg.charAt(COLUMN_TWO);            
    }    
}

Now just run your unit test. In Eclipse, right-click on the class MyAppTest and choose "Run as JUnit test". In this way you will start off on the right Object-Oriented foot.

If you later want to make your application executable, you can either add a main method to MyApp, or create a small bootstrap class to do the work:

public class MyAppStarter {

    public static void main(String[] args) {

        MyApp myApp = new MyApp(args[0]);
        System.out.println(myApp.createMessage("!!"));
    }
}

The nice thing of this solution is that you can keep the parsing of commandline arguments and other operational details of starting your application separated from the business code.

Adriaan Koster