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?
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.
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.
il y a plusieurs façons de simuler les paramètres par défaut en Java:
-
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.
-
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.
-
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.
-
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.
-
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();
-
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.
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.
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é.
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) {}
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);
Pas de. En général, Java n'a pas beaucoup de sucre syntaxique, car ils ont essayé de faire un langage simple.
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.
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);
}
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.
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";}
essayez cette solution:
public int getScore(int score, Integer... bonus)
{
if(bonus.length > 0)
{
return score + bonus[0];
}
return score;
}
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.
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.
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; }
});
}
}
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);
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
}