Question Java prend-il en charge les valeurs de paramètre par défaut?


Je suis tombé sur du code Java qui avait la structure suivante:

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

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

Je sais qu'en C ++ je peux assigner un paramètre à une valeur par défaut. Par exemple:

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

Est-ce que Java supporte ce genre de syntaxe? Y a-t-il des raisons pour lesquelles cette syntaxe en deux étapes est préférable?


1311
2018-06-15 18:04


origine


Réponses:


Non, la structure que vous avez trouvée est la façon dont Java la gère (c'est-à-dire avec une surcharge au lieu des paramètres par défaut).

Pour les constructeurs, Voir Java efficace: Guide du langage de programmation Item 1 tip (Considérez les méthodes statiques d'usine au lieu des constructeurs) si la surcharge devient compliquée. Pour les autres méthodes, il peut être utile de renommer certains cas ou d'utiliser un objet de paramètre. C'est quand vous avez assez de complexité que la différenciation est difficile. Un cas précis est où vous devez différencier en utilisant l'ordre des paramètres, pas seulement le nombre et le type.


757
2018-06-15 18:14



Non, mais vous pouvez utiliser le Modèle de constructeur, comme décrit dans cette réponse Stack Overflow.

Comme décrit dans la réponse liée, le motif Builder vous permet d'écrire du code comme

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

dans lequel certains champs peuvent avoir des valeurs par défaut ou être optionnels.


541
2018-06-15 19:20



Il existe plusieurs façons de simuler les paramètres par défaut dans Java:

  1. Méthode de surcharge.

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

    Une des limites de cette approche est qu'elle ne fonctionne pas si vous avez deux paramètres optionnels du même type et que l'un d'entre eux peut être omis.

  2. Varargs.

    a) Tous les paramètres optionnels sont du même type:

    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) Les types de paramètres optionnels peuvent être différents:

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

    Le principal inconvénient de cette approche est que si les paramètres optionnels sont de types différents, vous perdez la vérification de type statique. De plus, si chaque paramètre a une signification différente, vous avez besoin d'un moyen de les distinguer.

  3. Nuls Pour résoudre les limitations des approches précédentes, vous pouvez autoriser les valeurs NULL, puis analyser chaque paramètre dans un corps de méthode:

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

    Maintenant, toutes les valeurs des arguments doivent être fournies, mais celles par défaut peuvent être nulles.

  4. Classe optionnelle Cette approche est similaire aux valeurs null, mais utilise la classe Java 8 Optional pour les paramètres ayant une valeur par défaut:

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

    Facultatif rend un contrat de méthode explicite pour un appelant, cependant, on peut trouver une telle signature trop verbeuse.

  5. Modèle de constructeur. Le modèle de générateur est utilisé pour les constructeurs et est implémenté en introduisant une classe Builder séparée:

     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. Plans. Lorsque le nombre de paramètres est trop élevé et que la plupart des valeurs par défaut sont généralement utilisées, vous pouvez passer les arguments de la méthode sous la forme d'une carte de leurs noms / valeurs:

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

Veuillez noter que vous pouvez combiner n'importe laquelle de ces approches pour obtenir un résultat souhaitable.


348
2017-11-01 02:03



Malheureusement non.


197
2018-06-15 18:05



Malheureusement oui.

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

pourrait être écrit en Java 1.5 comme:

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

Mais si vous dépendez de ce que vous pensez du compilateur

new Boolean[]{}

pour chaque appel.

Pour plusieurs paramètres par défaut:

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

pourrait être écrit en Java 1.5 comme:

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

Cela correspond à la syntaxe C ++, qui n'autorise que les paramètres par défaut à la fin de la liste des paramètres.

Au-delà de la syntaxe, il y a une différence où cela a un contrôle du type d'exécution pour les paramètres par défaut passés et le type C ++ les vérifie pendant la compilation.


76
2018-05-26 21:51



Non, mais vous pouvez très facilement les imiter. Qu'est-ce en C ++ était:

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

En Java, ce sera une fonction surchargée:

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

Plus tôt a été mentionné, que les paramètres par défaut ont causé des cas ambigus dans la surcharge de la fonction. Ce n'est tout simplement pas vrai, on peut le voir dans le cas du C ++: oui, peut-être qu'il peut créer des cas ambigus, mais ces problèmes peuvent être facilement traités. Il n'a tout simplement pas été développé en Java, probablement parce que les créateurs voulaient un langage beaucoup plus simple que C ++ - s'ils avaient raison, c'est une autre question. Mais la plupart d'entre nous ne pense pas qu'il utilise Java en raison de sa simplicité.


35
2017-11-04 09:12



Vous pouvez le faire dans Scala, qui fonctionne sur la JVM et est compatible avec les programmes Java. http://www.scala-lang.org/

c'est à dire.

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

19
2017-07-21 16:26



Je pourrais dire l'évidence ici mais pourquoi ne pas simplement implémenter le paramètre «par défaut» vous-même?

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

pour la valeur par défaut, vous utiliseriez l'éther

func ("ma chaîne");

et si vous ne souhaitez pas utiliser la valeur par défaut, vous utiliserez

func ("ma chaîne", false);


11
2018-02-18 13:59



Non. En général, Java n'a pas beaucoup de sucre syntaxique, car ils ont essayé de faire un langage simple.


6
2018-06-15 18:49