Unterstützt Java Standardparameterwerte?

1661

Ich bin auf Java-Code gestoßen, 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. Zum Beispiel:

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

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

Gnavi
quelle
85
Nein. Das Builder-Muster kann jedoch hilfreich sein.
Dave Jarvis
50
Ich vermisse diese Funktion wirklich. Es ist sehr hilfreich, wenn vorhandener Code geändert wird, um zusätzliche Parameter für eine Funktion oder einen Konstruktor zu übernehmen
Jatin
4
@Jatin Mit dem Eclipse-Refactoring "Methodensignatur ändern" können Sie einen Parameter hinzufügen und einen Standardwert angeben, den vorhandene Aufrufer verwenden.
Erwin Bolwidt
2
@ErwinBolwidt Danke. Ich verwende Android Studio und es hat auch die Möglichkeit, die Methode umzugestalten und Standardwerte bereitzustellen. Ziemlich nützlich.
Jatin
3
@temporary_user_name public MyParameterizedFunction(String param1, int param2)ist eine Konstruktor- und keine Methodendeklaration.
Mario Ishac

Antworten:

955

Nein, die Struktur, die Sie gefunden haben, ist die, wie Java damit umgeht (dh mit Überladung anstelle von Standardparametern).

Informationen zu Konstruktoren finden Sie unter Tipp 1 zu Effective Java: Programmiersprachenhandbuch (Betrachten Sie statische Factory-Methoden anstelle von Konstruktoren), wenn die Überladung kompliziert wird. Bei anderen Methoden kann es hilfreich sein, einige Fälle umzubenennen oder ein Parameterobjekt zu verwenden. Dies ist der Fall, wenn Sie so komplex sind, dass eine Unterscheidung schwierig ist. In einem bestimmten Fall müssen Sie anhand der Reihenfolge der Parameter unterscheiden, nicht nur anhand der Anzahl und des Typs.

Kathy Van Stone
quelle
25
Dies war im Jahr 2009, staticalles wird im Jahr 2015 als ziemlich schädlich angesehen. Typensichere fließende BuilderInstanzen, die vollständige und gültige Bauaufträge durchsetzen, sind jetzt eine viel bessere Lösung.
135
@ JarrodRoberson: Statische Factory-Methoden sind nicht schädlicher als new. Sie werden verwendet , die ganze Zeit in neuem Code. Builder für einfache Wertobjekte sind häufig das Ergebnis von Überentwicklung.
Lii
12
@JarrodRoberson: Interessante Möglichkeit, die korrekte Verwendung über den Compiler zu erzwingen, danke für das Teilen! Freundlicher Vorschlag für zukünftige Beiträge: 300 Zeilen unkommentierten Quellcodes sind für die meisten Menschen wahrscheinlich etwas zu verdauen (Code ist schließlich schwerer zu lesen als zu schreiben). Danke noch einmal!
Christian Aichinger
17
@ JarrodRoberson: Schön, freue mich darauf! Was ich mitteilen wollte: Als Leser Ihres Blogs würde mir ein Beispiel mit 50 Zeilen und einer kurzen Textbeschreibung der Vorgänge mehr als 300 Zeilen ohne Kontext helfen.
Christian Aichinger
8
@ user177800 Nicht einverstanden - statische Methoden, wenn sie als reine Funktionen geschrieben wurden, sind vollkommen in Ordnung. Wenn eine statische Funktion mutiert, werden sie zu einem Problem ...
Levi Fuller
642

Nein, aber Sie können das Builder-Muster verwenden , wie in dieser Antwort zum Stapelüberlauf beschrieben .

Wie in der verknüpften Antwort beschrieben, können Sie mit dem Builder-Muster Code wie 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 auf andere Weise optional sind.

