Metody o zmiennej liczbie argumentów (varargs)
Od piątej wersji Javy, mamy do dyspozycji mechanizm pozwalający na tworzenie metod o zmiennej ilości argumentów, tzw. varargs, bez konieczności wykorzystywania tablic przechowujących te argumenty.
Schematycznie wygląda to tak:
[typ] metoda(typ ArgumentStały, typ...GrupaArgumentow)
Początek nagłówka i ArgumentStały, to rzecz nie wymagająca tłumaczeń, gdyż jest to najzwyklejszy nagłówek metody, oraz zwykły argument. Ciekawe rzeczy zaczynają się na drugim miejscu. Po typie argumentu znajduje się wielokropek i nazwa "grupy argumentów". Istotnym jest, aby ta "grupa" znajdowała się na miejscu ostatnim.
Przy wywoływaniu takiej metody, argumenty te podajemy po przecinku. Istotne jest, że aby móc na nich operować wewnątrz metody, zachowujemy się jakbyśmy w argumencie otrzymali tablicę.
To wszystko może się wydawać troszkę zawiłe, dlatego teraz jest dobry moment, aby poprzeć powyższą teorię przykładem.
Przykład 1
Napiszemy sobie metodę, która jako argumenty przyjmie dowolną ilość liczb całkowitych i zwróci ich sumę. Stworzymy sobie jeden argument stały i jedną "grupę argumentów". W ten sposób zostawimy sobie pewną furtkę, dzięki której, za pomocą naszej metody, będziemy mogli dodać zarówno dwie) liczby, jak i dużo więcej.
public int suma(int arg0, int...args) {
int wynik = arg0;
for(int i=0; i<args.length; i++) {
wynik += args[i];
}
return wynik;
}
Oraz przykładowe wywołania naszej metody :
System.out.print(wypisz(3) + " ");
System.out.print(wypisz(3,3) + " ");
System.out.print(wypisz(3,3,3) + " ");
System.out.print(wypisz(3,3,3,3,3,3) + " ");
Które zwrócą wyniki :
3 6 9 18
Przykład 2
Druga przykładowa metoda będzie po prostu wypisywać przekazane jej argumenty, zaznaczając czy dany argument jest stały, czy zmienny.
public void wypisz(int arg0, int...args) {
System.out.println("1 argument stały: " + arg0);
for(int i=0; i<args.length; i++) {
System.out.println(i+1 + " argument zmienny: " + args[i]);
}
}
Wywołanie jej, to na przykład :
wypisz(3,5,7,9,11)
Co skutkuje komunikatem:
1 argument stały: 3
1 argument zmienny: 5
2 argument zmienny: 7
3 argument zmienny: 9
4 argument zmienny: 11
Dyskusja i komentarze
Masz pytania do tego wpisu? Może chcesz się podzielić spostrzeżeniami? Zapraszamy dyskusji na naszej grupie na Facebooku.
Poniżej znajdziesz archiwalne wpisy z czasów, gdy strona była jeszcze hobbystycznym blogiem.
Rafał
W przykładzie 1 jest błąd. Tworzona jest metoda o nazwie "suma" public int suma(int arg0, int...args) { a poniżej wywoływana metoda o nazwie "wypisz" a powinna być również "suma" System.out.print(wypisz(3) + " ");
GZII13
byłem tu z rok temu widzię że wiele sie zmieniło, rozbudowany serwis, a kurs.. jeszcze chyba lepszego nie widziałem. pogratulować
Daniel
Dlaczego w obu przypadkach eclipse kazał mi zmienić metodę na static?
Nism0
<blockquote> <a href="#comment-11659" rel="nofollow"> <strong><em>Daniel:</em></strong> </a> Dlaczego w obu przypadkach eclipse kazał mi zmienić metodę na static? </blockquote> To dlatego, że nie można sięgać z jednej metody która jest statyczna (w tym przypadku sięgasz z metody main, która musi być statyczna ) do innej niestatycznej, bez utworzenia obiektu na rzecz którego można by wywołać tą metodę. Gdybyś sobie stworzył osobną klasę , i w niej umieścił niestatyczną metodę, a następnie utworzył sobie w metodzie statycznej main (w innej klasie ofc) obiekt danej klasy, to mógłbyś wówczas wywołać niestatyczną metodę na rzecz obiektu. Reasumując : niestatyczne metody, można wywołać jedynie na rzecz obiektu danej klasy. Jeśli chcemy korzystać z metody danej klasy, bez utworzenia dla niej obiektu, musi ona (metoda) być statyczna.
Pawel
Nie do końca rozumiem dlaczego w drugim przykładzie musiałem wskazać return na arg0, żeby zadziałało tak jak zostało to pokazane w przykładzi. Jest ktoś w stanie mi to wyjaśnić?
Mateusz
w drugim przykładzie funkcja wypisz jest typu void, więc nie powinna wymagać zwrócenia żadnego wyniku. Prawdopodobnie przerabiając pierwszy przykład zostawiłeś funkcję typu int, która do poprawnego zakończenia wymaga zwrócenia jakiegoś inta. Dlatego dopiero jak napiszesz return arg0 to Ci działa. Zmień typ funkcji na void i będzie działało bez return arg0.
W
Dlaczego nie mogę wywołać metod ani z 1 ani z 2 przykładu? Multiple markers at this line - Syntax error on token ";", @ expected - Syntax error, insert "}" to complete ClassBody - Syntax error on token ")", delete this token - Syntax error on token "wypisz", AnnotationName expected - Return type for the method is missing - Syntax error on token(s), misplaced construct(s) - Syntax error, insert ")" to complete MethodDeclaration - Syntax error, insert ";" to complete MethodDeclaration
lolo
Co do pierwszego przykładu jeśli skopiowałeś/aś przykładowe wywołanie to jest tam błąd nie wypisz tylko suma powinna być. Jeśli to nie pomoże to napisz temat na forum i tam wklej cały swój kod.
qwert
sorry, ale czy ta lekcja byla robiona na kolanie? wydaje sie niedokonczona i niewyjasniona.
mpat
Jako że te przykłady nie działały jak należy ja rozwiązałem je w inny sposób. Stworzyłem osobną klasę Suma.java i tam są te metody (z dwóch przykładów): public class Suma { int wynik; public int suma(int arg0, int...args){ int wynik = arg0; for(int i=0; i<args.length; i++){ wynik += args[i]; } return wynik; } public void wypisz(int arg0, int...args) { System.out.println("1 argument stały: " + arg0); for(int i=0; i<args.length; i++) { System.out.println(i+1 + " argument zmienny: " + args[i]); } } } A następnie w pliku Main.java wywołałem oba przyklady: public class Main { public static void main(String[] args){ Suma suma = new Suma(); System.out.println(suma.suma(3,4,5)); suma.wypisz(1,2,3); } } Może teraz osoby, którym te przykłady nie działają będą miały możliwość przeanalizowania ich na spokojnie :)
Adam
Twój przykład mi nie działał, są małe błędy, w public int suma() { wypisanie return powinno być w środku } a nie za klamrami Popranie działający przykład class Suma { int wynik; public int oblicz(int arg0, int...args){ wynik = arg0; for(int i=0; i<args.length; i++) wynik += args[i]; return wynik; } } class Suma1 { public void wypisz(int arg0, int...args) { System.out.println("1 argument stały: " + arg0); for(int i=0; i<args.length; i++) { System.out.println(i+1 + " argument zmienny: " + args[i]); } } } public class Args { public static void main(String[] args) { Suma suma = new Suma(); System.out.println(suma.oblicz(1,2,3,4)); System.out.println(suma.oblicz(5,6)); System.out.println(suma.oblicz(5,6,7)); System.out.println(suma.oblicz(5,6,7,8)); System.out.println("----------------------"); Suma1 suma1 = new Suma1(); suma1.wypisz(1,2,3,4,6); } }
Tomek
Czy zamiast "args" w "int...args" mogę wpisać cokolwiek, np "int...grupaArgumentow" albo "int...argumenty"?
Sławek Ludwiczak
oczywiście, nazwa parametru jest dowolna. W ogólności zmienną liczbę argumentów argumentów (varargs) należy rozumieć tak jak byśmy przekazywali jako parametr tablicę - tylko, że zamiast tablicy możemy wymienić argumenty po przecinku.
k2marko
Czy ilość argumentów stałych jest ograniczona do jednego, czy może być ich kilka?
Sławek Ludwiczak
argumentów stałych może być dowolna liczba, natomiast parametr zmienny może być tylko jeden i zawsze musi być on ostatnim z parametrów, czyli możesz zadeklarować metody: void metoda(int p1, int... zmienna){ ... } void metoda2(int p1, double p2, int... zmienna){ ... } ale błędne będzie np: void metoda3(int... zmienna, double p1){ ... } Postaram się rozbudować tę lekcję, bo mocno upraszcza ona ciekawe zagadnienie.
~eL
Świetna sprawa. Pisałem sporo w C# ale nigdy jakoś nie miałem okazji spotkać się z tym mechanizmem. Dzięki!
~eL
Warto też zauważyć że skoro pozostałe elementy są traktowane jako tablica, to możemy spokojnie działać na nich foreach'e, for (int element : args) { suma += element; }
Stig
System.out.print(wypisz(3) + " "); System.out.print(wypisz(3,3) + " "); System.out.print(wypisz(3,3,3) + " "); System.out.print(wypisz(3,3,3,3,3,3) + " "); Tutaj zamiast "wypisz" chyba powinno być "suma".