Подтвердить что ты не робот

Требование хотя бы одного элемента в списке аргументов переменной java

В этой конструкции кода:

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

можно ли требовать, чтобы numbers содержал хотя бы одну запись таким образом, что это проверяется во время компиляции? (Во время выполнения, конечно, я могу просто проверить number.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.

Может ли быть другой способ добиться того же, что и некоторые @-нотации, которые отмечают этот конструктор как неявный?

4b9b3361

Ответ 1

Полагаю, один невероятно удачный способ сделать это - создать метод без аргументов и пометить его как устаревший. Затем скомпилируйте эти два флага: -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));

Ответ 2

Я думаю, что лучший подход, чтобы иметь хотя бы один аргумент, заключается в следующем:

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 заставит конструктор потребовать его (хотя бы один аргумент). Затем вам просто нужно обработать свой первый аргумент отдельно.

Ответ 3

Уникальный способ проверки проверяет параметры.

Подтвердите аргументы:

if (numbers == null || numbers.length == 0 ) {
            throw new IllegalArgumentException("Your angry message comes here");
        }

Ответ 4

Как указано в комментариях, нет, не представляется возможным заставить var arg быть как минимум размером 1.

Единственное исправление времени компиляции, о котором я могу думать, - просто потребовать массив (Integer[]) в качестве аргумента конструктору. Подклассы все равно могли взять var arg в своем конструкторе, и любые другие пользователи класса просто должны были бы создать массив из требуемых аргументов перед вызовом конструктора.

Ответ 5

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

Ответ 6

По-настоящему хакерский способ сделать это - сделать приватную версию этого метода без параметров. Это по крайней мере помешало бы кому-либо, кроме этого класса, передавать один параметр во время компиляции, но это не даст полезного сообщения об ошибке. Но если это очень важно, по крайней мере одно значение передается, что сделает это так.

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?!?"); 
}

Ответ 7

Я думаю, что это не в самом классе ̶f̶u̶n̶c̶t̶i̶o̶n̶, но когда вы называете класс ̶f̶u̶n̶c̶t̶i̶o̶n̶. Убедитесь, что ваш массив имеет элементы перед вызовом класса ̶f̶u̶n̶c̶t̶i̶o̶n̶ с ним.