Eli Courtwright
quelle
142
Schließlich ein großartiges Beispiel für das Builder-Muster mit weniger als 2 Seiten.
Nevvermind
14
Ich bin allerdings neugierig, warum wir eine Builder-Klasse brauchen, wenn wir das Builder-Muster verwenden. Ich dachte an Student s1 = neuer Student (). Name ("Spicolo"). Alter (16). Motto ("Aloha, Mr Hand);
ivanceras
52
@ivanceras: Dies ist relevant, wenn für Klassen Felder erforderlich sind und Sie diese Klassen nicht in einem ungültigen Zustand instanziieren möchten. Wenn Sie also gerade gesagt haben Student s1 = new Student().age(16);, haben Sie einen Studenten ohne Namen, was möglicherweise schlecht ist. Wenn es nicht schlecht ist, ist Ihre Lösung in Ordnung.
Eli Courtwright
57
@ivanceras: Ein weiterer Grund ist, dass Sie möchten, dass Ihre Klasse nach der Erstellung unveränderlich ist, sodass Sie keine Methoden darin möchten, die ihre Werte ändern.
Jules
3
@ivanceras: Ich habe Builder für drei Dinge verwendet - das Eliminieren mehrerer Argumente und die fließende Initialisierung, Unveränderlichkeit und vor allem das Überprüfen des Domänenobjekts in der build () -Methode. Warum eine Objektinstanz erstellen, wenn sie ungültig ist. Sie können auch statische Elemente überladen Factory-Methoden wie im obigen Fall buildFreshman (), buildSenior () usw.
Abhijeet Kushe
485

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

  1. Methodenüberladung.

    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 besteht darin, dass er nicht funktioniert, wenn Sie zwei optionale Parameter desselben Typs haben und jeder von ihnen weggelassen werden kann.

  2. Varargs.

    a) Alle optionalen Parameter sind vom gleichen 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) Die Arten der optionalen Parameter 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 bei statischen Parametern unterschiedlicher Typen die statische Typprüfung verloren geht. Wenn jeder Parameter eine andere Bedeutung hat, müssen Sie ihn auf irgendeine Weise unterscheiden.

  3. Nullen. Um die Einschränkungen der vorherigen Ansätze zu beseitigen, können Sie Nullwerte zulassen und dann 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);

    Jetzt müssen alle Argumentwerte angegeben werden, die Standardwerte können jedoch null sein.

  4. Optionale Klasse. Dieser Ansatz ähnelt Nullen, verwendet jedoch die optionale Klasse Java 8 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 wird ein Methodenvertrag für einen Anrufer explizit festgelegt. Eine solche Signatur ist jedoch möglicherweise zu ausführlich.

  5. Builder-Muster. Das Builder-Muster wird für Konstruktoren verwendet und 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 von ihnen normalerweise Standardwerte verwendet werden, können Sie Methodenargumente als Zuordnung 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 jeden dieser Ansätze kombinieren können, um ein wünschenswertes Ergebnis zu erzielen.

Vitalii Fedorenko
quelle
1
Gute Erklärung. Ich habe noch nie solche Rückgabewerte gesehen. Für 5) was machen die return this? Auch, FooBuilder().setA("a").build();weil (per Definition) der Konstruktor zuerst aufgerufen wird und FooBuilder()einen Wert zurückgibt, bedeutet dies nicht, .setA("a"):dass er nicht die Chance bekommt, aufgerufen zu werden?
Celeritas
3
@Celeritas return thisgibt dasselbe Objekt zurück, für das die Methode aufgerufen wurde (im Beispiel FooBuilder). Dies ermöglicht die Verkettung von Methoden in einer Anweisung, die auf dasselbe Objekt wirkt: new FooBuilder().setA(..).setB(..).setC(..)usw., anstatt jede Methode in einer separaten Anweisung aufzurufen.
ADTC
2
@Celeritas new FooBuilder()gibt ein FooBuilderObjekt zurück, für das die setAMethode aufgerufen wird. Wie setBnicht aufgerufen, this.bbehält der Standardwert bei. Schließlich wird die buildMethode für dieses FooBuilderObjekt aufgerufen . Die buildMethode erstellt ein FooObjekt und gibt es zurück, das auf die Variable festgelegt ist Foo foo. Beachten Sie, dass das FooBuilderObjekt in keiner Variablen gespeichert ist.
ADTC
Anmerkungen können auch zum Erstellen von Standardparametern verwendet werden und sind am nützlichsten, wenn sie für polymorphe Sammlungen erforderlich sind. docs.oracle.com/javase/tutorial/java/annotations/declaring.html
Martin Spamer
1
Über 900 positive Stimmen zu derselben Antwort in zwei Fragen. Ich bin beeindruckt: stackoverflow.com/questions/965690/java-optional-parameters/…
AdamMc331
256

