Parametri opzionali Java


813

Come posso utilizzare i parametri opzionali in Java? Quali specifiche supportano i parametri opzionali?

Risposte:


517

varargs potrebbe farlo (in un certo senso). Oltre a ciò, devono essere fornite tutte le variabili nella dichiarazione del metodo. Se si desidera che una variabile sia facoltativa, è possibile sovraccaricare il metodo utilizzando una firma che non richiede il parametro.

private boolean defaultOptionalFlagValue = true;

public void doSomething(boolean optionalFlag) {
    ...
}

public void doSomething() {
    doSomething(defaultOptionalFlagValue);
}

Il sovraccarico del metodo è una buona risposta secondo me, mentre varargs è una pessima risposta. Rimuovere il commento su Varargs o spiegare il grave svantaggio causato dalla possibilità di più di un valore di ritorno.
Andreas Vogl, il

L'aggiunta di variabili globali potrebbe causare altri problemi.
Helen Cui,

1652

Esistono diversi modi per simulare parametri opzionali in Java:

  1. Metodo sovraccarico.

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

    Una delle limitazioni di questo approccio è che non funziona se si hanno due parametri opzionali dello stesso tipo e uno qualsiasi di essi può essere omesso.

  2. Varargs.

    a) Tutti i parametri opzionali sono dello stesso tipo:

    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) I tipi di parametri opzionali possono essere diversi:

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

    Lo svantaggio principale di questo approccio è che se i parametri opzionali sono di tipi diversi si perde la verifica del tipo statico. Inoltre, se ogni parametro ha un significato diverso, è necessario un modo per distinguerli.

  3. Null. Per affrontare i limiti degli approcci precedenti è possibile consentire valori null e quindi analizzare ogni parametro in un corpo del metodo:

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

    Ora devono essere forniti tutti i valori degli argomenti, ma quelli predefiniti potrebbero essere nulli.

  4. Classe opzionale. Questo approccio è simile ai null, ma utilizza la classe opzionale Java 8 per i parametri che hanno un valore predefinito:

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

    Facoltativo rende esplicito un contratto di metodo per un chiamante, tuttavia, è possibile trovare tale firma troppo dettagliata.

    Aggiornamento: Java 8 include la classe java.util.Optionalpronta all'uso, quindi non è necessario utilizzare guava per questo particolare motivo in Java 8. Il nome del metodo è tuttavia leggermente diverso.

  5. Modello del costruttore. Il modello builder viene utilizzato per i costruttori e viene implementato introducendo una classe Builder separata:

     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. Mappe. Quando il numero di parametri è troppo grande e di solito vengono utilizzati per la maggior parte dei valori predefiniti, è possibile passare argomenti del metodo come una mappa dei loro nomi / valori:

    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 = (Integer)parameters.get("a");
        }
        if (parameters.containsKey("b")) { 
            //... 
        }
        //...
    }
    
    foo(ImmutableMap.<String, Object>of(
        "a", "a",
        "b", 2, 
        "d", "value")); 

    In Java 9, questo approccio è diventato più semplice:

        @SuppressWarnings("unchecked")
        static <T> T getParm(Map<String, Object> map, String key, T defaultValue)
        {
            return (map.containsKey(key)) ? (T) map.get(key) : defaultValue;
        }
    
        void foo(Map<String, Object> parameters) {
            String a = getParm(parameters, "a", "");
            int b = getParm(parameters, "b", 0);
            // d = ...
        }
    
        foo(Map.of("a","a",  "b",2,  "d","value"));

Si noti che è possibile combinare uno di questi approcci per ottenere un risultato desiderabile.


2
@Vitalii Fedorenko Hmm, penso che tu abbia fatto un leggero errore di copia-incolla in # 6: stai controllando il tipo per un numero intero anche se la tua avariabile è una stringa (il cast è corretto).
ID sconosciuto

5
@Aetos il tuo link è morto.
Robino,

