Frage Unterstützt Java Standardparameterwerte?


Ich stieß auf Java-Code, der folgende Struktur hatte:

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

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

Ich weiß, dass ich in C ++ einem Parameter einen Standardwert zuweisen kann. Beispielsweise:

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

Unterstützt Java diese Syntax? Gibt es Gründe, warum diese zweistufige Syntax vorzuziehen ist?


1311
2018-06-15 18:04


Ursprung


Antworten:


Nein, die Struktur, die Sie gefunden haben, ist die Art und Weise, wie Java sie behandelt (dh mit Überladung anstelle von Standardparametern).

Für Konstrukteure, Siehe Effektives Java: Programmiersprachenhandbuch Punkt 1 Tipp (Betrachten Sie statische Factory-Methoden anstelle von Konstruktoren), wenn die Überlastung kompliziert wird. Bei anderen Methoden kann das Umbenennen einiger Fälle oder die Verwendung eines Parameterobjekts hilfreich sein. Dies ist, wenn Sie genug Komplexität haben, die Differenzierung schwierig ist. Ein bestimmter Fall ist, wo Sie unterscheiden müssen mit der Reihenfolge der Parameter, nicht nur Anzahl und Typ.


757
2018-06-15 18:14



Nein, aber Sie können das verwenden Erbauer-Musterwie beschrieben in diese Stapelüberlaufantwort.

Wie in der verknüpften Antwort beschrieben, können Sie mit dem Builder-Muster Code ähnlich schreiben

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

in denen einige Felder Standardwerte haben können oder anderweitig optional sind.


541
2018-06-15 19:20



Es gibt verschiedene Möglichkeiten, Standardparameter in Java zu simulieren:

  1. Überladen der Methode

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

    Eine der Einschränkungen dieses Ansatzes ist, dass es nicht funktioniert, wenn Sie zwei optionale Parameter des gleichen Typs haben und einige davon weggelassen werden können.

  2. Varargs.

    a) Alle optionalen Parameter sind vom selben Typ:

    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) Arten von optionalen Parametern können unterschiedlich sein:

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

    Der Hauptnachteil dieses Ansatzes besteht darin, dass Sie, wenn optionale Parameter unterschiedliche Typen haben, die statische Typprüfung verlieren. Wenn jeder Parameter eine andere Bedeutung hat, brauchen Sie eine andere Möglichkeit, sie zu unterscheiden.

  3. Nullen. Um die Einschränkungen der vorherigen Ansätze zu beheben, können Sie Nullwerte zulassen und anschließend jeden Parameter in einem Methodenkörper analysieren:

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

    Nun müssen alle Argumente Werte zur Verfügung gestellt werden, aber die Standardwerte können Null sein.

  4. Optionale Klasse Dieser Ansatz ähnelt Nullen, verwendet jedoch die Option Java 8 Optional für Parameter mit einem Standardwert:

    void foo(String a, Optional<Integer> bOpt) {
        Integer b = bOpt.isPresent() ? bOpt.get() : 0;
        //...
    }
    
    foo("a", Optional.of(2));
    foo("a", Optional.<Integer>absent());
    

    Optional macht einen Methodenvertrag für einen Aufrufer explizit, jedoch kann eine solche Signatur zu ausführlich sein.

  5. Erbauermuster. Das Builder-Muster wird für Konstruktoren verwendet und wird durch Einführung einer separaten Builder-Klasse implementiert:

     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. Karten. Wenn die Anzahl der Parameter zu groß ist und für die meisten Standardwerte verwendet werden, können Sie Methodenargumente als eine Karte ihrer Namen / Werte übergeben:

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

Bitte beachten Sie, dass Sie alle diese Ansätze kombinieren können, um ein wünschenswertes Ergebnis zu erzielen.


348
2017-11-01 02:03



Traurigerweise Nein.


197
2018-06-15 18:05



Leider ja.

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

könnte in Java 1.5 geschrieben werden als:

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

Aber ob Sie davon abhängen sollten, wie Sie sich über den Compiler fühlen, der ein

new Boolean[]{}

für jeden Anruf.

Für mehrere defaultable Parameter:

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

könnte in Java 1.5 geschrieben werden als:

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;
}

Dies entspricht der C ++ - Syntax, die nur die Standardparameter am Ende der Parameterliste zulässt.

Jenseits der Syntax gibt es einen Unterschied, wenn diese eine Laufzeittypprüfung für übergebene defaultable Parameter hat und C ++ - Typ diese während der Kompilierung überprüft.


76
2018-05-26 21:51



Nein, aber Sie können sie sehr leicht nachahmen. Was in C ++ war:

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

In Java wird es eine überladene Funktion sein:

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);
}

Zuvor wurde erwähnt, dass Default-Parameter zu mehrdeutigen Fällen beim Überladen von Funktionen geführt haben. Das ist einfach nicht wahr, wir können im Fall von C ++ sehen: Ja, vielleicht kann es mehrdeutige Fälle erzeugen, aber dieses Problem kann leicht behandelt werden. Es wurde einfach nicht in Java entwickelt, wahrscheinlich weil die Ersteller eine viel einfachere Sprache wollten, wie C ++ - wenn sie recht hatten, ist das eine andere Frage. Aber die meisten von uns glauben nicht, dass er Java wegen seiner Einfachheit verwendet.


35
2017-11-04 09:12



Sie können dies in Scala tun, das auf der JVM läuft und mit Java-Programmen kompatibel ist. http://www.scala-lang.org/

d.h.

class Foo(var prime: Boolean = false, val rib: String)  {}

19
2017-07-21 16:26