Коли ви використовуєте вараги на Java?


192

Я боюся вараг. Я не знаю, для чого їх використовувати.

Плюс до цього, небезпечно дозволяти людям передавати стільки аргументів, скільки їм хочеться.

Що є прикладом контексту, який би був хорошим місцем для їх використання?


3
Я не бачу, чому це було б "небезпечно". Це не небезпечніше, ніж мати метод, який називається велика кількість разів з різними аргументами. У вас є проблеми зі стеком? Тоді не слід, тому що варагги відображаються на масиви, які передаються посиланням.
jfpoilpret

66
Просто хотілося прозвучати: немає нічого поганого у тому, щоб уникнути мовних особливостей, якими ви (поки що) не дуже комфортні. Набагато краще, ніж використання функцій, яких ви не розумієте! ;)
Стівен

2
Це нормально боятися невідомого. Щоб дізнатися більше про читати про varargs тут docs.oracle.com/javase/tutorial/java/javaOO/arguments.html . Ви побачите, що варагам нічого боятися. Вараги корисні. Знання, як використовувати varargs, дає вам можливість писати такі методи, як [PrintStream.format] (" docs.oracle.com/javase/7/docs/api/java/io/… , java.lang.Object ...)" ) :).
розробник Marius Žilėnas

1
Це не критика вараргів, але насправді є деякі причини "боятися" (поки ви точно не зрозумієте обмеження варагрів); саме тому анотація @SafeVarargs існує. stackoverflow.com/a/14252221/1593924
Джон Кумбс

Відповіді:


150

Вараги є корисними для будь-якого методу, якому потрібно мати справу з невизначеною кількістю об'єктів . Один хороший приклад - це String.format. Рядок формату може приймати будь-яку кількість параметрів, тому вам потрібен механізм передачі будь-якої кількості об'єктів.

String.format("This is an integer: %d", myInt);
String.format("This is an integer: %d and a string: %s", myInt, myString);

5
Параметр масиву також може приймати невизначену кількість об'єктів, але параметр varargs забезпечує більшу гнучкість та зручність у точці виклику. Ви можете написати код, щоб створити масив і передати його, або ви можете дозволити Java робити це за вас, коли ви вирішите отримати його в параметрі varargs.
H2ONaCl

79

Хорошим правилом було б:

"Використовувати varargs для будь-якого методу (або конструктора), який потребує масиву T (незалежно від типу T) як вхідного даних".

Це полегшить дзвінки до цих методів (робити це не потрібно new T[]{...}).

Ви можете розширити це правило, включаючи методи з List<T>аргументом, за умови, що цей аргумент призначений лише для введення даних (тобто список не змінюється методом).

Крім того, я б утримався від використання, f(Object... args)оскільки його ковзання у напрямку програмування з незрозумілими API.

З точки зору прикладів, я використовував це в DesignGridLayout , де я можу додати кілька JComponents за один виклик:

layout.row().grid(new JLabel("Label")).add(field1, field2, field3);

У коді вище метод add () визначається як add(JComponent... components).

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

void f(T arg1, T... args) {...}

Я вважаю цей трюк потворним, оскільки реалізація методу буде менш простою, ніж просто T... argsу списку аргументів.

Сподіваємось, що це допоможе з’ясувати пункт про вараги.


1
Чи розглядали ви if (args.length == 0) throw new RuntimeException("foo");замість цього додати перевірку передумов ? (Оскільки абонент порушив договір)
Micha Wiedenmann

24
Ну, мета хорошого API - запобігти зловживанням якомога раніше, тому під час компіляції, коли це можливо, отже, пропозиція для void f(T arg1, T... args)цього завжди гарантує, що вона ніколи не викликається без аргументів, не потрібно чекати часу виконання.
jfpoilpret

Я думаю, що більшість часу дзвінок на функцію лише для варагрів, яка не має аргументів, буде також просто нічого не робити. Справа в тому, що надання аргументів функції varargs, швидше за все, не принесе значної шкоди.
WorldSEnder

Вараги корисні, але вони не еквівалентні використанню масиву. Вараги не піддаються повторенню. Отже, як і дженерики, на них впливає стирання типу, що може бути неприйнятним обмеженням залежно від роботи.
Джуліан

34

Я часто використовую varargs для виведення в журнали для налагодження.

Практично кожен клас у моєму додатку має метод debugPrint ():

private void debugPrint(Object... msg) {
    for (Object item : msg) System.out.print(item);
    System.out.println();
}

Тоді в межах методів класу у мене є такі дзвінки:

debugPrint("for assignment ", hwId, ", student ", studentId, ", question ",
    serialNo, ", the grade is ", grade);

Коли я впевнений, що мій код працює, я коментую його в методі debugPrint (), щоб журнали не містили занадто багато сторонньої та небажаної інформації, але я можу залишити окремі дзвінки на debugPrint () без коментарів. Пізніше, якщо я знайду помилку, я просто відкидаю код debugPrint (), і всі мої дзвінки на debugPrint () повторно активуються.

Звичайно, я міг би так само легко ухилятися від варагів і робити наступні дії:

private void debugPrint(String msg) {
    System.out.println(msg);
}

debugPrint("for assignment " + hwId + ", student " + studentId + ", question "
    + serialNo + ", the grade is " + grade);