Traurigerweise Nein.

Rob H.
quelle
34
Ist es so traurig Dies würde möglicherweise mehrdeutige Funktionssignaturen einführen.
Trey
69
@Trey: Sprachen mit Standardparametern überladen häufig die Funktion, da sie dann weniger überzeugend sind. Also keine Mehrdeutigkeit. Außerdem hat Scala die Funktion in 2.8 hinzugefügt und das Mehrdeutigkeitsproblem irgendwie gelöst (da die Überladung aus Kompatibilitätsgründen beibehalten wurde).
PhiLho
32
Ich kann nicht erkennen, wie die Standardeinstellungen der Parameter eine Überlastung der Funktionen verhindern. C # ermöglicht beispielsweise Überschreibungen und Standardinitialisierungen. Scheint wie eine willkürliche Wahl, nicht Einschränkung ist der Grund.
FlavorScape
51
Ja, lassen Sie uns einen Kompromiss eingehen, damit der Compiler zusätzliche Arbeit leistet und stattdessen alle 100000 Überladungen schreiben, um unseren Bibliotheksbenutzern Komfort zu bieten. Gute Idee.
28
@ user562566: Immer wenn ich an einem Java-Projekt arbeite, habe ich den Eindruck, dass Java-Entwickler dafür bezahlt / gemessen werden, wie viele Codezeilen sie pro Tag produzieren
Mark K Cowan
83

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 fühlen, wenn der Compiler a generiert

new Boolean[]{}

für jeden Anruf.

Für mehrere voreingestellte 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 Standardparameter am Ende der Parameterliste zulässt.

Über die Syntax hinaus gibt es einen Unterschied, bei dem die Laufzeit-Typprüfung auf übergebene Standardparameter erfolgt und der C ++ - Typ diese beim Kompilieren überprüft.

ebelisle
quelle
14
Clever, aber varargs (...) können nur für den endgültigen Parameter verwendet werden. Dies ist einschränkender als die Sprachen, die Standardparameter unterstützen.
CurtainDog
6
Das ist klug, aber ein bisschen chaotisch im Vergleich zur C ++
Someone Somewhere
5
Java benötigt definitiv optionale Standardparameter, da C # und andere dies zulassen ... die Syntax ist offensichtlich und ich nehme an, dass sie dies ziemlich einfach implementieren können, selbst wenn sie nur alle möglichen Kombinationen kompilieren ... Ich kann mir nicht vorstellen, warum sie es nicht zur Sprache hinzugefügt haben noch!
JWL
10
Man sollte niemals einen assertProduktionscode verwenden. Eine Ausnahme auslösen.
Michael Dorst
5
-1 Das ist wirklich nicht das, wofür Varargs ist. Das ist ein Hack. - In diesem Fall ist die Verwendung von Überladungen viel besser lesbar (was bedauerlich ist, da drei zusätzliche Zeichen besser lesbar sind als 5 zusätzliche Zeilen der Quelle ...). - Java unterstützt jedoch keine Standardparameter.
BrainSlugs83
38