2
Link alternativo @Robino sostenendo che Opzionale non dovrebbe essere usato come parametro qui . Nonostante l'uso di Optionalcome parametro in una delle opzioni, questa risposta è molto buona.
Dherik,

La soluzione più comune al problema sopra è probabilmente il sovraccarico del metodo. Anche se non sono mai stato un fan di questo. Personalmente preferirei se aggiungessero un qualche tipo di identificatore per i parametri di configurazione.
Alexander Heim,

1
questa dovrebbe essere probabilmente la migliore risposta - copre tutto
xproph

104

Esistono parametri opzionali con Java 5.0. Dichiara semplicemente la tua funzione in questo modo:

public void doSomething(boolean... optionalFlag) {
    //default to "false"
    //boolean flag = (optionalFlag.length >= 1) ? optionalFlag[0] : false;
}

potresti chiamare con doSomething();o doSomething(true);ora.


13
Questa è in realtà la risposta corretta. È semplice e compatto. Ricorda solo che potresti ottenere più di un parametro in modo che Java li inserisca in un array. Ad esempio, per recuperare un singolo parametro è necessario verificare prima i contenuti dell'array: 'code' boolean flag = (optionalFlag.length <1)? False: optionalFlag [0];
Salvador Valencia,

46
No, non è la risposta corretta, perché ciò non consente un singolo parametro facoltativo, ma un numero qualsiasi di parametri opzionali. Anche se questo è vicino a ciò che vuole OP, non è lo stesso. È una potenziale fonte di bug e incomprensioni accettare più parametri del necessario.
sleske,

2
In questo modo funziona se si dispone di un solo parametro facoltativo, ma è necessario controllare la lunghezza dell'array, ecc., Quindi non è super pulito: | Se si desidera un parametro facoltativo "un parametro", è possibile anche dichiarare due metodi (uno sovraccaricato doSomething() { doSomething(true); }, nessuna
matrice

Se ci sono più parametri opzionali, questo funziona solo se sono tutti dello stesso tipo di dati. Bene, potresti creare il tipo Object, ma sta diventando davvero brutto.
Jay

Come notato da @sleske, l'uso di varargs ha il terribile svantaggio di consentire il passaggio di più di un valore. OP ha chiaramente chiesto una soluzione per "opzionale", che significa un valore o zero. Come questo possa essere considerato una buona risposta da alcuni è vicino a me.
Andreas Vogl,

99

Puoi usare qualcosa del genere:

public void addError(String path, String key, Object... params) { 
}

La paramsvariabile è facoltativa Viene trattato come un array nullable di oggetti.

Stranamente, non ho trovato nulla al riguardo nella documentazione, ma funziona!

Questo è "nuovo" in Java 1.5 e versioni successive (non supportato in Java 1.4 o versioni precedenti).

Vedo anche l'utente bhoot menzionato di seguito.


55

Purtroppo Java non supporta direttamente i parametri predefiniti.

Tuttavia, ho scritto una serie di annotazioni JavaBean e una di esse supporta parametri predefiniti come il seguente:

protected void process(
        Processor processor,
        String item,
        @Default("Processor.Size.LARGE") Size size,
        @Default("red") String color,
        @Default("1") int quantity) {
    processor.process(item, size, color, quantity);
}
public void report(@Default("Hello") String message) {
    System.out.println("Message: " + message);
}

Il processore di annotazione genera i sovraccarichi del metodo per supportarlo correttamente.

Vedi http://code.google.com/p/javadude/wiki/Annotations

Esempio completo su http://code.google.com/p/javadude/wiki/AnnotationsDefaultParametersExample


53

Non ci sono parametri opzionali in Java. Quello che puoi fare è sovraccaricare le funzioni e quindi passare i valori predefiniti.

void SomeMethod(int age, String name) {
    //
}

// Overload
void SomeMethod(int age) {
    SomeMethod(age, "John Doe");
}

23

