Java supporte-t-il les valeurs par défaut?

j'ai trouvé 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 que dans C++ je peux assigner une valeur par défaut à un paramètre. 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?

1340
demandé sur peterh 2009-06-15 22:04:28

19 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: Programming Language Guide's " item 1 tip (Consider static factory methods instead of constructors) if the overloading is getting complicated. Pour d'autres méthodes, renommer certains cas ou utiliser un objet paramètre peut aider. C'est quand vous avez assez de complexité cette différenciation est difficile. Un cas défini est où vous devez différencier en utilisant l'ordre des paramètres, pas seulement le nombre et le type.

773
répondu Kathy Van Stone 2013-09-13 17:12:48

Non, mais vous pouvez utiliser le bouton Générateur de Pattern , comme décrit dans ce Débordement de Pile réponse .

comme décrit dans la réponse liée, le modèle de constructeur vous permet d'écrire le 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 en option.

551
répondu Eli Courtwright 2017-05-23 12:34:53

il y a plusieurs façons de simuler les paramètres par défaut en 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");
    

    L'une des limites de cette approche est qu'elle ne fonctionne pas si vous avez deux paramètres optionnels du même type et l'un d'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 facultatifs 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 le contrôle de type statique. De plus, si chaque paramètre a une signification différente, vous avez besoin d'un moyen pour les distinguer.

  3. les valeurs Null. pour adresser la limites des approches précédentes vous pouvez autoriser des valeurs nulles et ensuite 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 d'arguments doivent être fournies, mais celles par défaut peuvent être nulles.

  4. class Facultatif. cette approche est similaire à nulls, mais utilise la classe optionnelle Java 8 pour les paramètres qui ont 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 méthode contrat explicite pour un appelant, cependant, on peut trouver une telle signature trop verbeuse.

  5. Générateur de modèle. le modèle de constructeur est utilisé pour les constructeurs et est mis en œuvre par l'introduction d'une classe de constructeur 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. des Cartes. lorsque le nombre de paramètres est trop grand et que pour la plupart d'entre eux des valeurs par défaut sont habituellement utilisées, vous peut passer des arguments de méthode comme 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 l'une de ces approches pour obtenir un résultat souhaitable.

365
répondu Vitalii Fedorenko 2018-06-14 23:10:44

malheureusement, non.

198
répondu Rob H 2009-06-15 18:05:16

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 oui ou non vous devriez dépendre de ce que vous pensez du compilateur générant un

new Boolean[]{}

pour chaque appel.

pour plusieurs paramètres défaultables:

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 permet uniquement 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 lorsque cela a fait tourner la vérification de type de temps pour les paramètres défaultables passés et que le type C++ Les vérifie pendant la compilation.

76
répondu ebelisle 2013-10-03 21:37:48

Non, mais vous pouvez très facilement les imiter. Ce qui 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 le les créateurs voulaient un langage beaucoup plus simple comme C++ l'était - s'ils avaient raison, c'est une autre question. Mais la plupart d'entre nous ne pensent pas qu'il utilise Java à cause de sa simplicité.

35
répondu peterh 2017-10-18 03:39:53

vous pouvez faire cela dans Scala, qui fonctionne sur le 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
répondu lythic 2012-04-03 13:58:02

je pourrais énoncer l'évidence ici, mais pourquoi ne pas simplement mettre en œuvre le paramètre" default " vous-même?

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

par défaut vous éther utiliser

func("ma chaîne");

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

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

11
répondu IronWolf 2013-02-18 14:05:09

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

6
répondu tomjen 2009-06-15 18:49:17

Pas de.

vous pouvez obtenir le même comportement en passant un objet qui a des valeurs par défaut intelligentes. Mais encore une fois cela dépend de ce que votre cas est à portée de main.

6
répondu Santosh Gokak 2013-09-13 17:13:45

Non , mais la manière la plus simple de mettre en œuvre ce est:

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

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

public myParameterizedFunction(String param1, int param2) {

    this(param1, param2, false);
}

Ou à la place de l'opérateur ternaire vous pouvez utiliser si:

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

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

public myParameterizedFunction(String param1, int param2) {

    this(param1, param2, false);
}
6
répondu simhumileco 2018-08-29 13:51:29

comme Scala a été mentionné, Kotlin est également digne de mention. Dans la fonction Kotlin, les paramètres peuvent aussi avoir des valeurs par défaut et ils peuvent même renvoyer à d'autres paramètres:

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

comme Scala, Kotlin fonctionne sur JVM et peut être facilement intégré dans les projets Java existants.

4
répondu mrts 2017-11-26 19:51:08

il n'est pas supporté, mais il y a plusieurs options comme utiliser le paramètre object pattern avec un certain sucre de syntaxe:

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