Nein, aber Sie können sie sehr einfach emulieren. 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 Standardparameter mehrdeutige Fälle bei der Funktionsüberladung verursachten. 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 Entwickler eine viel einfachere Sprache wollten als C ++ - wenn sie Recht hatten, ist eine andere Frage. Aber die meisten von uns glauben nicht, dass er Java wegen seiner Einfachheit verwendet.

Peter - Setzen Sie Monica wieder ein
quelle
8
Die Hauptidee der C # -Standardwertnotation besteht genau darin, diese Boilerplate-Codierung zu vermeiden und nur einen Konstruktor anstelle von vielen zu haben.
Kolya Ivankov
1
@KolyaIvankov Ich kenne C # nicht, aber ich kenne C ++, wo die Argumentation dieselbe ist. Ich weiß nicht, was besser ist, aber ich denke, tatsächlich wird vom Compiler im Fall von C ++ / C # derselbe Boilerplate-Code generiert und geht in die endgültige Binärdatei.
Peterh - Wiedereinsetzung Monica
5
Jede Programmiersprache ist (insbesondere) ein Mittel, um ein Assembler-Boilerplate zu vermeiden. Liege ich falsch? Die Frage ist nur, ob es eine praktische Funktionalität gibt oder nicht.
Kolya Ivankov
2
Der erste Satz ist eine rhetorische Frage. Das Wort "Frage" im zweiten Satz hat nichts mit der rhetorischen Frage im ersten zu tun.
Kolya Ivankov
1
Genauer gesagt: Sprachen sind Werkzeuge, mit denen wir Programme so schreiben können, dass wir die Kontrolle über das Geschriebene haben. Kompilieren ist eine Möglichkeit, einer Maschine mitzuteilen, was wir von ihr wollen. Ein Werkzeug ist nützlicher, wenn es uns ermöglicht, Boilerplate zu vermeiden. Tatsächlich fragte gnavi, ob sie genau die Art von Boilerplate-Code vermeiden können, die Sie als Antwort vorschlagen, da C # dies zulässt.
Kolya Ivankov
24

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

dh

class Foo(var prime: Boolean = false, val rib: String)  {}
lythisch
quelle
58
Bringen Sie eine ganz neue Sprache mit, um eine nicht so häufige Funktion zu erhalten?
Om-Nom-Nom
8
@ om-nom-nom: Java sollte niemals existieren. Zu sagen, dass eine Funktion nicht verwendet wird, ist gleichbedeutend damit, dass niemand sie benötigt. Wenn Java vor seiner Erfindung nicht beliebt war, sollte Gosling nicht damit beginnen, sie zu entwerfen.
Val
28
@ Val sagt nur, dass dies wie das Schießen von Vögeln mit Kanonen ist
om-nom-nom
8
das hat nichts mit der Frage des OP zu tun
destan
Funktioniert auch in Kotlin. Und Groovy. Und C#. Und Javascript. Und fast alle anderen Sprachen, die für echte Menschen und Probleme gemacht sind.
Spyro
17

Nein , aber der einfachste Weg, dies umzusetzen, ist:

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

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

public myParameterizedFunction(String param1, int param2) {

    this(param1, param2, false);
}

oder anstelle des ternären Operators können Sie Folgendes verwenden 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
quelle
2
Ja, dieser Ansatz scheint der beste unter den anderen Alternativen zu sein. Trotzdem wäre es schön, wenn Java Standardwerte übernehmen würde. Kotlin hat gezeigt, dass dies möglich ist, daher bin ich mir nicht sicher, warum Oracle nicht in die Moderne eintritt, und entwerfe Java weiterhin so, als ob es die 1990er Jahre wären. : D
Shevy
13

Ich könnte hier das Offensichtliche sagen, aber warum nicht einfach den "Standard" -Parameter selbst implementieren?

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

Für die Standardeinstellung würden Sie entweder verwenden

func("my string");

und wenn Sie die Standardeinstellung nicht verwenden möchten, würden Sie verwenden

