Czy Java obsługuje domyślne wartości parametrów?

1661

Natknąłem się na kod Java, który miał następującą strukturę:

public MyParameterizedFunction(String param1, int param2)
{
    this(param1, param2, false);
}

public MyParameterizedFunction(String param1, int param2, boolean param3)
{
    //use all three parameters here
}

Wiem, że w C ++ mogę przypisać parametrowi wartość domyślną. Na przykład:

void MyParameterizedFunction(String param1, int param2, bool param3=false);

Czy Java obsługuje taką składnię? Czy są jakieś powody, dla których ta dwustopniowa składnia jest lepsza?

gnavi
źródło
85
Nie. Jednak wzorzec Konstruktora może pomóc.
Dave Jarvis
50
Naprawdę tęsknię za tą funkcją. Bardzo pomaga to w modyfikowaniu istniejącego kodu w celu przeniesienia dodatkowego parametru do funkcji lub konstruktora
Jatin
4
@Jatin Dzięki refaktoryzacji „Zmień sygnaturę metody” Eclipse możesz dodać parametr i podać wartość domyślną, której będą używać istniejący wywołujący.
Erwin Bolwidt,
2
@ErwinBolwidt Dzięki. Korzystam z Android Studio, a także ma opcję refaktoryzacji metody i podania wartości domyślnych. Całkiem użyteczne.
Jatin
3
@nazwa_użytkownika public MyParameterizedFunction(String param1, int param2)to konstruktor, a nie metoda, deklaracja.
Mario Ishac

Odpowiedzi:

955

Nie, struktura, którą znalazłeś, to sposób, w jaki Java ją obsługuje (to znaczy z przeciążeniem zamiast parametrów domyślnych).

W przypadku konstruktorów zobacz Poradnik dla efektywnego języka Java: Podręcznik programowania w języku 1 (rozważ konstruktor statycznych metod fabrycznych zamiast konstruktorów), jeśli przeciążenie staje się skomplikowane. W przypadku innych metod pomocne może być zmiana nazwy niektórych przypadków lub użycie obiektu parametru. To wtedy masz wystarczająco złożoność, że odróżnienie jest trudne. Zdecydowanym przypadkiem jest rozróżnienie przy użyciu kolejności parametrów, a nie tylko liczby i typu.

Kathy Van Stone
źródło
135
@JarrodRoberson: Statyczne metody fabryczne nie są bardziej szkodliwe niż new. Są one cały czas używane w nowym kodzie. Konstruktory prostych obiektów o wartości są często wynikiem nadmiernej inżynierii.
Lii
12
@JarrodRoberson: Ciekawy sposób na wymuszenie poprawnego korzystania z kompilatora, dziękuję za udostępnienie! Przyjazna sugestia dla przyszłych postów: 300 wierszy nieskomentowanego kodu źródłowego jest prawdopodobnie nieco do strawienia dla większości ludzi (w końcu kod jest trudniejszy do odczytania niż do napisania). Dzięki jeszcze raz!
Christian Aichinger
17
@JarrodRoberson: Fajnie, nie mogę się doczekać! Co chciałem przekazać: jako czytelnik twojego bloga 50-liniowy przykład z krótkim tekstowym opisem tego, co się dzieje, pomógłby mi ponad 300 linii bez kontekstu.
Christian Aichinger
8
@ user177800 Nie zgadzam się - metody statyczne, jeśli napisane jako czyste funkcje są w porządku. To wtedy, gdy funkcja statyczna mutuje stan, staje się problemem ...
Levi Fuller,
641

Nie, ale możesz użyć Wzorca konstruktora , jak opisano w odpowiedzi na Przepełnienie stosu .

Jak opisano w połączonej odpowiedzi, wzorzec konstruktora umożliwia pisanie kodu podobnego

Student s1 = new StudentBuilder().name("Eli").buildStudent();
Student s2 = new StudentBuilder()
                 .name("Spicoli")
                 .age(16)
                 .motto("Aloha, Mr Hand")
                 .buildStudent();

w których niektóre pola mogą mieć wartości domyślne lub być opcjonalne.

