在 java 变量参数列表中至少需要一个元素

在此代码构造中:

public MyClass(Integer... numbers) {
    do_something_with(numbers[]);
}

是否可以要求以这种方式包含至少一个条目,以便在编译时对其进行检查?(当然,在运行时,我只能检查 numbers.length。numbers

显然,我可以这样做:

public MyClass(Integer number, Integer... more_numbers) {
    do_something_with(number, more_numbers[]);
}

但这不会很优雅。

我想这样做的原因是为了确保子类不会简单地忘记调用这个构造函数,这将默认为调用列表中没有数字的构造函数。在这种情况下,我宁愿得到熟悉的错误消息:。super()Implicit super constructor is undefined. Must explicitly invoke another constructor

有没有另一种方法可以实现相同的目标,比如一些将这个构造函数标记为非隐式的@-annotation?


答案 1

我认为至少有1个参数的最好方法是添加一个这样的参数:

public MyClass (int num, int... nums) {
    //Handle num and nums separately
    int total = num;
    for(i=0;i<nums.length;i++) {
        total += nums[i];
    }
    //...
}

将相同类型的参数与 varargs 一起添加将强制构造函数需要它(至少一个参数)。然后,您只需要单独处理第一个参数即可。


答案 2

我想一个非常黑客的方法是创建一个no-args方法并将其标记为已弃用。然后使用以下两个标志进行编译:.这将导致任何使用已弃用的方法的行为都是编译时错误。-Xlint:deprecation -Werror

编辑(在初始答案之后很长一段时间):

一个不那么棘手的解决方案是放弃构造函数并将其替换为(并添加一个私有的no-args构造函数)。它阻止编译器隐式使用超类构造函数,但没有任何参数,并为您提供编译时错误消息。MyClass(Integer... numbers)MyClass(Integer[] numbers)

./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

代价是你的调用语法会变得更加冗长:

new Child(new Integer[] {1, 2, 3});

你当然可以写一个帮助程序函数来帮助解决这个问题,例如。

public static Child newInstance(Integer... numbers) {
    return new Child(numbers);
}

@SafeVarargs
public static <T> T[] array(T... items) {
    return items;
}

然后:

Child c0 = Child.newInstance(1, 2, 3);
Child c1 = new Child(array(1, 2, 3));