func("my string", false);
IronWolf
quelle
11
Das Poster fragte, ob dieses (ziemlich hässliche) Muster vermieden werden kann ... ;-) In moderneren Sprachen (wie c #, Scala) benötigen Sie diese zusätzlichen Überladungen nicht, wodurch nur mehr Codezeilen entstehen. Bis zu einem gewissen Punkt können Sie in der Zwischenzeit varargs verwenden (static int max (int ... array) {}), aber sie sind nur eine sehr hässliche Problemumgehung.
Offler
2
Überladen ist nicht hässlich und hat viele Vorteile, z. B. können unterschiedliche Methodenaufrufe mit unterschiedlichen Signaturen unterschiedliche Funktionen ausführen. //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
Nun, wenn man ein anderes Verhalten will. Wenn der einzige Unterschied eine geringfügige Änderung der Berechnungen usw. ist, ist es sicher eine Verschwendung von Aufwand, mehrere Signaturen zu erstellen. Standardeinstellungen sind dort sinnvoll, wo sie benötigt werden ... und das Fehlen sollte nicht als "nutzlose" Anforderung eingestuft werden.
Kapil
@ Offler Standardparameter haben nichts mit "moderner Sprache" zu tun. Ich habe sie vor 20 Jahren in Delphi benutzt und sie existierten wahrscheinlich bereits in Turbo Pascal.
Der unglaubliche
Ich stimme Offler zu und stimme Antony Booth nicht zu. Ich finde es nicht nur hässlich, sondern auch ziemlich ineffizient. Sprachen wie Ruby oder Python machen es trivial, Standardparameter zu verwenden. Ich denke, Java erfordert, dass Sie Problemumgehungen finden (und verwenden). Die explizite Prüfung gegen Null scheint die am wenigsten hässliche Wahl zu sein, da ich das auch über die Befehlszeile aufrufen kann (nur nichts bereitstellen und dann die vernünftige Variante behandeln); Der Operator-Überladungsansatz scheint ... sehr ausführlich zu sein (wie mindestens +3 Zeilen im Vergleich zur Nullprüfung und mehr Zeilen, wenn der Code komplexer ist).
Shevy
8

Wie Scala erwähnt wurde, ist auch Kotlin erwähnenswert. In Kotlin können Funktionsparameter auch Standardwerte haben und sich sogar auf andere Parameter beziehen:

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

Kotlin läuft wie Scala auf der JVM und kann problemlos in bestehende Java-Projekte integriert werden.

mrts
quelle
6

Nein.

Sie können dasselbe Verhalten erzielen, indem Sie ein Objekt mit intelligenten Standardeinstellungen übergeben. Aber auch hier kommt es darauf an, was Ihr Fall ist.

Santosh Gokak
quelle
5

Nein. Im Allgemeinen hat Java nicht viel (irgendeinen) syntaktischen Zucker, da sie versucht haben, eine einfache Sprache zu erstellen.

Tomjen
quelle
26
Nicht ganz. Die bittere Wahrheit ist, dass das Team einen engen Zeitplan hatte und keine Zeit für syntaktischen Zucker hatte. Warum sonst constund gotoreserviert Schlüsselwörter, die keine Implementierung? - Besonders constetwas vermisse ich bitter - finalist kein Ersatz und sie wussten es. - Und wenn Sie die bewusste Entscheidung getroffen haben, niemals zu implementieren, müssen gotoSie das Schlüsselwort nicht reservieren. - Und später im Java-Team betrogen, indem es das Label basiert breakund continueso mächtig wie ein Pascal machte goto.
Martin
"Einfach, objektorientiert und vertraut" war in der Tat ein Designziel - siehe oracle.com/technetwork/java/intro-141325.html
mikera
1
tomjen sagte: "Nein. Im Allgemeinen hat Java nicht viel (irgendeinen) syntaktischen Zucker, da sie versucht haben, eine einfache Sprache zu erstellen." Sie sagen also, dass das Entfernen vieler unnötiger Funktionen aus C ++ Java zu einer einfachen Sprache macht. Sagen Sie mir dann, warum Java über verschiedene Methoden verfügt. Warum hat es Varargs? Es wird nicht benötigt, wenn Sie stattdessen einfach ein Array von Objekten verwenden können, habe ich Recht? So können Varargs aus der Sprache entfernt werden, da dies nicht erforderlich ist. Dadurch wird Java einfacher als jetzt. Habe ich recht? Überladung kann auch entfernt werden, da Sie für jede Methode unendlich viele Namen haben.
1
und deshalb haben wir Frühling und Sachen, die die einfache Sprache nehmen und jedes echte Java-Projekt in einen Clusterfick aus Syntax und Boilerplate
verwandeln
Entwickler dazu zu zwingen, Code und komplizierte Problemumgehungen zu erstellen, ist nicht mein Verständnis des Wortes "einfach". myFunction (a, b = false, c = 3), das nenne ich einfach.
Spyro
5

Anstatt zu verwenden:

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

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

Sie können die optionale Funktionalität von Java mit einer einzigen Methode nutzen:

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

Der Hauptunterschied besteht darin, dass Sie Wrapper-Klassen anstelle von primitiven Java-Typen verwenden müssen, um nullEingaben zu ermöglichen . Booleanstatt boolean, Integerstatt intund so weiter.

Viktor Taranenko
quelle
4

Es wird nicht unterstützt, aber es gibt verschiedene Optionen wie die Verwendung von Parameterobjektmustern mit etwas Syntaxzucker:

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

In diesem Beispiel konstruieren wir ParameterObjectmit Standardwerten und überschreiben diese im Abschnitt zur Initialisierung der Klasseninstanz{ param1 = 10; param2 = "bar";}

hoaz
quelle
3

Versuchen Sie diese Lösung:

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

    return score;
}
Hamzeh Soboh
quelle
3

