4

Is there any method, other than through static factory methods or builder patterns, to handle default constructor parameters of type array?

There is plenty of fruitful discussion here regarding how to do this with builder patterns and static factory methods, and there are plenty of other examples out there of how to handle various constructors of varying parameter count, but all these patterns appear to include only parameters of simple type (e.g. int, double, etc.), which I have no problem getting to work. I am trying to have a default parameter of type array, and am unable to achieve this with the standard constructor setup.

It tried a few approaches to this and they all result in errors of some kind, so I am searching for an alternative, still making use of a constructor pattern. The first approach:

public class MyClass{

    double[] mWeights;

    public MyClass(){
        double[] weights = {1, 1, 1}
        this(weights);
    }

    public MyClass(double[] weights){
        this.mWeights = weights
    }
}

but this results in an error:

Call to 'this()' must be first statement in constructor body

Alternatively, I tried:

public class MyClass{

    double[] mWeights = new double[] {1, 1, 1};  

    public ActionDistribution(){
        this(mWeights); 
    }  

    public ActionDistribution(double[] weights){  
        this.mWeights = weights;
    }
}

but this results in an error:

Cannot reference 'MyClass.mWeights' before supertype constructor has been called.

Lastly, I tried:

public class MyClass{

    double[] Mweights;  

    public ActionDistribution(){
        this({1, 1, 1}); 
    }  

    public ActionDistribution(double[] weights){  
        this.mWeights = weights;
    }
}

but this results in the error:

Array initializer is not allowed here

Any ideas as to how I can set up a constructor to handle a default array without the use of static factory methods or builder patterns? Bonus points if you have a solution that works for any generic type (and not just arrays), and even more points for explaining why this is possible for simpler data types and not arrays.

Edit: In case it is not clear, in a working form of the code above, I am hoping to later call

MyClass myClass = new MyClass();

and have it result in a myClass object with a field myClass.mWeights of value {1, 1, 1}

3 Answers 3

3

You most likely want to use new double[] { ... } syntax:

class MyClass{

    public MyClass(){
        this(new double[] { 1, 1, 1});
    }

    public MyClass(double[] weights){
        this.mWeights = weights;
    }
}

The array creation syntax is explained in §JLS 15.10.1. Array Creation Expressions. As per §10.6. Array Initializers:

An array initializer may be specified in a field declaration (§8.3, §9.3) or local variable declaration (§14.4), or as part of an array creation expression (§15.10.1), to create an array and provide some initial values.

In your case you are not assigning a field or a local variable so you can't use array initializer shorthand. Method (and constructor) parameters require full array creation syntax.

Sign up to request clarification or add additional context in comments.

2 Comments

Yes! Thank you. Care to comment as to why you can pass simpler types in without this syntax?
I see, so maybe there is no generalized answer to how to setup a default value for use in a constructor of any given data type as it appears to depend on the data type. In summary, you need to ensure the object of type T is initialized within the empty constructor according to its data type initialization rules, and this proper initialization syntax needs to be completely contained within the this() call. Makes sense, but maybe this makes more sense from a readability standpoint? Especially if you are going to have more than one parameter.
2

You can use .. syntax as well:

public class MyClass {

    double[] mWeights;

    public MyClass(double... mWeights) {
        mWeights = mWeights;
    }
    public MyClass(){
        this(1, 2, 3);
    }

}

6 Comments

This also seems to work, but I am not familiar with this syntax. Can you point me some documentation to read up on this? I would like to compare the pros/cons of using this over this answer (Finding the ... string on google is not so easy it seems :P)
it is syntax sugar for arrays ... As a matter of fact, it is the same construction as this ... You can have a quick look to varargs
Thanks for the links. I read through the varargs link and noticed: >Varargs can be used only in the final argument position So how would you handle the case of multiple array type parameters with this syntax? i.e. public MyClass(double... mWeights1, double... mWeights2) will throw an error related to the quoted varargs docs. public MyClass(double... mWeights1, mWeights2) not public MyClass(double... {mWeights1, mWeights2}) appear to work either. Any links to a doc generalizing the syntax of the ellipses?
in case of 'MyClass(double... mWeights1, double... mWeights2)' it will not work and throw a compile exception. The opposite question - What case is it needed?
I was asking if you knew of any place that details the general syntax of how to use the varargs ellipses as I didn't find the Oracle doc very detailed. Although my example code is written for a single parameter, my actual use case involves multiple parameters, so I was hoping to understand the syntax of this a bit better, such that I could try it out with multiple parameters. From the examples here it looks like it is useful for cases where you hope to loop through a single variable length array.
|
1

You could just use your second approach an leave your constructor empty instead:

public class MyClass {

    double[] mWeights = new double[] {1, 1, 1};  

    public ActionDistribution(){}  

    public ActionDistribution(double[] weights){  
        this.mWeights = weights;
    }
}

Ititializing your class with the default empty constructor will leave your weights as you initialized them in your Class field with {1, 1, 1}.

4 Comments

I like this. Seems cleaner than the other solutions.
It also creates a redundant mWeights array that will be discarded by double[] constructor. Perhaps JVM is smart enough to optimize this use case, but it feels sloppy.
@KarolDowbecki As you said it will be discarded, so there won't be any memory issue. I doubt this will have any performance impact.
@KarolDowbecki, at least for my use case, I'm not too worried about this, even if there were some memory drawbacks, as this answer would make the code much more readable for multiple parameters. Though both answers potentially have their own pros/cons.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.