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

Natknąłem się na jakiś kod Javy, 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 tego typu składnię? Czy są jakieś powody, dla których ta dwuetapowa składnia jest preferowana?

Author: peterh, 2009-06-15

19 answers

Nie, znaleziona struktura jest taka, jak obsługuje ją Java (tj. z przeciążeniem zamiast domyślnych parametrów).

Dla konstruktorów, Zobacz skuteczne Java: Przewodnik po języku programowania punkt 1 wskazówka (rozważ statyczne metody fabryczne zamiast konstruktorów), jeśli przeciążenie staje się skomplikowane. W przypadku innych metod może pomóc zmiana nazwy niektórych przypadków lub użycie obiektu parametru. To jest, gdy masz wystarczająco dużo złożoności, że różnicowanie jest trudne. Konkretnym przypadkiem jest gdzie trzeba odróżnić za pomocą kolejności parametrów, a nie tylko liczby i typu.

 773
Author: Kathy Van Stone,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2013-09-13 17:12:48

Nie, ale możesz użyć Builder Pattern , jak opisano w Ta odpowiedź przepełnienia stosu .

Jak opisano w linked answer, wzorzec Builder pozwala na pisanie kodu w stylu

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

, w którym niektóre pola mogą mieć wartości domyślne lub w inny sposób być opcjonalne.

 551
Author: Eli Courtwright,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-05-23 12:34:53

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

  1. Metoda przeciążenia.

    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 i każdy z nich można pominąć.

  2. Varargs.

    A) wszystkie opcjonalne parametry 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) typy 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łówny wadą tego podejścia jest to, że jeśli opcjonalne parametry są różnych typów, tracisz sprawdzanie typu statycznego. Ponadto, jeśli każdy parametr ma inne znaczenie, musisz w jakiś sposób je rozróżnić.

  3. Nulls. aby rozwiązać ograniczenia poprzednich podejść, możesz zezwolić na wartości null, a następnie przeanalizować każdy parametr w ciele metody:

    void foo(String a, Integer b, Integer c) {
        b = b != null ? b : 0;
        c = c != null ? c : 0;
        //...
    }
    
    foo("a", null, 2);
    

    Teraz muszą być podane wszystkie wartości argumentów, ale domyślne mogą być null.

  4. Klasa opcjonalna. to podejście jest podobne do NULL, ale używa opcjonalnej klasy Java 8 dla parametrów, które mają wartość domyślną:

    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 umowa metody jest jednoznaczna dla rozmówcy, jednak może się okazać, że taki podpis jest zbyt gadatliwy.

  5. Wzór budowniczego. wzorzec builder jest używany dla konstruktorów i jest zaimplementowany poprzez wprowadzenie oddzielnej klasy Builder:

     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żna 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")); 
    

Należy pamiętać, że można połączyć dowolne z tych podejść, aby osiągnąć pożądany wynik.

 365
Author: Vitalii Fedorenko,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2018-06-14 23:10:44

Niestety nie.

 198
Author: Rob H,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2009-06-15 18:05:16

Niestety tak.

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

Można zapisać 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ś zależeć od tego, co myślisz o kompilatorze generującym

new Boolean[]{}

Dla każdego połączenia.

Dla wielu domyślnych parametrów:

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

Można zapisać 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;
}

To pasuje do składni C++, która dopuszcza tylko domyślne parametry na końcu listy parametrów.

Poza składnią, Istnieje różnica, gdzie to ma przebieg Typ czasowy sprawdza przekazane parametry domyślne i typ C++ sprawdza je podczas kompilacji.

 76
Author: ebelisle,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2013-10-03 21:37:48

Nie, ale bardzo łatwo można je naśladować. Co w C++ było:

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

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

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 potrafi 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 uważa, że nie używa Javy ze względu na jej prostotę.

 35
Author: peterh,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-10-18 03:39:53

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

Tzn.

class Foo(var prime: Boolean = false, val rib: String)  {}
 19
Author: lythic,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2012-04-03 13:58:02

Być może stwierdzam oczywistość, ale dlaczego po prostu nie zaimplementować parametru "default" samemu?

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

Dla domyślnego użycia ether

Func ("my string");

A jeśli nie chcesz użyć domyślnego, użyj

Func ("my string", false);

 11
Author: IronWolf,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2013-02-18 14:05:09

Nie. Ogólnie Rzecz Biorąc, Java nie ma zbyt wiele cukru składniowego, ponieważ starali się stworzyć prosty język.

 6
Author: tomjen,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2009-06-15 18:49:17

Nie.

Można osiągnąć to samo zachowanie, przekazując obiekt, który ma inteligentne wartości domyślne. Ale znowu zależy, jaka jest twoja sprawa.

 6