Sie können den Java Method Invocation Builder verwenden , um den Builder automatisch mit Standardwerten zu generieren.

Fügen Sie einfach @GenerateMethodInvocationBuilder zur Klasse oder Schnittstelle und @Default zu Parametern in Methoden hinzu, in denen Sie Standardwerte wünschen. Zur Kompilierungszeit wird ein Builder mit den Standardwerten generiert, die Sie in Ihren Anmerkungen angegeben haben.

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

Und dann können Sie die Methoden aufrufen.

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

Oder setzen Sie einen der Standardwerte auf einen anderen Wert.

CarService instance = new CarService();
String carsByFilter = CarServiceGetCarsByFilterBuilder.getCarsByFilter()//
  .withColor(Color.YELLOW)//
  .invoke(instance);
Tomas Bjerre
quelle
2

Ein ähnlicher Ansatz für https://stackoverflow.com/a/13864910/2323964 , der in Java 8 funktioniert, ist die Verwendung einer Schnittstelle mit Standard-Gettern. Dies ist ein ausführlicheres Leerzeichen, ist jedoch verspottbar und eignet sich hervorragend, wenn Sie eine Reihe von Fällen haben, in denen Sie tatsächlich auf die Parameter aufmerksam machen möchten.

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
quelle
2

Ich habe jetzt einige Zeit damit verbracht, herauszufinden, wie dies mit Methoden verwendet werden kann, die Werte zurückgeben, und ich habe bisher keine Beispiele gesehen. Ich dachte, es könnte nützlich sein, dies hier hinzuzufügen:

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

int foo() {
    return foo(0); // here, 0 is a default value for a
}
AAGD
quelle
1

So habe ich es gemacht ... es ist vielleicht nicht so praktisch wie ein 'optionales Argument' gegen Ihren definierten Parameter, aber es erledigt den Job:

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