Eli Courtwright
źródło
141
Wreszcie świetny przykład mniej niż 2-stronicowego wzorca Konstruktora.
nevvermind
14
Jestem jednak ciekawy, dlaczego potrzebujemy klasy konstruktora podczas korzystania z wzorca konstruktora. Myślałem o Student s1 = new Student (). Name („Spicolo”). Age (16) .motto („Aloha, Mr Hand);
ivanceras
52
@ivanceras: Ma to znaczenie, gdy klasy mają wymagane pola i nie chcesz mieć możliwości tworzenia instancji tych klas w nieprawidłowym stanie. Więc jeśli tylko powiedziałeś, Student s1 = new Student().age(16);to sprawiłoby, że miałbyś Ucznia bez imienia, co może być złe. Jeśli nie jest źle, to twoje rozwiązanie jest w porządku.
Eli Courtwright
57
@ivanceras: innym powodem jest to, że możesz chcieć, aby twoja klasa była niezmienna po zbudowaniu, więc nie chciałbyś w niej metod, które zmieniają jej wartości.
Jules
3
@ivanceras: Używałem Builderów do 3 rzeczy - eliminując wiele argumentów i płynną inicjalizację, niezmienność i co najważniejsze, uważam, że sprawdzam poprawność obiektu domeny w metodzie build (). Dlaczego warto utworzyć instancję obiektu, jeśli jest niepoprawna. metody fabryczne, jak w powyższym przypadku buildFreshman (), buildSenior () itp.
Abhijeet Kushe
485

Istnieje kilka sposobów symulacji domyślnych parametrów w Javie:

  1. 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ąć.

  2. 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 sposobu na ich rozróżnienie.

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

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

  5. 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();
  6. Mapy Gdy liczba parametrów jest zbyt duża i dla większości z nich zwykle używane są wartości domyślne, 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 = (String)parameters.get("a");
        } else if (parameters.containsKey("b")) { 
            //... 
        }
        //...
    }
    
    foo(ImmutableMap.<String, Object>of(
        "a", "a",
        "b", 2, 
        "d", "value")); 

Pamiętaj, że możesz połączyć dowolne z tych podejść, aby osiągnąć pożądany rezultat.

Vitalii Fedorenko
źródło
1
Dobre wytłumaczenie. Nigdy nie widziałem, aby zwracano takie wartości. Po 5) co return thiszrobić? Ponadto, FooBuilder().setA("a").build();ponieważ skoro (z definicji) konstruktor jest wywoływany jako pierwszy i FooBuilder()zwraca wartość, czy to nie oznacza, .setA("a"):że nie ma szansy na wywołanie?
Celeritas
3
@Celeritas return thiszwraca ten sam obiekt, na którym wywołano metodę (w przykładzie FooBuilder). Umożliwia to łączenie metod w jednej instrukcji działającej na ten sam obiekt: new FooBuilder().setA(..).setB(..).setC(..)itp. W przeciwieństwie do wywoływania każdej metody w osobnej instrukcji.
ADTC
2
@Celeritas new FooBuilder()zwraca FooBuilderobiekt, do którego setAwywoływana jest metoda. Jak setBsię nie nazywa, this.bzachowuje wartość domyślną. Wreszcie buildmetoda jest wywoływana na tym FooBuilderobiekcie. buildMetoda tworzy i zwraca Fooobiekt, który jest ustawiony do zmiennej Foo foo. Zauważ, że FooBuilderobiekt nie jest przechowywany w żadnej zmiennej.
ADTC
Adnotacji można także używać do tworzenia domyślnych parametrów i jest ona najbardziej przydatna, gdy jest wymagana w przypadku kolekcji polimorficznych. docs.oracle.com/javase/tutorial/java/annotations/declaring.html
Martin Spamer
1
Ponad 900 głosujących za tą samą odpowiedzią na dwa pytania. Jestem pod wrażeniem: stackoverflow.com/questions/965690/java-optional-parameters/…
AdamMc331
256

Niestety nie.