Однак у цьому випадку, коли я коментую код debugPrint (), сервер все ще повинен зазнати проблеми з об'єднанням всіх змінних у кожному виклику до debugPrint (), хоча нічого не робиться з отриманим рядком. Якщо я використовую varargs, сервер повинен лише помістити їх у масив до того, як він зрозуміє, що вони їм не потрібні. Зберігається багато часу.


4
Ви можете реалізувати метод налагодження у надкласі для друку будь-якого об’єкта за допомогою відображення.
Lluis Martinez

12

Вараги можна використовувати, коли ми не впевнені в кількості аргументів, які потрібно передавати методом. Він створює масив параметрів невизначеної довжини на задньому плані, і такий параметр може трактуватися як масив під час виконання.

Якщо у нас є метод, який перевантажений для прийняття різної кількості параметрів, то замість того, щоб перевантажувати метод у різні часи, ми можемо просто використовувати концепцію varargs.

Крім того, коли тип параметрів буде змінюватися, використання "Тест об'єкта ..." значно спростить код.

Наприклад:

public int calculate(int...list) {
    int sum = 0;
    for (int item : list) {
        sum += item;
    }
    return sum;
}

Тут опосередковано масив типу (список) int передається як параметр і трактується як масив у коді.

Для кращого розуміння перейдіть за цим посиланням (це мені дуже допомогло зрозуміти цю концепцію): http://www.javadb.com/using-varargs-in-java

PS: Навіть я боявся використовувати вараги, коли не знав цього. Але зараз я звик до цього. Як сказано: "Ми чіпляємось за відоме, боїмося невідомого", тому просто використовуйте його, наскільки можете, і вам теж почнуть подобатися :)


4
C # Еквівалент вараггів - «парами». Він також робить те ж саме і приймає змінну кількість параметрів. Дивіться це для кращого розуміння: dotnetperls.com/params
Сарван

11

Varargs - це функція, додана у версії 1.5 Java.

Навіщо це використовувати?

  1. Що робити, якщо ви не знаєте кількості аргументів для передачі методу?
  2. Що робити, якщо ви хочете передати методу необмежену кількість аргументів?

Як це працює?

Він створює масив із заданими аргументами та передає масив методу.

Приклад:

public class Solution {



    public static void main(String[] args) {
        add(5,7);
        add(5,7,9);
    }

    public static void add(int... s){
        System.out.println(s.length);
        int sum=0;
        for(int num:s)
            sum=sum+num;
        System.out.println("sum is "+sum );
    }

}

Вихід:

2

сума - 12

3

сума - 21


6

У мене теж страх, пов'язаний з вараггами:

Якщо абонент передає методу явний масив (на відміну від декількох параметрів), ви отримаєте спільну посилання на цей масив.

Якщо вам потрібно зберегти цей масив внутрішньо, ви можете спершу його клонувати, щоб уникнути того, що абонент зможе його змінити пізніше.

 Object[] args = new Object[] { 1, 2, 3} ;

 varArgMethod(args);  // not varArgMethod(1,2,3);

 args[2] = "something else";  // this could have unexpected side-effects

Хоча це насправді не відрізняється від передачі будь-якого виду об’єктів, стан якого може змінитися згодом, оскільки масив зазвичай (у випадку виклику з декількома аргументами замість масиву) свіжий, створений компілятором внутрішньо, що ви можете безпечно використання, це, безумовно, несподівана поведінка.


1
Правильно, але цей приклад здається трохи надуманим. Це, ймовірно, люди будуть використовувати ваш API таким чином?
jfpoilpret

2
Ніколи не знаєш ... І особливо, коли кількість аргументів не є жорстко зашифрованою на стороні, що викликає, але також зібрана заявляє в список у циклі, передача в масив - не все так рідко.
Тіло

5
Я думаю, що ваш приклад використання, як правило, малоймовірний. Можна стверджувати, що ваш API не повинен використовувати вхідний масив таким чином, і якщо він є, він повинен його документувати.
Лоуренс Дол

перевантажувати метод для підтримки обох; argMethod (Object .. objList) argMethod (Object [] objList)
thetoolman

2
@thetoolman: Я не думаю, що це можливо. Це буде розглядатися як дублюючий метод.
Тіло

1

Я часто використовую varargs для конструкторів, які можуть приймати якийсь об’єкт фільтра. Наприклад, значна частина нашої системи на базі Hadoop базується на Mapper, який обробляє серіалізацію та десеріалізацію елементів у JSON, і застосовує ряд процесорів, які кожен беруть елемент вмісту і змінюють, і повертають його, або повертають null відхилити.


1

У Java-документі Var-Args цілком зрозуміло використання var args:

http://docs.oracle.com/javase/1.5.0/docs/guide/language/varargs.html

про використання він говорить:

"Отже, коли ви повинні використовувати varargs? Як клієнт, ви повинні користуватися ними, коли API пропонує їх. Важливими напрямами використання основних API є відображення, форматування повідомлень та новий інструмент printf. Як дизайнер API ви повинні використовувати їх щадно, лише тоді, коли користь справді переконлива. Взагалі кажучи, ви не повинні перевантажувати метод varargs, інакше програмістам буде складно зрозуміти, на яку виклик перезавантаження ".

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.