Szkolenia programowania we Wrocławiu
Kurs Java Podstawy - rozszerzony

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

<- Poprzednia LekcjaNastępna Lekcja ->

Komentarze

Komentarze zamknięte. Zapraszamy do grupy na Facebooku
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



Daniel:

Dlaczego w obu przypadkach eclipse kazał mi zmienić metodę na static?



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".