Rob H.
źródło
34
Czy to takie smutne? Takie postępowanie wprowadziłoby potencjalnie niejednoznaczne sygnatury funkcji.
Trey
69
@Trey: języki z domyślnymi parametrami często przeciążają funkcję rowu, ponieważ jest to mniej przekonujące. Więc nie ma dwuznaczności. Poza tym Scala dodała tę funkcję w 2.8 i jakoś rozwiązała problem niejednoznaczności (ponieważ utrzymywali przeciążenie ze względu na kompatybilność).
PhiLho
32
Nie widzę, jak wartości domyślne parametrów zapobiegają przeciążeniu funkcji. Na przykład C # pozwala na przesłonięcia, a także pozwala na domyślne inicjowanie. Wydaje się, że wybór jest arbitralny, a nie ograniczenie jest powodem.
FlavorScape
51
Tak, odłóżmy na bok, aby kompilator wykonał dodatkową pracę i zamiast tego zmusił nas do napisania 100000 przeciążeń, aby zapewnić użytkownikom biblioteki wygodę. Dobry pomysł.
28
@ user562566: Ilekroć pracuję nad projektem Java, mam wrażenie, że deweloperzy Java są opłacani / mierzeni przez liczbę wierszy kodu, które produkują dziennie
Mark K Cowan,
83

Niestety tak.

void MyParameterizedFunction(String param1, int param2, bool param3=false) {}

można napisać w Javie 1.5 jako:

void MyParameterizedFunction(String param1, int param2, Boolean... params) {
    assert params.length <= 1;
    bool param3 = params.length > 0 ? params[0].booleanValue() : false;
}

Ale czy powinieneś polegać na tym, jak się czujesz na temat generowania kompilatora

new Boolean[]{}

dla każdego połączenia.

W przypadku wielu parametrów domyślnych:

void MyParameterizedFunction(String param1, int param2, bool param3=false, int param4=42) {}

można napisać w Javie 1.5 jako:

void MyParameterizedFunction(String param1, int param2, Object... p) {
    int l = p.length;
    assert l <= 2;
    assert l < 1 || Boolean.class.isInstance(p[0]);
    assert l < 2 || Integer.class.isInstance(p[1]);
    bool param3 = l > 0 && p[0] != null ? ((Boolean)p[0]).booleanValue() : false;
    int param4 = l > 1 && p[1] != null ? ((Integer)p[1]).intValue() : 42;
}

Jest to zgodne ze składnią C ++, która dopuszcza parametry domyślne tylko na końcu listy parametrów.

Poza składnią istnieje różnica w tym, że ma to sprawdzanie typu w czasie wykonywania pod kątem parametrów domyślnych, a typ C ++ sprawdza je podczas kompilacji.

ebelisle
źródło
14
Sprytne, ale varargs (...) można wykorzystać tylko dla parametru końcowego, który jest bardziej ograniczający niż języki, które obsługują parametry domyślne.
CurtainDog
6
to sprytne, ale nieco niechlujne w porównaniu do wersji C ++
Someone Somewhere
5
Java zdecydowanie potrzebuje opcjonalnych parametrów domyślnych, ponieważ C #, a inne pozwalają ... składnia jest oczywista i przypuszczam, że mogą to zaimplementować dość prosto, nawet po prostu kompilując wszystkie możliwe kombinacje ... Nie wyobrażam sobie, dlaczego nie dodali tego do języka jeszcze!
jwl
10
Nigdy nie należy używać assertkodu produkcyjnego. Rzuć wyjątek.
Michael Dorst
5
-1 Tak naprawdę nie do tego służy varargs. To jest hack. - w tym przypadku użycie przeciążeń będzie znacznie bardziej czytelne (co jest niefortunne, ponieważ trzy dodatkowe znaki są bardziej czytelne niż 5 dodatkowych wierszy źródła ...). - ale Java nie obsługuje parametrów domyślnych.
BrainSlugs83
38

Nie, ale możesz bardzo łatwo je emulować. Co w C ++ było:

public: void myFunction(int a, int b=5, string c="test") { ... }

W Javie będzie to funkcja przeciążona:

public void myFunction(int a, int b, string c) { ... }

public void myFunction(int a, int b) {
    myFunction(a, b, "test");
}

public void myFunction(int a) {
    myFunction(a, 5);
}

Wcześniej wspomniano, że domyślne parametry powodowały niejednoznaczne przypadki przeciążenia funkcji. To po prostu nieprawda, widzimy w przypadku C ++: tak, może może tworzyć niejednoznaczne przypadki, ale problem ten można łatwo rozwiązać. Po prostu nie został opracowany w Javie, prawdopodobnie dlatego, że twórcy chcieli znacznie prostszego języka, jakim był C ++ - jeśli mieli rację, to kolejne pytanie. Ale większość z nas nie uważa, że ​​używa Javy ze względu na jej prostotę.