dans cet échantillon, nous construisons ParameterObject avec des valeurs par défaut et les outrepassons dans la section d'initialisation de l'instance de classe { param1 = 10; param2 = "bar";}

3
répondu hoaz 2012-12-13 17:15:14

essayez cette solution:

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

    return score;
}
3
répondu Hamzeh Soboh 2014-09-03 16:45:05

il y a une demi-douzaine ou mieux de problèmes tels que celui-ci, éventuellement vous arrivez à la configuration statique de l'usine ... voir l'api de chiffrement. Tri difficile à expliquer, mais pensez-y de cette façon: si vous avez un constructeur, par défaut ou autrement, la seule façon de propager l'état au-delà des lacets bouclés est soit d'avoir un booléen isValid; ( avec la valeur nulle par défaut v failed constructor ) ou de jeter une exception qui n'est jamais informative en le récupérant des utilisateurs de terrain.

code Correct soit damné, j'écris mille constructeurs de ligne et faire ce dont j'ai besoin. Je trouve que l'utilisation d'isValid à la construction d'objet - en d'autres termes, deux constructeurs de ligne - mais pour une raison quelconque, je suis en train de migrer vers le modèle d'usine statique. Je viens d'semble que vous pouvez faire beaucoup de choses si vous êtes dans un appel de méthode, il y a toujours sync() les questions, mais les valeurs par défaut peuvent être "remplacé" mieux ( safer )

je pense que ce que nous devons faire ici est de traiter la question de null comme valeur par défaut vis-a-vis something String one=new String(""); en tant que variable membre, puis faire une vérification pour null avant d'assigner une chaîne passée au constructeur.

Très remarquable la quantité de matières premières, de l'ozone stratosphérique informatique fait en Java.

C++ et ainsi de suite a vendeur libs, oui. Java peut les distancer sur les serveurs à grande échelle en raison de sa boîte à outils massive. Étudiez les blocs statiques d'initialisation, restez avec nous.

1
répondu Nicholas Jordan 2009-09-28 02:33:40

C'est comme ça que je l'ai fait ... ce n'est peut-être pas aussi pratique que d'avoir un 'argument optionnel' contre votre paramètre défini, mais cela permet de faire le travail:

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

Avis je peux invoquer le même nom de méthode avec juste un string ou je peux l'appeler avec une chaîne et une valeur booléenne. Dans ce cas, mettre wipeClean à true remplacera tout le texte de ma TextArea par la chaîne de caractères fournie. Mettre wipeClean à false ou tout simplement l'abandonner ajoute le texte fourni pour le TextArea.

notez aussi que je ne répète pas de code dans les deux méthodes, Je ne fais qu'ajouter la fonctionnalité de pouvoir réinitialiser le TextArea en créant une nouvelle méthode avec le même nom seulement avec le booléen ajouté.

en fait, je pense que C'est un peu plus propre que si Java fournissait un "argument optionnel" pour nos paramètres puisque nous aurions besoin de coder les valeurs par défaut etc. Dans cet exemple, je n'ai pas besoin de vous soucier de tout ça. Oui, j'ai ajouté une autre méthode à ma classe, mais c'est plus facile à lire à long terme à mon humble avis.

1
répondu Michael Sims 2015-01-18 15:40:19

une approche similaire à https://stackoverflow.com/a/13864910/2323964 qui fonctionne en Java 8 est d'utiliser une interface avec des getters par défaut. Ce sera plus verbeux dans l'espace, mais est mockable, et c'est génial pour quand vous avez un tas d'instances où vous voulez réellement attirer l'attention sur les paramètres.

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
répondu Novaterata 2017-05-23 11:47:32

vous pouvez utiliser Java Method Invocation Builder pour générer automatiquement le constructeur avec des valeurs par défaut.

il suffit d'ajouter @GenerateMethodInvocationBuilder à la classe, ou l'interface, et le @Default aux paramètres dans les méthodes où vous voulez des valeurs par défaut. Un builder sera généré au moment de la compilation, en utilisant les valeurs par défaut que vous avez spécifiées avec vos annotations.

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

Et alors vous pouvez invoquer le méthode.

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

ou définissez l'une des valeurs par défaut à autre chose.

CarService instance = new CarService();
String carsByFilter = CarServiceGetCarsByFilterBuilder.getCarsByFilter()//
  .withColor(Color.YELLOW)//
  .invoke(instance);
0
répondu Tomas Bjerre 2016-06-13 17:42:50

non, mais nous avons alternative sous la forme de la surcharge de fonction.

appelé quand aucun paramètre ne passe

void operation(){

int a = 0;
int b = 0;

} 

appelé quand" un "paramètre a été passé

void operation(int a){

int b = 0;
//code

} 

appelé quand le paramètre B passe

void operation(int a , int b){
//code
} 
0
répondu Umair Khalid 2016-09-01 06:51:15