Odpowiedzi:
varargs może to zrobić (w pewien sposób). Poza tym należy podać wszystkie zmienne w deklaracji metody. Jeśli chcesz, aby zmienna była opcjonalna, możesz przeładować metodę za pomocą podpisu, który nie wymaga parametru.
private boolean defaultOptionalFlagValue = true;
public void doSomething(boolean optionalFlag) {
...
}
public void doSomething() {
doSomething(defaultOptionalFlagValue);
}
Istnieje kilka sposobów symulacji opcjonalnych parametrów w Javie:
Przeciążenie metody.
void foo(String a, Integer b) {
//...
}
void foo(String a) {
foo(a, 0); // here, 0 is a default value for b
}
foo("a", 2);
foo("a");
Jednym z ograniczeń tego podejścia jest to, że nie działa, jeśli masz dwa opcjonalne parametry tego samego typu, a każdy z nich można pominąć.
Varargs.
a) Wszystkie parametry opcjonalne są tego samego typu:
void foo(String a, Integer... b) {
Integer b1 = b.length > 0 ? b[0] : 0;
Integer b2 = b.length > 1 ? b[1] : 0;
//...
}
foo("a");
foo("a", 1, 2);
b) Rodzaje parametrów opcjonalnych mogą być różne:
void foo(String a, Object... b) {
Integer b1 = 0;
String b2 = "";
if (b.length > 0) {
if (!(b[0] instanceof Integer)) {
throw new IllegalArgumentException("...");
}
b1 = (Integer)b[0];
}
if (b.length > 1) {
if (!(b[1] instanceof String)) {
throw new IllegalArgumentException("...");
}
b2 = (String)b[1];
//...
}
//...
}
foo("a");
foo("a", 1);
foo("a", 1, "b2");
Główną wadą tego podejścia jest to, że jeśli parametry opcjonalne są różnych typów, tracisz sprawdzanie typu statycznego. Ponadto, jeśli każdy parametr ma inne znaczenie, potrzebujesz jakiegoś sposobu na ich rozróżnienie.
Zero Aby rozwiązać ograniczenia poprzednich podejść, możesz zezwolić na wartości zerowe, a następnie przeanalizować każdy parametr w treści metody:
void foo(String a, Integer b, Integer c) {
b = b != null ? b : 0;
c = c != null ? c : 0;
//...
}
foo("a", null, 2);
Teraz należy podać wszystkie wartości argumentów, ale wartości domyślne mogą być zerowe.
Klasa fakultatywna To podejście jest podobne do wartości zerowych, ale wykorzystuje klasę opcjonalną Java 8 dla parametrów o wartości domyślnej:
void foo(String a, Optional<Integer> bOpt) {
Integer b = bOpt.isPresent() ? bOpt.get() : 0;
//...
}
foo("a", Optional.of(2));
foo("a", Optional.<Integer>absent());
Opcjonalne sprawia, że metoda dzwoniąca jest jawna dla osoby dzwoniącej, jednak taki podpis może okazać się zbyt szczegółowy.
Aktualizacja: Java 8 zawiera klasę java.util.Optional
gotową do użycia, więc nie ma potrzeby używania guava z tego konkretnego powodu w Javie 8. Nazwa metody jest jednak nieco inna.
Wzór konstruktora. Wzorzec konstruktora jest używany dla konstruktorów i jest implementowany przez wprowadzenie oddzielnej klasy konstruktora:
class Foo {
private final String a;
private final Integer b;
Foo(String a, Integer b) {
this.a = a;
this.b = b;
}
//...
}
class FooBuilder {
private String a = "";
private Integer b = 0;
FooBuilder setA(String a) {
this.a = a;
return this;
}
FooBuilder setB(Integer b) {
this.b = b;
return this;
}
Foo build() {
return new Foo(a, b);
}
}
Foo foo = new FooBuilder().setA("a").build();
Mapy Gdy liczba parametrów jest zbyt duża i dla większości wartości domyślnych są zwykle używane, możesz przekazać argumenty metody jako mapę ich nazw / wartości:
void foo(Map<String, Object> parameters) {
String a = "";
Integer b = 0;
if (parameters.containsKey("a")) {
if (!(parameters.get("a") instanceof Integer)) {
throw new IllegalArgumentException("...");
}
a = (Integer)parameters.get("a");
}
if (parameters.containsKey("b")) {
//...
}
//...
}
foo(ImmutableMap.<String, Object>of(
"a", "a",
"b", 2,
"d", "value"));
W Javie 9 takie podejście stało się łatwiejsze:
@SuppressWarnings("unchecked")
static <T> T getParm(Map<String, Object> map, String key, T defaultValue)
{
return (map.containsKey(key)) ? (T) map.get(key) : defaultValue;
}
void foo(Map<String, Object> parameters) {
String a = getParm(parameters, "a", "");
int b = getParm(parameters, "b", 0);
// d = ...
}
foo(Map.of("a","a", "b",2, "d","value"));
Pamiętaj, że możesz połączyć dowolne z tych podejść, aby osiągnąć pożądany rezultat.
a
zmienna jest ciągiem (rzutowanie jest poprawne).
Istnieją opcjonalne parametry w Javie 5.0. Po prostu zadeklaruj swoją funkcję w ten sposób:
public void doSomething(boolean... optionalFlag) {
//default to "false"
//boolean flag = (optionalFlag.length >= 1) ? optionalFlag[0] : false;
}
możesz zadzwonić z doSomething();
lub doSomething(true);
teraz.
doSomething() { doSomething(true); }
nie ma tablic do czynienia, nie ma dwuznaczności
Możesz użyć czegoś takiego:
public void addError(String path, String key, Object... params) {
}
params
Zmienna jest opcjonalna. Jest traktowany jako zerowalna tablica obiektów.
O dziwo, nie mogłem nic na ten temat znaleźć w dokumentacji, ale działa!
Jest to „nowe” w Javie 1.5 i nowszych wersjach (nie obsługiwane w Javie 1.4 lub wcześniejszych).
Widzę, że użytkownik bhoot wspomniał o tym również poniżej.
Niestety Java nie obsługuje bezpośrednio parametrów domyślnych.
Jednak napisałem zestaw adnotacji JavaBean, a jeden z nich obsługuje domyślne parametry, takie jak:
protected void process(
Processor processor,
String item,
@Default("Processor.Size.LARGE") Size size,
@Default("red") String color,
@Default("1") int quantity) {
processor.process(item, size, color, quantity);
}
public void report(@Default("Hello") String message) {
System.out.println("Message: " + message);
}
Procesor adnotacji generuje przeciążenia metody, aby odpowiednio to obsługiwać.
Zobacz http://code.google.com/p/javadude/wiki/Annotacje
Pełny przykład na http://code.google.com/p/javadude/wiki/AnnotationsDefaultParametersExample
Wspomniano o VarArgs i przeciążeniu. Inną opcją jest wzorzec konstruktora, który wyglądałby mniej więcej tak:
MyObject my = new MyObjectBuilder().setParam1(value)
.setParam3(otherValue)
.setParam6(thirdValue)
.build();
Chociaż ten wzorzec byłby najbardziej odpowiedni, gdy potrzebujesz opcjonalnych parametrów w konstruktorze.
W JDK> 1.5 możesz używać tego w ten sposób;
public class NewClass1 {
public static void main(String[] args) {
try {
someMethod(18); // Age : 18
someMethod(18, "John Doe"); // Age & Name : 18 & John Doe
} catch (Exception e) {
e.printStackTrace();
}
}
static void someMethod(int age, String... names) {
if (names.length > 0) {
if (names[0] != null) {
System.out.println("Age & Name : " + age + " & " + names[0]);
}
} else {
System.out.println("Age : " + age);
}
}
}
Możesz to zrobić za pomocą metody przeciążania w ten sposób.
public void load(String name){ }
public void load(String name,int age){}
Możesz także użyć adnotacji @Nullable
public void load(@Nullable String name,int age){}
wystarczy przekazać null jako pierwszy parametr.
Jeśli przekazujesz zmienną tego samego typu, możesz jej użyć
public void load(String name...){}
Przeładowanie jest w porządku, ale jeśli istnieje wiele zmiennych, które wymagają wartości domyślnej, otrzymasz:
public void methodA(A arg1) { }
public void methodA( B arg2,) { }
public void methodA(C arg3) { }
public void methodA(A arg1, B arg2) { }
public void methodA(A arg1, C arg3) { }
public void methodA( B arg2, C arg3) { }
public void methodA(A arg1, B arg2, C arg3) { }
Sugerowałbym więc użycie argumentu zmiennych dostarczanego przez Javę. Oto link do wyjaśnienia.
Możesz użyć klasy, która działa podobnie jak konstruktor, aby zawierać opcjonalne wartości w ten sposób.
public class Options {
private String someString = "default value";
private int someInt= 0;
public Options setSomeString(String someString) {
this.someString = someString;
return this;
}
public Options setSomeInt(int someInt) {
this.someInt = someInt;
return this;
}
}
public static void foo(Consumer<Options> consumer) {
Options options = new Options();
consumer.accept(options);
System.out.println("someString = " + options.someString + ", someInt = " + options.someInt);
}
Użyj jak
foo(o -> o.setSomeString("something").setSomeInt(5));
Dane wyjściowe to
someString = something, someInt = 5
Aby pominąć wszystkie opcjonalne wartości, które trzeba by tak nazwać foo(o -> {});
lub, jeśli wolisz, możesz utworzyć drugą foo()
metodę, która nie przyjmuje parametrów opcjonalnych.
Korzystając z tego podejścia, możesz określić opcjonalne wartości w dowolnej kolejności bez żadnych dwuznaczności. Możesz także mieć parametry różnych klas w przeciwieństwie do varargs. Takie podejście byłoby jeszcze lepsze, gdyby można użyć adnotacji i generowania kodu do utworzenia klasy Options.
Java obsługuje teraz opcjonalne wersje 1.8, utknąłem w programowaniu na Androidzie, więc używam zer, dopóki nie będę mógł przefakturować kodu, aby użyć opcjonalnych typów.
Object canBeNull() {
if (blah) {
return new Object();
} else {
return null;
}
}
Object optionalObject = canBeNull();
if (optionalObject != null) {
// new object returned
} else {
// no new object returned
}
Domyślnych argumentów nie można używać w Javie. Gdzie w C #, C ++ i Python, możemy ich użyć ..
W Javie musimy użyć 2 metod (funkcji) zamiast jednej z domyślnymi parametrami.
Przykład:
Stash(int size);
Stash(int size, int initQuantity);
Jest to stare pytanie, być może jeszcze przed wprowadzeniem rzeczywistego typu Opcjonalnego, ale obecnie można rozważyć kilka rzeczy: - użycie przeciążenia metody - użycie Typu opcjonalnego, który ma tę zaletę, że pozwala uniknąć przepuszczania wartości NULL w okolicy Opcjonalny typ został wprowadzony w Javie 8 przed jego użyciem z lib stron trzecich, takich jak Google Guava. Używanie opcjonalnych jako parametrów / argumentów można uznać za nadmierne wykorzystanie, ponieważ głównym celem było wykorzystanie go jako czasu powrotu.
Ref: https://itcodehub.blogspot.com/2019/06/using-optional-type-in-java.html
Możemy ustawić opcjonalny parametr przez przeciążenie metody lub użycie DataType ...
| * | Przeciążenie metody:
RetDataType NameFnc(int NamePsgVar)
{
// |* Code Todo *|
return RetVar;
}
RetDataType NameFnc(String NamePsgVar)
{
// |* Code Todo *|
return RetVar;
}
RetDataType NameFnc(int NamePsgVar1, String NamePsgVar2)
{
// |* Code Todo *|
return RetVar;
}
Najłatwiej jest
| * | Typ danych ... może być parametrem opcjonalnym
RetDataType NameFnc(int NamePsgVar, String... stringOpnPsgVar)
{
if(stringOpnPsgVar.length == 0) stringOpnPsgVar = DefaultValue;
// |* Code Todo *|
return RetVar;
}
RetDtaTyp
... poważnie? Czy RetDataType
zbyt trudno jest napisać?
Jeśli planujesz użyć interfejsu z wieloma parametrami , możesz użyć następującego wzoru strukturalnego i zastosować lub zastąpić - metodę opartą na twoich wymaganiach .
public abstract class Invoker<T> {
public T apply() {
return apply(null);
}
public abstract T apply(Object... params);
}
Jeśli jest to punkt końcowy interfejsu API, eleganckim sposobem jest użycie adnotacji „Spring”:
@GetMapping("/api/foos")
@ResponseBody
public String getFoos(@RequestParam(required = false, defaultValue = "hello") String id) {
return innerFunc(id);
}
Zauważ, że w tym przypadku innerFunc będzie wymagało zmiennej, a ponieważ nie jest to punkt końcowy interfejsu API, nie można użyć tej adnotacji z wiosny, aby uczynić ją opcjonalną. Odniesienie: https://www.baeldung.com/spring-request-param