Menu

Varargs w Javie: metody przyjmujące dowolną liczbę argumentów

Jak varargs (...) w Javie pozwalają metodzie przyjąć dowolną liczbę argumentów, jak stają się tablicą, zasada jednego varargs na końcu oraz pułapki pustego wywołania i niejednoznaczności.

Na tej stronie są działające edytory: edytuj, uruchamiaj i od razu zobacz wynik.

Jedna metoda, dowolna liczba argumentów

Czasem nie wiesz z góry, ilu argumentów potrzebuje metoda. Raz chcesz max(3, 9), a za chwilę max(1, 7, 4, 2, 8). Bez varargs musiałbyś pisać przeciążenie dla każdej liczby argumentów albo zmuszać wywołującego do budowania tablicy. Varargs (skrót od variable arguments, czyli zmienna liczba argumentów) pozwalają jednej metodzie przyjąć zero, jedną albo wiele wartości tego samego typu.

Deklarujesz je, stawiając trzy kropki (...) po typie parametru:

Wywołujący przekazuje luźne wartości, a wewnątrz metody numbers to prawdziwa tablica. Na tym polega cały pomysł: kompilator pakuje argumenty w tablicę za ciebie.

Varargs to po prostu tablica

W czasie działania nie ma tu żadnej magii. Parametr zadeklarowany jako int... numbers jest wewnątrz metody dokładnie tablicą int[]. Możesz sprawdzić jej length, sięgać do elementów po indeksie i przechodzić ją pętlą jak każdą inną tablicę.

Skoro to naprawdę tablica, metodzie z varargs możesz też przekazać tablicę, którą już masz. Przyjmuje obie formy:

Zasady: na końcu i tylko jeden

Dwie zasady sprawiają, że varargs są jednoznaczne, a kompilator pilnuje obu:

  1. Parametr varargs musi być ostatni. Najpierw zwykłe parametry, potem parametr ... zgarnia wszystko, co zostało.
  2. Metoda może mieć najwyżej jeden parametr varargs. Przy dwóch nie dałoby się ustalić, gdzie kończy się jeden, a zaczyna drugi.

To się kompiluje. Ale postawienie varargs na początku, static void log(Object... values, String level), to błąd kompilacji: varargs parameter must be the last. Wymagany parametr level zawsze stoi przed ....

Gdzie już używasz varargs

Metody z varargs wywołujesz od samego początku. System.out.printf i String.format to klasyczne przykłady: ich drugi parametr to Object... args:

List.of(...), Arrays.asList(...) i wiele API w stylu buildera to również varargs. Dlatego możesz przekazać im dowolną liczbę elementów, bez samodzielnego opakowywania czegokolwiek w tablicę.

Varargs a przeciążanie

Varargs i przeciążanie współdziałają w jeden zaskakujący sposób. Gdy do wywołania pasuje i zwykłe przeciążenie, i przeciążenie z varargs, Java wybiera bardziej konkretne: wygrywa metoda o stałej liczbie parametrów:

pick(1, 2) pasuje do obu, ale Java wybiera przeciążenie bez varargs, bo pasuje lepiej. Metoda z varargs uruchamia się tylko wtedy, gdy nie pasuje żadne przeciążenie o stałej liczbie parametrów. Zwykle o to właśnie chodzi, ale oznacza to, że dodanie przeciążenia z varargs może po cichu zmienić, która metoda zostanie wywołana.

Uważaj na puste wywołania i null

Dwie pułapki często zaskakują. Po pierwsze, wywołanie metody z varargs bez argumentów przekazuje jej pustą tablicę, a nie null, więc numbers.length wynosi 0, a pętla nic nie robi. Dla przypadku bez argumentów nie potrzebujesz sprawdzania null:

Po drugie, przekazanie dosłownego null jest niejednoznaczne i niebezpieczne: Java może zinterpretować count(null) jako "cała tablica varargs jest null", a nie "jeden element null", co potem rzuca NullPointerException, gdy odczytujesz jej length. Jeśli naprawdę chodzi ci o jeden element null, zapisz to wprost: count((Object) null).

Dalej: klasy

Varargs dopełniają to, co możesz zrobić z parametrami metod: elastyczne listy argumentów obok przeciążania. Do tej pory metody żyły luźno w klasie ze static. Dalej zobaczysz, jak naprawdę działają klasy: łączenie danych (pól) i zachowania (metod) we własne typy, co jest sercem programowania obiektowego w Javie.

Najczęściej zadawane pytania

Czym są varargs w Javie?

Varargs (zmienna liczba argumentów) pozwalają metodzie przyjąć dowolną liczbę argumentów tego samego typu. Deklarujesz je, stawiając ... po typie: int sum(int... numbers). Wywołujący może przekazać zero, jedną albo wiele wartości, a wewnątrz metody numbers to zwykła tablica. To lukier składniowy: Java sama zbiera luźne argumenty w tablicę.

Czy metoda w Javie może mieć więcej niż jeden parametr varargs?

Nie. Metoda może mieć najwyżej jeden parametr varargs i musi on być ostatni na liście parametrów, np. void log(String level, Object... values). Gdyby nie był ostatni, Java nie wiedziałaby, gdzie kończy się część o zmiennej długości, a zaczyna kolejny parametr. Zwykłe parametry zawsze stoją przed parametrem ....

Czym różnią się varargs od parametru tablicowego w Javie?

W czasie działania to prawie to samo: parametr varargs int... jest wewnątrz metody tablicą int[]. Różnica jest w miejscu wywołania: przy varargs piszesz sum(1, 2, 3) (luźne wartości), a przy jawnym parametrze tablicowym musisz zbudować i przekazać tablicę, sum(new int[]{1, 2, 3}). Metoda z varargs przyjmuje też tablicę bezpośrednio, więc jest bardziej elastycznym wyborem.

Ilustracja języków programowania w Coddy

Ucz się programowania z Coddy

ZACZNIJ