Sono stati menzionati VarArgs e sovraccarico. Un'altra opzione è un modello Builder, che sarebbe simile a questo:

 MyObject my = new MyObjectBuilder().setParam1(value)
                                 .setParam3(otherValue)
                                 .setParam6(thirdValue)
                                 .build();

Sebbene quel modello sarebbe più appropriato per quando sono necessari parametri opzionali in un costruttore.


voglio aggiungere la dipendenza da parametri per that.let, dico che voglio impostare param3 solo se ho impostato param1. Per es. voglio impostare il messaggio di avanzamento solo se imposto progressi visibili. isProgressVisible (). setProgressMessage ("caricamento"). come posso farlo?
Harshal Bhatt,

14

In JDK> 1.5 puoi usarlo in questo modo;

public class NewClass1 {

    public static void main(String[] args) {

        try {
            someMethod(18); // Age : 18
            someMethod(18, "John Doe"); // Age & Name : 18 & John Doe
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    static void someMethod(int age, String... names) {

        if (names.length > 0) {
            if (names[0] != null) {
                System.out.println("Age & Name : " + age + " & " + names[0]);
            }
        } else {
            System.out.println("Age : " + age);
        }
    }
}

7

Puoi fare qualcosa usando il metodo di sovraccarico in questo modo.

 public void load(String name){ }

 public void load(String name,int age){}

Inoltre puoi usare l'annotazione @Nullable

public void load(@Nullable String name,int age){}

passa semplicemente null come primo parametro.

Se stai passando la stessa variabile di tipo puoi usarla

public void load(String name...){}

7

Versione breve :

Utilizzando tre punti :

public void foo(Object... x) {
    String first    =  x.length > 0 ? (String)x[0]  : "Hello";
    int duration    =  x.length > 1 ? Integer.parseInt((String) x[1])     : 888;
}   
foo("Hii", ); 
foo("Hii", 146); 

(basato sulla risposta di @ VitaliiFedorenko)


2

Il sovraccarico va bene, ma se ci sono molte variabili che richiedono un valore predefinito, finirai con:

public void methodA(A arg1) {  }
public void methodA( B arg2,) {  }
public void methodA(C arg3) {  }
public void methodA(A arg1, B arg2) {  }
public void methodA(A arg1, C arg3) {  }
public void methodA( B arg2, C arg3) {  }
public void methodA(A arg1, B arg2, C arg3) {  }

Quindi suggerirei di usare l'argomento Variable fornito da Java. Ecco un link per la spiegazione.


l'uso di varargs è considerato una cattiva pratica. se il sistema necessita di tali metodi (sopra menzionati), allora dovresti pensare a un nuovo design poiché il design della classe sembra male.
Diablo

2
È una pratica ancora peggiore inventare scuse per le carenze di Java e accusare gli altri di cattive pratiche per aver notato quegli inconvenienti e escogitare soluzioni alternative.
BrianO

1
Aggiungi tutte le informazioni pertinenti alla tua risposta invece di collegarti a fonti esterne - il link indicato è morto
Nico Haase,

2

Puoi usare una classe che funziona in modo molto simile a un builder per contenere i tuoi valori opzionali come questo.

public class Options {
    private String someString = "default value";
    private int someInt= 0;
    public Options setSomeString(String someString) {
        this.someString = someString;
        return this;
    }
    public Options setSomeInt(int someInt) {
        this.someInt = someInt;
        return this;
    }
}

public static void foo(Consumer<Options> consumer) {
    Options options = new Options();
    consumer.accept(options);
    System.out.println("someString = " + options.someString + ", someInt = " + options.someInt);
}

Usa come

foo(o -> o.setSomeString("something").setSomeInt(5));

L'output è

someString = something, someInt = 5

Per saltare tutti i valori opzionali che dovresti chiamarlo come foo(o -> {});o se preferisci, puoi creare un secondo foo()metodo che non accetta i parametri opzionali.

Utilizzando questo approccio, è possibile specificare valori opzionali in qualsiasi ordine senza alcuna ambiguità. Puoi anche avere parametri di classi diverse a differenza di varargs. Questo approccio sarebbe ancora migliore se fosse possibile utilizzare annotazioni e generazione di codice per creare la classe Options.


1

Java ora supporta gli opzionali in 1.8, sono bloccato con la programmazione su Android, quindi sto usando null fino a quando non posso refactoring il codice per utilizzare tipi opzionali.

Object canBeNull() {
    if (blah) {
        return new Object();
    } else {
        return null;
    }
}

Object optionalObject = canBeNull();
if (optionalObject != null) {
    // new object returned
} else {
    // no new object returned
}

puoi fornire un esempio per favore?
sepehr

1

Gli argomenti predefiniti non possono essere utilizzati in Java. Dove in C #, C ++ e Python, possiamo usarli ..

In Java, dobbiamo usare 2 metodi (funzioni) anziché uno con parametri predefiniti.

Esempio:

Stash(int size); 

Stash(int size, int initQuantity);

http://parvindersingh.webs.com/apps/forums/topics/show/8856498-java-how-to-set-default-parameters-values-like-c-


28
Le versioni più recenti di C # consentono i parametri predefiniti.
Sogger

2
java ha l'opzione "..." anche per qualsiasi parametro.
Cacho Santa,

0

Questa è una vecchia domanda forse anche prima che fosse introdotto il tipo opzionale Opzionale, ma oggigiorno è possibile prendere in considerazione alcune cose: - utilizzare il metodo di overload - utilizzare il tipo Opzionale che ha il vantaggio di evitare il passaggio di NULL intorno al tipo Opzionale è stato introdotto in Java 8 prima che fosse normalmente usato da lib di terze parti come Guava di Google. L'uso facoltativo come parametri / argomenti può essere considerato un uso eccessivo poiché lo scopo principale era di usarlo come tempo di ritorno.

Rif: https://itcodehub.blogspot.com/2019/06/using-optional-type-in-java.html


0

Siamo in grado di impostare parametri opzionali sovraccaricando il metodo o utilizzando DataType ...

| * | Metodo di sovraccarico:

RetDataType NameFnc(int NamePsgVar)
{
    // |* Code Todo *|
    return RetVar;
}

RetDataType NameFnc(String NamePsgVar)
{
    // |* Code Todo *|
    return RetVar;
}

RetDataType NameFnc(int NamePsgVar1, String NamePsgVar2)
{
    // |* Code Todo *|
    return RetVar;
}

Il modo più semplice è

| * | DataType ... può essere un parametro opzionale

RetDataType NameFnc(int NamePsgVar, String... stringOpnPsgVar)
{
    if(stringOpnPsgVar.length == 0)  stringOpnPsgVar = DefaultValue; 

    // |* Code Todo *|
    return RetVar;
}


8
RetDtaTyp... sul serio? È RetDataTypetroppo difficile da scrivere?
Alexander - Ripristina Monica il

Puoi aggiungere qualche spiegazione in più a quel codice? Cosa fanno tutte queste strane variabili?
Nico Haase,

Modificato i nomi delle variabili per facilità di comprensione ...
Sujay ONU

0

Se si prevede di utilizzare un'interfaccia con più parametri , è possibile utilizzare il seguente modello strutturale e implementare o sostituire l'applicazione - un metodo basato sulle proprie esigenze .

public abstract class Invoker<T> {
    public T apply() {
        return apply(null);
    }
    public abstract T apply(Object... params);
}

0

Se si tratta di un endpoint API, un modo elegante è utilizzare le annotazioni "Spring":

@GetMapping("/api/foos")
@ResponseBody
public String getFoos(@RequestParam(required = false, defaultValue = "hello") String id) { 
    return innerFunc(id);
}

Si noti in questo caso che innerFunc richiederà la variabile e poiché non è un endpoint API, non è possibile utilizzare questa annotazione Spring per renderla facoltativa. Riferimento: https://www.baeldung.com/spring-request-param

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.