На варагс
Конструкция Type...
в объявлении параметров метода обычно называется varargs. В JLS это называется параметром переменная arity .
Последний формальный параметр в списке является специальным; это может быть переменная arity параметр, обозначенный elipsis после типа.
Если последний формальный параметр является параметром переменной arity типа T
, считается, что он определяет формальный параметр типа T[]
. Метод тогда является переменная arity метод. В противном случае это метод fixed arity . Вызовы метода переменной арности могут содержать больше фактических выражений аргументов, чем формальных параметров. Все действительные выражения аргумента, которые не соответствуют формальным параметрам, предшествующим параметру переменной arity, будут оценены, а результаты сохранены в массив, который будет передан в вызов метода.
Чтобы проиллюстрировать в коде, вот что varargs позволяет вам делать:
static void f(int... nums) {
for (int num : nums) {
System.out.println(num);
}
}
//...
f(1,2,3); // prints "1", "2", "3"
Напротив, без конструкции varargs вы должны сделать это:
static void g(int[] nums) {
for (int num : nums) {
System.out.println(num);
}
}
//...
g(new int[] { 1, 2, 3 }); // prints "1", "2", "3"
Varargs - это то, что называется синтаксическим сахаром, который скрывает от вас многословие.
Итак, чтобы вернуться к вашему вопросу, разница между printMax(double... numbers)
и printmax(double numbers[])
заключается в том, что первым является метод variable arity , то есть вы можете присвоить ему переменное количество параметров. Последний - это метод fixed arity , что означает, что он будет принимать один-единственный параметр.
Обратите внимание на приведенную выше цитату о том, что T...
действительно T[]
. То есть даже с varargs вы можете делать следующее:
f(new int[] { 1, 2, 3 }); // prints "1", "2", "3"
Здесь вы вручную создаете массив для хранения параметров vararg. На самом деле, если вы зайдете так далеко, как декомпилируете код, вы обнаружите, что, как указано в JLS, f
фактически принимает параметр int[]
, а f(1, 2, 3)
реализован как f(new int[] { 1, 2, 3 })
.
См. Также
Varargs Gotchas
Как решить varargs довольно сложно, и иногда он делает вещи, которые могут вас удивить.
Рассмотрим этот пример:
static void count(Object... objs) {
System.out.println(objs.length);
}
count(null, null, null); // prints "3"
count(null, null); // prints "2"
count(null); // throws java.lang.NullPointerException!!!
Из-за того, как решаются varargs, последний оператор вызывается с objs = null
, что, конечно, приведет к NullPointerException
с objs.length
. Если вы хотите дать один null
аргумент параметру varargs, вы можете сделать одно из следующих:
count(new Object[] { null }); // prints "1"
count((Object) null); // prints "1"
Похожие вопросы
Ниже приведен пример некоторых вопросов, которые люди задавали при работе с varargs:
Когда использовать varargs
Как показал предыдущий раздел, varargs может быть хитрым. Однако при правильном использовании они могут привести к гораздо более лаконичному коду.
Вот цитата из Effective Java 2nd Edition, Item 42: Используйте varargs разумно (выделено автором):
Урок понятен. Не модифицируйте каждый метод, имеющий окончательный параметр массива; используйте varargs только , когда вызов действительно работает с последовательностью значений переменной длины .
Варарги могут не только сбивать с толку, но и дорого обходиться. Effective Java 2nd Edition фактически рекомендует предоставлять перегрузки фиксированной арности для наиболее распространенных сценариев использования.
Предположим, вы определили, что 95 процентов вызовов метода имеют три или менее параметров. Затем объявите пять перегрузок метода, по одному для каждого с нулем через три обычных параметра, и один varargs для использования, когда число параметров превышает три.
Книга идет гораздо глубже, но по сути вы должны использовать varargs только тогда, когда это действительно имеет смысл.И даже в этих случаях вы все равно можете подумать о предоставлении перегрузок с фиксированной арностью для повышения производительности.
Смежный вопрос
API ссылки
Вот несколько примеров, где varargs имеет смысл:
При объявлении массива
Пожалуйста, не делайтепривычка объявлять массивы следующим образом:
int x[];
Вместо скобок следует ставить тип , а не идентификатор :
int[] x;
Обратите внимание, что это также относится к массивам в приведенных выше обсуждениях, например, T[]
int[]
и т. Д.
Смежные вопросы