Author: Santosh Gokak,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2013-09-13 17:13:45

NIE , ale najprostszym sposobem implementacji 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ójdzielnego można użyć, Jeśli:

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

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

public myParameterizedFunction(String param1, int param2) {

    this(param1, param2, false);
}
 6
Author: simhumileco,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2018-08-29 13:51:29

Jak wspomniano o Scali, Kotlin jest również wart wspomnieć. W kotlinie parametry funkcji 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.

 4
Author: mrts,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-11-26 19:51:08

Nie jest obsługiwana, ale istnieje kilka opcji, takich jak użycie parametru obiekt pattern z pewnym cukrem składni:

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 tej próbce konstruujemy ParameterObject z wartościami domyślnymi i nadpisujemy je w sekcji inicjalizacji instancji klasy { param1 = 10; param2 = "bar";}

 3
Author: hoaz,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2012-12-13 17:15:14

Spróbuj tego rozwiązania:

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

    return score;
}
 3
Author: Hamzeh Soboh,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2014-09-03 16:45:05

Istnieje pół tuzina lub lepszych problemów, takich jak ten, w końcu dojdziesz do statycznego wzorca fabrycznego ... zobacz crypto api dla tego. Sortuj trudne do wyjaśnienia, ale pomyśl o tym w ten sposób: Jeśli masz konstruktor, domyślny lub inny, jedynym sposobem propagacji stanu poza nawiasami klamrowymi jest albo posiadanie Boolean isValid; ( wraz z null jako wartością domyślną V failed constructor ) lub wyrzucenie wyjątku, który nigdy nie jest pouczający podczas uzyskiwania go z pola użytkowników.

Kod poprawny niech mnie szlag, piszę tysiące konstruktorów liniowych i robię to, czego potrzebuję. Znajduję użycie isValid przy budowie obiektów - innymi słowy, dwóch konstruktorów liniowych-ale z jakiegoś powodu migruję do statycznego wzorca fabrycznego. Po prostu wydaje mi się, że możesz zrobić wiele, jeśli w wywołaniu metody, nadal są problemy z sync (), ale domyślne mogą być "podstawione" lepiej (bezpieczniej)

Myślę, że to, co musimy tutaj zrobić, to rozwiązać problem null jako wartości domyślnej vis-a-vis something String one=new String (""); jako zmienna składowa, następnie sprawdzanie null przed przypisaniem łańcucha przekazanego do konstruktora.

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

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

 1
Author: Nicholas Jordan,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2009-09-28 02:33:40

Tak to zrobiłem ... nie jest to tak wygodne, jak posiadanie 'opcjonalnego argumentu' 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 albo tylko łańcuchem znaków, albo mogę wywołać ją łańcuchem znaków i wartością logiczną. W takim przypadku ustawienie wipeClean na true zastąpi cały tekst w mojej TextArea dostarczonym ciągiem znaków. Ustawienie wipeClean na false lub pozostawienie go razem po prostu dodaje podany tekst do TextArea.

Zauważ również, że nie powtarzam kodu w dwóch metodach, po prostu dodaję funkcjonalność możliwości resetowania TextArea poprzez utworzenie nowej metody o tej samej nazwie tylko z dodanym logicznym.

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

 1
Author: Michael Sims,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2015-01-18 15:40:19

Podobne podejście do https://stackoverflow.com/a/13864910/2323964 to, co działa w Javie 8, to użycie interfejsu z domyślnymi getterami. Będzie to bardziej wyraziste białe znaki, ale można je wyśmiewać i jest to świetne rozwiązanie, gdy masz kilka instancji, w których 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; }
        });
    }
}
 1
Author: Novaterata,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-05-23 11:47:32

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 wartości domyślne. Konstruktor zostanie wygenerowany podczas kompilacji, używając domyślnych wartości podanych 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;
 }
}

I wtedy możesz wywołać metody.

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

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

CarService instance = new CarService();
String carsByFilter = CarServiceGetCarsByFilterBuilder.getCarsByFilter()//
  .withColor(Color.YELLOW)//
  .invoke(instance);
 0
Author: Tomas Bjerre,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2016-06-13 17:42:50

Nie, ale mamy alternatywę w postaci przeciążenia funkcji.

Wywołane, gdy żaden parametr nie został przekazany

void operation(){

int a = 0;
int b = 0;

} 

Wywołane po przekazaniu parametru " a "

void operation(int a){

int b = 0;
//code

} 

Wywołane po przejściu parametru b

void operation(int a , int b){
//code
} 
 0
Author: Umair Khalid,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2016-09-01 06:51:15