Beachten Sie, dass ich denselben Methodennamen entweder nur mit einer Zeichenfolge oder mit einer Zeichenfolge und einem booleschen Wert aufrufen kann. In diesem Fall wird durch Setzen von wipeClean auf true der gesamte Text in meiner TextArea durch die angegebene Zeichenfolge ersetzt. Wenn Sie wipeClean auf false setzen oder alles zusammen weglassen, wird der bereitgestellte Text einfach an die TextArea angehängt.

Beachten Sie auch, dass ich den Code in den beiden Methoden nicht wiederhole. Ich füge lediglich die Funktionalität hinzu, die TextArea zurücksetzen zu können, indem eine neue Methode mit demselben Namen nur mit dem hinzugefügten Booleschen Wert erstellt wird.

Ich denke tatsächlich, dass dies ein wenig sauberer ist, als wenn Java ein 'optionales Argument' für unsere Parameter bereitstellen würde, da wir dann für Standardwerte usw. codieren müssten. In diesem Beispiel muss ich mir darüber keine Gedanken machen. Ja, ich habe meiner Klasse noch eine weitere Methode hinzugefügt, aber meiner bescheidenen Meinung nach ist es auf lange Sicht einfacher zu lesen.

Michael Sims
quelle
1

NEIN, aber wir haben eine Alternative in Form von Funktionsüberladung.

Wird aufgerufen, wenn kein Parameter übergeben wurde

void operation(){

int a = 0;
int b = 0;

} 

Wird aufgerufen, wenn der Parameter "a" übergeben wurde

void operation(int a){

int b = 0;
//code

} 

wird aufgerufen, wenn Parameter b übergeben wurde

void operation(int a , int b){
//code
} 
Umair Khalid
quelle
1

Es gibt ein halbes Dutzend oder bessere Probleme wie dieses. Schließlich gelangen Sie zum statischen Factory-Muster. Siehe dazu die Krypto-API. Sortieren Sie schwer zu erklären, aber denken Sie so: Wenn Sie einen Konstruktor haben, standardmäßig oder auf andere Weise, besteht die einzige Möglichkeit, den Status über die geschweiften Klammern hinaus zu verbreiten, darin, entweder einen Booleschen Wert zu haben. (zusammen mit der Null als Standardwert v fehlgeschlagener Konstruktor) oder lösen Sie eine Ausnahme aus, die niemals informativ ist, wenn Sie sie von Feldbenutzern zurückerhalten.

Code Richtig, verdammt, ich schreibe tausend Zeilenkonstruktoren und mache, was ich brauche. Ich finde die Verwendung von isValid bei der Objektkonstruktion - mit anderen Worten, zweizeilige Konstruktoren -, aber aus irgendeinem Grund migriere ich zum statischen Factory-Muster. Ich scheine nur, dass Sie viel tun können, wenn Sie in einem Methodenaufruf immer noch Probleme mit sync () haben, aber die Standardeinstellungen können besser (sicherer) "ersetzt" werden.

Ich denke, wir müssen hier das Problem von null als Standardwert gegenüber etwas behandeln. String one = new String (""); Als Mitgliedsvariable wird dann auf Null geprüft, bevor dem Konstruktor übergebene Zeichenfolge zugewiesen wird.

Sehr bemerkenswert ist die Menge an roher, stratosphärischer Informatik, die in Java durchgeführt wird.

C ++ und so weiter hat Vendor Libs, ja. Java kann sie auf großen Servern überholen, da es sich um eine riesige Toolbox handelt. Studieren Sie statische Initialisierungsblöcke, bleiben Sie bei uns.

Nicholas Jordan
quelle
1

Es wird in Java nicht unterstützt, wie beispielsweise in anderen Sprachen. Kotlin.

Virendra Pal Singh
quelle
0

Sie können Folgendes verwenden:

public void mop(Integer x) {
  // Define default values
        x = x == null ? 200 : x;
}
Sobhit Sharma
quelle