Boję się varargs. Nie wiem do czego ich używać.
Ponadto niebezpieczne jest pozwalanie ludziom przekazywać tyle argumentów, ile chcą.
Jaki jest przykład kontekstu, który byłby dobrym miejscem do ich użycia?
Boję się varargs. Nie wiem do czego ich używać.
Ponadto niebezpieczne jest pozwalanie ludziom przekazywać tyle argumentów, ile chcą.
Jaki jest przykład kontekstu, który byłby dobrym miejscem do ich użycia?
Odpowiedzi:
Varargs są przydatne w każdej metodzie, która musi poradzić sobie z nieokreśloną liczbą obiektów . Dobrym przykładem jest String.format
. Ciąg formatu może zaakceptować dowolną liczbę parametrów, dlatego potrzebny jest mechanizm do przekazywania dowolnej liczby obiektów.
String.format("This is an integer: %d", myInt);
String.format("This is an integer: %d and a string: %s", myInt, myString);
Dobrą zasadą byłoby:
„Użyj varargs dla dowolnej metody (lub konstruktora), która potrzebuje tablicy T (niezależnie od typu T) jako danych wejściowych”.
Ułatwi to wywołanie tych metod (nie trzeba tego robić new T[]{...}
).
Możesz rozszerzyć tę regułę o metody z List<T>
argumentem, pod warunkiem, że ten argument służy tylko do wprowadzania danych (tj. Lista nie jest modyfikowana przez metodę).
Ponadto powstrzymałbym się od używania, f(Object... args)
ponieważ jego poślizg w kierunku programowania z niejasnymi interfejsami API.
Pod względem przykładów użyłem go w DesignGridLayout , gdzie mogę dodać kilka JComponent
s w jednym wywołaniu:
layout.row().grid(new JLabel("Label")).add(field1, field2, field3);
W powyższym kodzie metoda add () jest zdefiniowana jako add(JComponent... components)
.
Wreszcie, wdrożenie takich metod musi zadbać o to, aby można je było wywołać z pustym vararg! Jeśli chcesz narzucić co najmniej jeden argument, musisz użyć brzydkiej sztuczki, takiej jak:
void f(T arg1, T... args) {...}
Uważam tę sztuczkę za brzydką, ponieważ implementacja metody będzie mniej prosta niż tylko T... args
na liście argumentów.
Ma nadzieję, że pomoże to wyjaśnić punkt dotyczący varargs.
if (args.length == 0) throw new RuntimeException("foo");
zamiast tego rozważałeś dodanie kontroli warunków wstępnych ? (Ponieważ dzwoniący naruszył umowę)
void f(T arg1, T... args)
aby zawsze zapewniać, że nigdy nie zostanie wywołane bez argumentów, bez konieczności czekania do czasu wykonania.
Często używam varargsa do wysyłania danych do dzienników w celu debugowania.
Prawie każda klasa w mojej aplikacji ma metodę debugPrint ():
private void debugPrint(Object... msg) {
for (Object item : msg) System.out.print(item);
System.out.println();
}
Następnie, w ramach metod klasy, mam wywołania takie jak następujące:
debugPrint("for assignment ", hwId, ", student ", studentId, ", question ",
serialNo, ", the grade is ", grade);
Kiedy jestem przekonany, że mój kod działa, komentuję kod w metodzie debugPrint (), aby dzienniki nie zawierały zbyt wielu obcych i niepożądanych informacji, ale mogę pozostawić poszczególne wywołania debugPrint () bez komentarza. Później, jeśli znajdę błąd, odkomentuję kod debugPrint () i wszystkie moje wywołania debugPrint () zostaną ponownie aktywowane.
Oczywiście mógłbym równie łatwo uniknąć varargs i zamiast tego wykonać następujące czynności:
private void debugPrint(String msg) {
System.out.println(msg);
}
debugPrint("for assignment " + hwId + ", student " + studentId + ", question "
+ serialNo + ", the grade is " + grade);
Jednak w tym przypadku, gdy komentuję kod debugPrint (), serwer nadal musi sobie poradzić z konkatenacją wszystkich zmiennych w każdym wywołaniu debugPrint (), nawet jeśli nic nie jest zrobione z wynikowym łańcuchem. Jeśli jednak używam varargs, serwer musi tylko umieścić je w tablicy, zanim zorientuje się, że ich nie potrzebuje. Oszczędność czasu.
Varargs można zastosować, gdy nie jesteśmy pewni co do liczby argumentów przekazywanych w metodzie. Tworzy tablicę parametrów o nieokreślonej długości w tle, a taki parametr można traktować jako tablicę w czasie wykonywania.
Jeśli mamy metodę, która jest przeciążona, aby zaakceptować inną liczbę parametrów, to zamiast przeciążać metodę w różnych momentach, możemy po prostu użyć koncepcji varargs.
Również, gdy typ parametrów będzie się zmieniać, wówczas użycie „Object ... test” znacznie uprości kod.
Na przykład:
public int calculate(int...list) {
int sum = 0;
for (int item : list) {
sum += item;
}
return sum;
}
Tutaj pośrednio tablica typu int (lista) jest przekazywana jako parametr i jest traktowana jako tablica w kodzie.
Dla lepszego zrozumienia skorzystaj z tego linku (bardzo pomogło mi to w zrozumieniu tej koncepcji): http://www.javadb.com/using-varargs-in-java
PS: Nawet bałem się używania varargsa, kiedy go nie znałem. Ale teraz się do tego przyzwyczaiłem. Jak powiedziano: „Trzymamy się tego, co znane, boimy się nieznanego”, więc używaj go jak najwięcej, a ty też polubisz :)
Varargs to funkcja dodana w wersji Java 1.5.
Dlaczego z tego korzystać?
Jak to działa
Tworzy tablicę z podanymi argumentami i przekazuje tablicę do metody.
Przykład:
public class Solution {
public static void main(String[] args) {
add(5,7);
add(5,7,9);
}
public static void add(int... s){
System.out.println(s.length);
int sum=0;
for(int num:s)
sum=sum+num;
System.out.println("sum is "+sum );
}
}
Wynik :
2)
suma wynosi 12
3)
suma wynosi 21
Mam też lęk związany z varargsem:
Jeśli wywołujący przekaże do metody jawną tablicę (w przeciwieństwie do wielu parametrów), otrzymasz wspólne odwołanie do tej tablicy.
Jeśli musisz przechowywać tę tablicę wewnętrznie, możesz ją najpierw sklonować, aby rozmówca nie mógł jej później zmienić.
Object[] args = new Object[] { 1, 2, 3} ;
varArgMethod(args); // not varArgMethod(1,2,3);
args[2] = "something else"; // this could have unexpected side-effects
Chociaż tak naprawdę nie różni się to od przekazywania jakiegokolwiek obiektu, którego stan może się później zmienić, ponieważ tablica jest zwykle (w przypadku wywołania z wieloma argumentami zamiast tablicy) świeżo utworzona przez kompilator wewnętrznie, którą można bezpiecznie użycie, jest to z pewnością nieoczekiwane zachowanie.
Często używam varargs dla konstruktorów, które mogą pobrać jakiś obiekt filtrujący. Na przykład duża część naszego systemu opartego na Hadoop jest oparta na programie Mapper, który obsługuje serializację i deserializację elementów w JSON, i stosuje szereg procesorów, z których każdy pobiera element i modyfikuje go i zwraca, lub zwraca wartość null odrzucić.
W dokumentacji Java Var-Args jest całkiem jasne, że użycie var args:
http://docs.oracle.com/javase/1.5.0/docs/guide/language/varargs.html
o użyciu mówi:
„Więc kiedy powinieneś używać varargs? Jako klient powinieneś z nich korzystać, ilekroć API je oferuje. Ważne zastosowania w podstawowych API obejmują odbicie, formatowanie wiadomości i nową funkcję printf. Jako projektant API powinieneś ich używać oszczędnie, tylko wtedy, gdy korzyść jest naprawdę przekonująca. Mówiąc ogólnie, nie powinieneś przeciążać metody varargs, w przeciwnym razie programiści będą mieli trudności z ustaleniem, które wywołanie przeciążenia zostanie wywołane. ”