Java varargs

Стаття з групи Random UA
Сьогодні ми обговоримо таку штуку як varargs у Java. Varargs або Variable Arguments — це технологія, яка дозволяє створювати методи з довільною кількістю аргументів. У цій статті ми навчимося створювати такі методи, обговоримо, навіщо потрібні varargs і коли їх краще використовувати.

Що таке varargs?

Varargs - це аргументи змінної довжини: фіча, яка з'явилася ще JDK5. Varargs дозволяють нам створювати методи із довільною кількістю аргументів. За великим рахунком, створювати такі методи можна було раніше. Щоправда, робити це було не дуже зручно. Наведемо приклад. Припустимо, нам необхідно написати метод, який прийматиме довільну кількість цілих аргументів і складатиме їх разом. Java varargs - 1У нас є два варіанти. Варіант 1 - перевантаження:
class Calculator {
    int sum(int a, int b){...};
    int sum(int a, int b, int c){...};
    int sum(int a, int b, int c, int d){...};
    int sum(int a, int b, int c, int d, int e){...};
}
Але з навантаженням виникають дві проблеми. По-перше, не завжди зрозуміло, коли настав час зупинитися, а по-друге, це громіздко. Краще масиви. Варіант 2 - масиви:
class Calculator {
    int sum(int[] numbers){...};
}
З масивом вже не громіздко, і як би масив виглядає нічого так ... до тих пір, поки не прийде час викликати метод:
public static void main(String... sss) {
    Calculator calculator = new Calculator();

    int[] arguments = new int[7];
    arguments[0] = 1;
    arguments[1] = 10;
    arguments[2] = 123;
    arguments[3] = 234;
    arguments[4] = 6234;
    arguments[5] = 12;
    arguments[6] = 8;

    int sum = calculator.sum(arguments);
}
Згодні, можна, звичайно, і коротше записати. Але по-перше, хочеться все-таки продемонструвати незручність використання масивів як аргументи змінної довжини, а по-друге, навіть якщо ми запишемо так:
int[] arguments = {1,10,123,234,6234,12,8};
int sum = calculator.sum(arguments);
То ми все одно не позбудемося зайвої кількості коду. Однак із виходом Java 5 для вирішення цих проблем з'явилася фіча Varargs. Вона дозволила передавати до методів довільну кількість аргументів. Виглядає це приблизно так:
public class Calculator {
    public static void main(String... sss) {
        Calculator calculator = new Calculator();
        int sum = calculator.sum(1,10,123,234,6234,12,8);
    }
    int sum(int... numbers){
       return Arrays.stream(numbers).sum();
    }
}
Отже, резюмуємо. Varargs - це аргументи змінної довжини, фіча, яка з'явилася з виходом Java 5. Далі детальніше розглянемо деякі правила роботи з Varargs.

5 правил varargs

Правило 1. Vararg аргумент (або аргумент змінної/довільної довжини) позначається через три крапки наступним чином:
String... words
Integer... numbers
Person... people
Cat... cats
Правило 2. Аргумент довільної довжини може бути зазначений лише як аргумент деякого методу:
void print(String... words)
int sum(Integer... numbers)
void save(Person... people)
void feed(Cat... cats)
Правило 3. Кожен такий аргумент змінної довжини у тілі методу є масивом:
void print(String... words){
    for (int i = 0; i < words.length; i++) {
        System.out.println(words[i]);
    }
}
Правило 4. Vararg аргумент має бути останнім у списку аргументів методу:
void print(String... words, String anotherWord) // - Так нельзя!
void print(String... words, int someNumber) // - Так нельзя!

void print(String anotherWord, String... words) // - Так можно
void print(int someNumber, String... words) // - Так можно
Правило 5. Незважаючи на те, що варіації є масивами, при виклику методу, який приймає аргументи змінної довжини, не обов'язково створювати масив. Достатньо і навіть бажано просто перерахувати необхідні аргументи через кому:
public class Main {
    public static void main(String... sss) {
        print("Як","же","прекрасно","изучать","Java");
    }

    static void print(String... words){
        for (int i = 0; i < words.length; i++) {
            System.out.println(words[i]);
        }
    }
}

Приклади varargs

У наведеному нижче прикладі ми напишемо метод, який приймає varargs що складається з цілих чисел і виводить на екран кількість переданих елементів та їх суму. Передамо в цей метод і масив, і ряд цілих чисел (обидва варіанти допустимі):
public static void main(String... sss) {
    int[] a = new int[100];
    for (int i = 0; i < a.length; i++) {
        a[i] = i;
    }

    sum(a);
    sum(1,2,3,4,5,6,7,8,9,10);
}

static void sum(int... numbers){
    final int length = numbers.length;
    final int sum = Arrays.stream(numbers).sum();
    final String lineSeparator = System.lineSeparator();

    System.out.printf("Кол-во элементов для сложения - %d, сумма - %d%s", length, sum, lineSeparator);
}
Після запуску програма виведе:

Кол-во элементов для сложения - 100, сумма - 4950 
Кол-во элементов для сложения - 10, сумма - 55 
Варто сказати, що метод System.out.printfтакож приймає варіації. Якщо ми поглянемо на код цього методу, то переконаємось у цьому:
public PrintStream printf(String format, Object ... args) {
    return format(format, args);
}
Ще один метод, що широко використовується, приймає varags — String.format. Його код наведено нижче:
public static String format(String format, Object... args) {
    return new Formatter().format(format, args).toString();
}

Коли використати varargs?

Відповідь це питання залежить від того, хто запитує. Якщо таке запитання задає клієнт деякого API, у якому є методи з varargs, то відповідь буде “використовувати такі методи якнайчастіше”. Для клієнта коду varargs істотно спрощує життя, полегшуючи написання коду та підвищуючи його читальність. Однак у випадку, якщо це питання задає розробник API, який цікавиться, як часто варто створювати методи з varargs, то відповідь буде “не слід часто використовувати varargs”. Varargs слід використовувати лише тоді, коли вигода від використання очевидна. Також не слід перевантажувати методи з varargs, тому що це викличе у клієнтів вашого коду труднощі у розумінні, який із перевантажених методів насправді викликається.

Висновок

Отже, ми розібрали ще одну тему, varargs в Java. Розібрали, що це таке. Розписали правила використання varargs. Поглянули на приклади методів з аргументами довільної довжини, а також обговорабо, коли варіації краще використовувати, а коли від використання краще утриматися. Як домашнє завдання можна реалізувати такі методи:
  • Написати voidметод, який приймає ряд цілих чисел і повертає їхнє середнє арифметичне.
  • Написати voidметод, який приймає рядок рядків і виводить на друк найдовше слово.
  • Написати метод, який повертає booleanі приймає першим аргументом змінну типу String, а наступним аргументом ряд booleanзмінної довжини.
    Можливі значення String- AND, OR, XOR. Якщо перший аргумент має якесь інше значення, метод повинен залишити виняток IllegalArgumentException.
    Метод повинен здійснити логічну операцію (вказану в першому аргументі) над кожним елементом varargs аргументу і повернути результат обчислення.
Приклад аргументів та результату:
  • "AND", true, true, false - поверне false
  • "OR", false, true, false, false - поверне true
Коментарі
ЩОБ ПОДИВИТИСЯ ВСІ КОМЕНТАРІ АБО ЗАЛИШИТИ КОМЕНТАР,
ПЕРЕЙДІТЬ В ПОВНУ ВЕРСІЮ