Что означают три точки рядом с типом параметра в Java?
Вопрос о значении трех точек в параметрах метода на языке Java
У меня есть метод, объявленный следующим образом:
public void myMethod(String... strings) {
// тело метода
}
Что означают три точки после типа String
в этом методе? Как они влияют на его использование и какие преимущества они предоставляют?
5 ответ(ов)
Это означает, что в качестве аргументов для этого метода можно передать ноль или более объектов типа String (или один массив этих объектов).
Посмотрите раздел "Произвольное количество аргументов" здесь: http://java.sun.com/docs/books/tutorial/java/javaOO/arguments.html#varargs
В вашем примере вы можете вызвать метод любым из следующих способов:
myMethod(); // Вероятно, бесполезно, но возможно
myMethod("one", "two", "three");
myMethod("solo");
myMethod(new String[]{"a", "b", "c"});
Важно: Аргументы, переданные таким образом, всегда представляют собой массив, даже если передан только один элемент. Убедитесь, что вы обрабатываете их как массив в теле метода.
Важно 2: Аргумент с ...
должен быть последним в сигнатуре метода. Поэтому myMethod(int i, String... strings)
является допустимым, но myMethod(String... strings, int i)
— нет.
Спасибо Vash за разъяснения в его комментарии.
Varargs — это сокращение от variable-length arguments (аргументы переменной длины) и является функцией, которая позволяет методу принимать переменное количество аргументов (от нуля до любого количества). С использованием varargs создание методов, которые принимают переменное количество аргументов, стало значительно проще. Эта функция была добавлена в Java 5.
Синтаксис varargs
Vararg указывается с помощью троеточия (три точки) после типа данных, его общий вид:
return_type method_name(data_type ... variableName){
}
Необходимость varargs
Ранее, до Java 5, если методу необходимы были переменные аргументы, существовали два подхода:
- Если максимальное количество аргументов, которое мог принимать метод, было небольшим и известным, можно было создать перегруженные версии метода.
- Если максимальное количество аргументов было большим или/и неизвестным, аргументы помещались в массив и передавались в метод, который принимал массив в качестве параметра.
Оба подхода были ненадежными — каждый раз приходилось создавать массив параметров, что затрудняло обслуживание. Добавление нового аргумента могло потребовать написания новой перегруженной версии метода.
Преимущества varargs
Varargs предлагает гораздо более простой вариант. Меньше кода, так как нет необходимости писать перегруженные методы.
Пример использования varargs
public class VarargsExample {
public void displayData(String ... values){
System.out.println("Количество переданных аргументов: " + values.length);
for(String s : values){
System.out.println(s + " ");
}
}
public static void main(String[] args) {
VarargsExample vObj = new VarargsExample();
// четыре аргумента
vObj.displayData("var", "args", "are", "passed");
// три аргумента
vObj.displayData("Three", "args", "passed");
// без аргументов
vObj.displayData();
}
}
Вывод:
Количество переданных аргументов: 4
var
args
are
passed
Количество переданных аргументов: 3
Three
args
passed
Количество переданных аргументов: 0
В программе видно, что для подсчета количества переданных аргументов используется метод length, так как varargs автоматически передаются как массив. Все переданные аргументы хранятся в массиве, который ссылается на имя, данное varargs. В данной программе массив называется values. Обратите внимание, что метод вызывается с разным количеством аргументов: первый вызов — с четырьмя аргументами, затем — с тремя и затем — без аргументов. Все эти вызовы обрабатываются одним и тем же методом, который принимает varargs.
Ограничения varargs
Возможно иметь другие параметры с параметром varargs в методе, однако в этом случае параметр varargs должен быть последним в списке аргументов метода.
void displayValues(int a, int b, int ... values) // ОК
void displayValues(int a, int b, int ... values, int c) // ошибка компиляции
Еще одно ограничение — в методе может быть только один параметр varargs.
void displayValues(int a, int b, int ... values, int ... moreValues) // ошибка компиляции
Перегрузка методов с varargs
Метод с параметром varargs можно перегружать. Перегрузка varargs может осуществляться по следующим критериям:
- Разные типы параметров vararg.
- Добавление других параметров.
Пример перегрузки метода с varargs:
public class OverloadingVarargsExp {
// Метод с парметром vararg типа String
public void displayData(String ... values){
System.out.println("Количество переданных аргументов: " + values.length);
for(String s : values){
System.out.println(s + " ");
}
}
// Метод с параметром vararg типа int
public void displayData(int ... values){
System.out.println("Количество переданных аргументов: " + values.length);
for(int i : values){
System.out.println(i + " ");
}
}
// Метод с параметрами vararg типа int и одним параметром типа String
public void displayData(String a, int ... values){
System.out.println("a: " + a);
System.out.println("Количество переданных аргументов: " + values.length);
for(int i : values){
System.out.println(i + " ");
}
}
public static void main(String[] args) {
OverloadingVarargsExp vObj = new OverloadingVarargsExp();
// четыре строковых аргумента
vObj.displayData("var", "args", "are", "passed");
// два целых аргумента
vObj.displayData(10, 20);
// Один строковый параметр и два целых аргумента
vObj.displayData("Test", 20, 30);
}
}
Вывод:
Количество переданных аргументов: 4
var
args
are
passed
Количество переданных аргументов: 2
10
20
a: Test
Количество переданных аргументов: 2
20
30
Неоднозначность вызовов с varargs и перегрузкой
В некоторых случаях вызов может оказаться неоднозначным, когда постепенно перегружены методы с varargs. Например:
public class OverloadingVarargsExp {
// Метод с параметром vararg типа String
public void displayData(String ... values){
System.out.println("Количество переданных аргументов: " + values.length);
for(String s : values){
System.out.println(s + " ");
}
}
// Метод с параметром vararg типа int
public void displayData(int ... values){
System.out.println("Количество переданных аргументов: " + values.length);
for(int i : values){
System.out.println(i + " ");
}
}
public static void main(String[] args) {
OverloadingVarargsExp vObj = new OverloadingVarargsExp();
// четыре строковых аргумента
vObj.displayData("var", "args", "are", "passed");
// два целых аргумента
vObj.displayData(10, 20);
// Этот вызов является неоднозначным
vObj.displayData();
}
}
В этом примере при вызове метода displayData() без параметров возникает ошибка, потому что компилятор не может определить, к какому методу относится данный вызов — к displayData(String ... values)
или displayData(int ... values)
.
Аналогично, если у нас есть перегруженные методы, где один имеет метод vararg
одного типа, а другой метод имеет один параметр и vararg
того же типа, это также приведет к неоднозначности:
displayData(int ... values)
displayData(int a, int ... values)
Эти два перегруженных метода всегда будут иметь неоднозначность.
Вот как в Java передаются varargs (переменное количество аргументов).
Если вы знакомы с C, это похоже на синтаксис ...
, используемый в функции printf
:
int printf(const char * format, ...);
Но в Java это сделано с учетом типов: каждый аргумент должен соответствовать указанному типу (в вашем примере, все они должны быть типа String
).
Вот простой пример того, как можно использовать varargs:
class VarargSample {
public static void PrintMultipleStrings(String... strings) {
for (String s : strings) {
System.out.println(s);
}
}
public static void main(String[] args) {
PrintMultipleStrings("Hello", "world");
}
}
Аргумент ...
на самом деле является массивом, поэтому вы можете передать параметр типа String[]
.
Можно сказать, что это пример синтаксического сахара, поскольку на самом деле это реализовано как массив (что не означает, что это бесполезно). Я предпочитаю передавать массив, чтобы сохранить ясность, а также объявлять методы с массивами заданного типа. Однако это скорее мнение, чем ответ.
Чтобы прояснить ситуацию, важно знать, что параметры переменной длины (var-args) могут использоваться только один раз в методе, и вы не можете иметь несколько параметров var-args. Например, следующий код является некорректным:
public void myMethod(String... strings, int ... ints){
// тело метода
}
Это связано с тем, что Java не позволяет методам принимать более одного параметра, который использует синтаксис var-args. Если вам нужно передать несколько типов данных, вы можете рассмотреть альтернативы, такие как использование массивов или объектов.
Как работают сервлеты? Инстанцирование, сессии, общие переменные и многопоточность
Разница между StringBuilder и StringBuffer
Java 8: Преобразование List<V> в Map<K, V>
Возможные значения конфигурации hbm2ddl.auto в Hibernate и их назначение
Что такое PECS (Producer Extends Consumer Super)?