peterh - Przywróć Monikę
źródło
8
Główną ideą notowania wartości domyślnej w C # jest właśnie unikanie tego kodowania na schemacie i posiadanie jednego konstruktora zamiast wielu.
Kolya Ivankov
1
@KolyaIvankov Nie znam C #, ale znam C ++, gdzie rozumowanie jest takie samo. Nie wiem, co jest lepsze, ale myślę, że ten sam kod generatora jest generowany przez kompilator w przypadku C ++ / C # i przechodzi do ostatecznego pliku binarnego.
peterh - Przywróć Monikę
5
Każdy język programowania jest (w szczególności) sposobem na uniknięcie płyty głównej Asemblera, czy się mylę? Pytanie tylko, czy daje to przydatną funkcjonalność, czy nie.
Kolya Ivankov
2
Pierwsze zdanie jest pytaniem retorycznym. Słowo „pytanie” w drugim zdaniu nie ma nic wspólnego z pytaniem retorycznym w pierwszym zdaniu.
Kolya Ivankov
1
Mówiąc dokładniej: języki to narzędzia, które pozwalają nam pisać programy w sposób, który pozwala nam kontrolować to, co jest napisane, kompilacja jest sposobem na powiedzenie maszynie, czego od niej chcemy. Narzędzie jest bardziej przydatne, jeśli pozwala nam uniknąć płyty kotłowej. W efekcie gnavi zapytał, czy mogą uniknąć dokładnie tego rodzaju kodu, który zaproponujesz jako odpowiedź, ponieważ C # pozwala na to.
Kolya Ivankov
24

Możesz to zrobić w Scali, która działa na JVM i jest kompatybilna z programami Java. http://www.scala-lang.org/

to znaczy

class Foo(var prime: Boolean = false, val rib: String)  {}
mityczny
źródło
58
Przynieść zupełnie nowy język, aby uzyskać jeden nie tak powszechny?
om-nom-nom
8
@ om-nom-nom: Java nigdy nie powinna istnieć. Powiedzenie, że funkcja nie jest używana, jest równoznaczne z tym, że nikt jej nie potrzebuje. Mówienie, że Java nie była popularna przed jej wynalezieniem, oznacza, że ​​Gosling nie powinien zacząć jej projektować.
Val
28
@ Val mówi tylko, że to jak strzelanie do ptaków z armat
om-nom-nom
8
nie ma to nic wspólnego z pytaniem PO
destan
Działa również w Kotlinie. I Groovy. I C#. I JavaScript. I prawie wszystkie inne języki stworzone dla prawdziwych ludzi i problemów.
spyro
17

Nie , ale najprostszym sposobem na wdrożenie tego jest:

public myParameterizedFunction(String param1, int param2, Boolean param3) {

    param3 = param3 == null ? false : param3;
}

public myParameterizedFunction(String param1, int param2) {

    this(param1, param2, false);
}

lub zamiast operatora trójskładnikowego możesz użyć if:

public myParameterizedFunction(String param1, int param2, Boolean param3) {

    if (param3 == null) {
        param3 = false;
    }
}

public myParameterizedFunction(String param1, int param2) {

    this(param1, param2, false);
}
simhumileco
źródło
2
Tak, to podejście wydaje się najlepsze z innych alternatyw. Przyjemnie byłoby, gdyby Java przyjęła wartości domyślne; Kotlin pokazał, że można to zrobić, więc nie jestem pewien, dlaczego Oracle nie wkracza w erę współczesną i wciąż projektuje java, jakby to było w latach 90. : D
shevy
13

Być może stwierdzam tu oczywistość, ale dlaczego po prostu nie wdrożyć parametru „domyślnego”?

public class Foo() {
        public void func(String s){
                func(s, true);
        }
        public void func(String s, boolean b){
                //your code here
        }
}

domyślnie użyłbyś albo

func("my string");

a jeśli nie chcesz używać domyślnej, skorzystasz

