In this code construct:
public MyClass(Integer... numbers) {
do_something_with(numbers[]);
}
is it possible to require that numbers
contains at least one entry in such a way, that this is checked at compile-time? (At run-time, of course, I can just check numbers.length.)
Clearly I could do this:
public MyClass(Integer number, Integer... more_numbers) {
do_something_with(number, more_numbers[]);
}
but this isn't going to be very elegant.
The reason I would like to do this is to make sure that a sub-class does not simply forget to call this constructor at all, which will default to a call to super()
with no numbers in the list. In this case, I would rather like to get the familiar error message: Implicit super constructor is undefined. Must explicitly invoke another constructor
.
Could there be another way to achieve the same, like some @-annotation that marks this constructor as non-implicit?
I suppose one incredibly hacky way to do this is to create a no-args method and mark it as deprecated. Then compile with these two flags: -Xlint:deprecation -Werror
. This will cause any use of a deprecated method to be a compile time error.
edit (a long time after the initial answer):
A less hacky solution would be to ditch the MyClass(Integer... numbers)
constructor and replace it with MyClass(Integer[] numbers)
(and add a private no-args constructor). It stops the compiler from being able to implicitly use the super class constructor, but without any args, and gives you a compile time error message.
./some_package/Child.java:7: error: constructor Parent in class Parent cannot be applied to given types;
public Child(Integer[] args) {
^
required: Integer[]
found: no arguments
reason: actual and formal argument lists differ in length
The cost is your calling syntax will become a bit more verbose:
new Child(new Integer[] {1, 2, 3});
You can of course write a helper functions to help with this eg.
public static Child newInstance(Integer... numbers) {
return new Child(numbers);
}
@SafeVarargs
public static <T> T[] array(T... items) {
return items;
}
and then:
Child c0 = Child.newInstance(1, 2, 3);
Child c1 = new Child(array(1, 2, 3));