27

在此代码结构中:

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

是否可以要求numbers至少包含一个条目,以便在编译时检查?(当然,在运行时,我可以检查 numbers.length。)

显然我可以这样做:

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?

4

7 回答 7

22

我认为拥有至少 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];
    }
    //...
}

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

于 2015-12-07T19:51:09.423 回答
9

我想一种令人难以置信的 hacky 方法是创建一个无参数方法并将其标记为已弃用。然后用这两个标志编译:-Xlint:deprecation -Werror. 这将导致对已弃用方法的任何使用都成为编译时错误。

编辑(在最初的答案之后很长时间):

一个不那么老套的解决方案是放弃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));
于 2012-10-05T22:23:06.647 回答
8

验证的唯一方法是验证参数。

验证参数:

if (numbers == null || numbers.length == 0 ) {
            throw new IllegalArgumentException("Your angry message comes here");
        }
于 2012-10-05T18:37:34.827 回答
2

如评论中所述,不,似乎不可能强制 var arg 至少大小为 1。

我能想到的唯一编译时修复是简单地要求一个数组 ( Integer[]) 作为构造函数的参数。子类仍然可以在其构造函数中使用 var arg,并且该类的任何其他用户只需在调用构造函数之前从所需的参数创建一个数组。

于 2012-10-05T18:39:02.003 回答
1
public MyClass(boolean ignore, Integer... numbers) {
    do_something_with(numbers[]);
}
于 2012-10-05T19:31:05.220 回答
0

您可以做到这一点的一种非常hacky的方法是制作该方法的私有版本,不带参数。这至少会阻止此类之外的任何人在编译时传递一个参数,但它不会提供有用的错误消息。但是如果它是非常重要的,至少传入一个值,那就是这样。

private MyClass() {
    // This exception will be thrown only if you manage to do a "new MyClass()"
    // within your own class since it is private.
    throw new RuntimeException("Why did you do this?!?"); 
}
于 2012-10-05T18:46:32.177 回答
0

我认为它不在 ̶f̶u̶n̶c̶t̶i̶o̶n̶ 类本身,而是当您调用 ̶f̶u̶n̶c̶t̶i̶o̶n̶ 类时。在调用 ̶f̶u̶n̶c̶t̶i̶o̶n̶ 类之前,请确保您的数组具有元素。

于 2012-10-05T19:45:12.470 回答