func("my string", false);
IronWolf
źródło
11
Plakat zapytał, czy tego (raczej brzydkiego) wzoru można uniknąć ... ;-) W bardziej nowoczesnych językach (takich jak c #, Scala) nie potrzebujesz dodatkowych przeciążeń, które tworzą tylko więcej linii kodu. Do tego czasu możesz używać varargs w międzyczasie (static int max (int ... array) {}), ale są to tylko bardzo brzydkie obejście.
Offler
2
Przeładowanie nie jest brzydkie i ma wiele zalet, takich jak różne wywołania metod z różnymi podpisami mogą pełnić różne funkcje. //This is better public class Foo() { /* This does something */ public void func(String s){ //do something } /* This does something else with b */ public void func(String s, boolean b){ // b was passed } } //Than this public class Foo() { /* This does something unless b = value, then it does something else */ public void func(String s, boolean b = value){ If (b){ // Do Something } else{ // Do something else } } }
Antony Booth
Cóż, jeśli ktoś chce inne zachowanie. Jeśli jedyną różnicą jest niewielka zmiana w obliczeniach itp., To z pewnością marnowanie wysiłku na tworzenie wielu podpisów. Wartości domyślne mają sens tam, gdzie ich potrzebujesz ... a ich brak nie powinien być klasyfikowany jako wymóg „bezużyteczny”.
Kapil
Domyślne parametry @Offler nie mają nic wspólnego z „nowoczesnym językiem”. Użyłem ich w Delphi 20 lat temu i prawdopodobnie już istniały w Turbo Pascal.
Niesamowity
Zgadzam się z Offlerem i nie zgadzam się z Antony Booth. Uważam, że jest to nie tylko brzydkie, ale także dość nieefektywne. Języki takie jak ruby ​​lub python sprawiają, że używanie parametrów domyślnych jest trywialne; Myślę, że Java wymaga od ciebie znalezienia (i użycia) obejścia. Wyraźne sprawdzanie w porównaniu do wartości null wydaje się być najmniej brzydkim wyborem, ponieważ mogę to również wywołać z wiersza poleceń (po prostu nie dostarczaj niczego, a następnie obsługuj rozsądny wariant); podejście przeciążające operatora wydaje się ... bardzo szczegółowe (jak co najmniej +3 wiersze, w porównaniu do zerowania i więcej wierszy, jeśli kod jest bardziej złożony).
shevy
8

Jak wspomniano Scalę, Kotlin również jest wart wspomnienia. W funkcji Kotlin parametry mogą mieć również wartości domyślne, a nawet mogą odnosić się do innych parametrów:

fun read(b: Array<Byte>, off: Int = 0, len: Int = b.size) {
    ...
}

Podobnie jak Scala, Kotlin działa na JVM i może być łatwo zintegrowany z istniejącymi projektami Java.

mrts
źródło
6

Nie.

Możesz osiągnąć to samo zachowanie, przekazując obiekt, który ma inteligentne ustawienia domyślne. Ale znowu to zależy od tego, co masz pod ręką.

Santosh Gokak
źródło
5

Nie. Ogólnie Java nie ma dużo (żadnego) cukru syntaktycznego, ponieważ próbowali stworzyć prosty język.

tomjen
źródło
26
Nie do końca. Gorzka prawda jest taka, że ​​zespół miał napięty harmonogram i nie miał czasu na syntaktyczny cukier. Po co jeszcze consti gotobyłyby zastrzeżone słowa kluczowe, których nie ma w implementacji? - Szczególnie constgorzko tęsknię - finalnie ma zastępstwa i wiedzieli o tym. - A jeśli podjąłeś świadomą decyzję, aby nigdy nie wdrożyć goto, nie musisz rezerwować słowa kluczowego. - A później w zespole Java oszukiwał, czyniąc oparty na Label breaki continuetak potężny jak Pascal goto.
Martin
„Prosty, obiektowy i znajomy” był rzeczywiście celem projektowym - patrz oracle.com/technetwork/java/intro-141325.html
mikera
1
tomjen powiedział: „Nie. Ogólnie Java nie ma dużo (żadnego) cukru syntaktycznego, ponieważ próbowali stworzyć prosty język”. Mówisz więc, że usunięcie wielu niepotrzebnych funkcji z C ++ sprawia, że ​​Java jest prostym językiem, a następnie powiedz mi, dlaczego Java ma różne metody? Dlaczego ma varargs? Nie jest potrzebne, jeśli zamiast tego możesz po prostu użyć tablicy obiektów, mam rację? Tak więc varargs można usunąć z języka, ponieważ nie jest to konieczne. To sprawi, że Java będzie prostsza niż jest teraz. Czy mam rację? Przeciążenie można również usunąć, ponieważ masz nieskończone nazwy dla każdej metody.
1
i dlatego mamy wiosnę i inne rzeczy, które przyjmują prosty język i zamieniają każdy prawdziwy projekt Java w kibicowanie składni i
poprawek
Zmuszanie programistów do tworzenia kodu i skomplikowanych obejść nie jest dla mnie zrozumieniem słowa „łatwe”. myFunction (a, b = false, c = 3), to nazywam easy.
spyro
5

Zamiast używać:

void parameterizedMethod(String param1, int param2) {
    this(param1, param2, false);
}

void parameterizedMethod(String param1, int param2, boolean param3) {
    //use all three parameters here
}

Możesz skorzystać z opcjonalnej funkcjonalności java, mając jedną metodę:

void parameterizedMethod(String param1, int param2, @Nullable Boolean param3) {
    param3 = Optional.ofNullable(param3).orElse(false);
    //use all three parameters here
}

Główną różnicą jest to, że musisz używać klas opakowań zamiast pierwotnych typów Java, aby umożliwić nullwprowadzanie danych. Booleanzamiast boolean, Integerzamiast inti tak dalej.

Viktor Taranenko
źródło
4

To nie jest obsługiwane, ale istnieje kilka opcji, takich jak użycie wzorca obiektu parametru z odrobiną cukru składniowego:

public class Foo() {
    private static class ParameterObject {
        int param1 = 1;
        String param2 = "";
    }

    public static void main(String[] args) {
        new Foo().myMethod(new ParameterObject() {{ param1 = 10; param2 = "bar";}});
    }

    private void myMethod(ParameterObject po) {
    }
}

W tym przykładzie konstruujemy ParameterObjectwartości domyślne i zastępujemy je w sekcji inicjalizacji instancji klasy{ param1 = 10; param2 = "bar";}

hoaz
źródło
3

Wypróbuj to rozwiązanie:

public int getScore(int score, Integer... bonus)
{
    if(bonus.length > 0)
    {
        return score + bonus[0];
    }

    return score;
}
Hamzeh Soboh
źródło
3

Możesz użyć Java Method Invocation Builder, aby automatycznie wygenerować builder z wartościami domyślnymi.

Po prostu dodaj @GenerateMethodInvocationBuilder do klasy lub interfejsu, a @Default do parametrów w metodach, w których chcesz mieć wartości domyślne. Konstruktor zostanie wygenerowany w czasie kompilacji przy użyciu wartości domyślnych określonych w adnotacjach.

@GenerateMethodInvocationBuilder
public class CarService {
 public CarService() {
 }

 public String getCarsByFilter(//
   @Default("Color.BLUE") Color color, //
   @Default("new ProductionYear(2001)") ProductionYear productionYear,//
   @Default("Tomas") String owner//
 ) {
  return "Filtering... " + color + productionYear + owner;
 }
}

Następnie możesz wywołać metody.

CarService instance = new CarService();
String carsByFilter = CarServiceGetCarsByFilterBuilder.getCarsByFilter()//
  .invoke(instance);

Lub ustaw dowolną z wartości domyślnych na coś innego.

CarService instance = new CarService();
String carsByFilter = CarServiceGetCarsByFilterBuilder.getCarsByFilter()//
  .withColor(Color.YELLOW)//
  .invoke(instance);
Tomas Bjerre
źródło
2

Podobne podejście do https://stackoverflow.com/a/13864910/2323964, które działa w Javie 8, polega na użyciu interfejsu z domyślnymi modułami pobierającymi. Będzie to bardziej szczegółowe białe znaki, ale można z niego wyśmiewać i jest to świetne, gdy masz kilka przypadków, w których naprawdę chcesz zwrócić uwagę na parametry.

public class Foo() {
    public interface Parameters {
        String getRequired();
        default int getOptionalInt(){ return 23; }
        default String getOptionalString(){ return "Skidoo"; }
    }

    public Foo(Parameters parameters){
        //...
    }

    public static void baz() {
        final Foo foo = new Foo(new Person() {
            @Override public String getRequired(){ return "blahblahblah"; }
            @Override public int getOptionalInt(){ return 43; }
        });
    }
}
Novaterata
źródło
2

Spędziłem teraz trochę czasu, aby dowiedzieć się, jak tego używać z metodami, które zwracają wartości, i jak dotąd nie widziałem żadnych przykładów, pomyślałem, że przydatne może być dodanie tego tutaj:

int foo(int a) {
    // do something with a
    return a;
}

int foo() {
    return foo(0); // here, 0 is a default value for a
}
AAGD
źródło
1

Tak to zrobiłem ... być może nie jest to tak wygodne jak „opcjonalny argument” przeciwko zdefiniowanemu parametrowi, ale wykonuje zadanie:

public void postUserMessage(String s,boolean wipeClean)
{
    if(wipeClean)
    {
        userInformation.setText(s + "\n");
    }
    else
    {
        postUserMessage(s);
    }
}

public void postUserMessage(String s)
{
    userInformation.appendText(s + "\n");
}

Zauważ, że mogę wywołać tę samą nazwę metody za pomocą tylko łańcucha lub mogę wywołać ją za pomocą łańcucha i wartości logicznej. W takim przypadku ustawienie wipeClean na true spowoduje zastąpienie całego tekstu w moim obiekcie TextArea podanym ciągiem. Ustawienie wipeClean na false lub pomijanie go razem powoduje dołączenie dostarczonego tekstu do TextArea.

Zauważ też, że nie powtarzam kodu w dwóch metodach, po prostu dodaję funkcję resetowania TextArea, tworząc nową metodę o tej samej nazwie tylko z dodaną wartością logiczną.

Myślę, że jest to trochę czystsze niż gdyby Java podała „opcjonalny argument” dla naszych parametrów, ponieważ musielibyśmy wtedy kodować wartości domyślne itp. W tym przykładzie nie muszę się tym martwić. Tak, dodałem jeszcze jedną metodę do mojej klasy, ale na dłuższą metę łatwiej jest ją czytać, moim skromnym zdaniem.

Michael Sims
źródło
1

NIE, Ale mamy alternatywę w postaci przeciążenia funkcji.

wywoływany, gdy nie przekazano żadnego parametru

void operation(){

int a = 0;
int b = 0;

} 

wywoływane, gdy parametr „a” został przekazany

void operation(int a){

int b = 0;
//code

} 

wywoływane, gdy parametr b minie

void operation(int a , int b){
//code
} 
Umair Khalid
źródło
1

Istnieje pół tuzina lub lepszych problemów, takich jak ten, w końcu dochodzisz do statycznego wzorca fabrycznego ... zobacz o tym API kryptograficzne. Sortuj trudne do wyjaśnienia, ale pomyśl o tym w ten sposób: Jeśli masz konstruktor, domyślny lub inny, jedynym sposobem propagowania stanu poza nawiasy klamrowe jest albo użycie logicznej wartości isValid; (wraz z wartością null jako wartością domyślną v nieudany konstruktor) lub zgłasza wyjątek, który nigdy nie jest pouczający, gdy odzyskuje go od użytkowników pola.

Kod Poprawnie, do diabła, piszę tysiące konstruktorów linii i robię to, czego potrzebuję. Używam isValid przy budowie obiektów - innymi słowy, konstruktory dwuwierszowe - ale z jakiegoś powodu migruję do statycznego wzorca fabrycznego. Wydaje mi się, że możesz wiele zdziałać, jeśli używasz metody, nadal występują problemy z synchronizacją (), ale wartości domyślne można lepiej zastąpić (bezpieczniej)

Myślę, że musimy tutaj zająć się kwestią zerową jako wartością domyślną względem czegoś String one = new String (""); jako zmienną składową, a następnie sprawdzanie wartości null przed przypisaniem ciągu przekazywanego do konstruktora.

Niezwykła ilość surowej, stratosferycznej informatyki wykonanej w Javie.

C ++ i tak dalej ma biblioteki dostawców, tak. Java może wyprzedzić je na dużych serwerach ze względu na ogromny zestaw narzędzi. Studiuj statyczne bloki inicjalizujące, zostań z nami.

Nicholas Jordan
źródło
1

Nie jest obsługiwany w Javie jak w innym języku np. Kotlin.

Virendra Pal Singh
źródło
0

Możesz użyć następujących-

public void mop(Integer x) {
  // Define default values
        x = x == null ? 200 : x;
}
Sobhit Sharma
źródło