Parâmetros Opcionais Java

813

Como uso parâmetros opcionais em Java? Que especificação suporta parâmetros opcionais?

Mike Pone
fonte

Respostas:

517

varargs poderia fazer isso (de certa forma). Fora isso, todas as variáveis ​​na declaração do método devem ser fornecidas. Se você deseja que uma variável seja opcional, você pode sobrecarregar o método usando uma assinatura que não exija o parâmetro

private boolean defaultOptionalFlagValue = true;

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

public void doSomething() {
    doSomething(defaultOptionalFlagValue);
}
laginimaineb
fonte
Sobrecarga de método é uma boa resposta na minha opinião, enquanto varargs é uma resposta muito ruim. Remova o comentário sobre varargs ou explique a séria desvantagem causada pela possibilidade de mais de um valor de retorno.
Andreas Vogl
Adicionar variáveis ​​globais pode causar outros problemas.
Helen Cui
1652

Existem várias maneiras de simular parâmetros opcionais em Java:

  1. Sobrecarga de método.

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

    Uma das limitações dessa abordagem é que ela não funcionará se você tiver dois parâmetros opcionais do mesmo tipo e qualquer um deles puder ser omitido.

  2. Varargs.

    a) Todos os parâmetros opcionais são do mesmo 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) Os tipos de parâmetros opcionais podem ser diferentes:

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

    A principal desvantagem dessa abordagem é que, se os parâmetros opcionais forem de tipos diferentes, você perderá a verificação de tipo estático. Além disso, se cada parâmetro tiver um significado diferente, você precisará de alguma maneira de distingui-lo.

  3. Nulos. Para abordar as limitações das abordagens anteriores, você pode permitir valores nulos e analisar cada parâmetro em um corpo de método:

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

    Agora todos os valores dos argumentos devem ser fornecidos, mas os padrão podem ser nulos.

  4. Classe opcional. Essa abordagem é semelhante a nulos, mas usa a classe Java 8 Optional para parâmetros que possuem um valor padrão:

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

    Opcional torna um contrato de método explícito para um chamador, no entanto, pode-se achar essa assinatura muito detalhada.

    Atualização: o Java 8 inclui a classe java.util.Optionalpronta para uso, portanto, não há necessidade de usar a goiaba por esse motivo específico no Java 8. O nome do método é um pouco diferente.

  5. Padrão do construtor. O padrão do construtor é usado para construtores e é implementado através da introdução de uma classe Builder separada:

     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. Maps. Quando o número de parâmetros é muito grande e para a maioria dos valores padrão geralmente são usados, você pode passar argumentos de método como um mapa de seus nomes / valores:

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

    No Java 9, essa abordagem ficou mais fácil:

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

Observe que você pode combinar qualquer uma dessas abordagens para obter um resultado desejável.

Vitalii Fedorenko
fonte
2
@Vitalii Fedorenko Hmm, acho que você cometeu um pequeno erro de copiar e colar no # 6: Você está verificando um tipo de número inteiro, embora sua avariável seja uma String (a conversão está correta).
Identificação desconhecida
5
@ Aetos seu link está morto.
Robino 30/10
2
Link alternativo do @Robino argumentando que o opcional não deve ser usado como parâmetro aqui . Apesar do uso de Optionalcomo parâmetro em uma das opções, esta resposta é muito boa.
Dherik
A solução mais comum para o problema acima é provavelmente a sobrecarga de método. Embora eu nunca tenha sido realmente fã disso. Pessoalmente, eu preferiria se eles adicionassem algum tipo de identificador para parâmetros de configuração.
Alexander Heim
1
esta deve ser provavelmente a melhor resposta - cobre todos
xproph
104

Existem parâmetros opcionais com o Java 5.0. Apenas declare sua função assim:

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

você poderia ligar com doSomething();ou doSomething(true);agora.

bhoot
fonte
13
Esta é realmente a resposta correta. É simples e compacto. Lembre-se de que você pode obter mais de um parâmetro para que o Java os coloque dentro de uma matriz. Por exemplo, para recuperar um único parâmetro, você deve verificar primeiro o conteúdo da matriz: flag 'booleano' code = (optionalFlag.length <1)? False: optionalFlag [0];
Salvador Valencia
46
Não, não é a resposta correta, porque isso não permite um único parâmetro opcional, mas qualquer número de parâmetros opcionais. Embora isso esteja próximo do que o OP deseja, não é o mesmo. É uma fonte potencial de erros e mal-entendidos para aceitar mais parâmetros do que você precisa.
Sleske 28/05
2
Dessa forma, funciona se você tiver apenas um parâmetro opcional, mas precisaria verificar o comprimento da matriz, etc., para que não fique super limpo: | Se você quiser "um parâmetro" parâmetro opcional, então você pode também apenas declarar dois métodos (um sobrecarregada doSomething() { doSomething(true); }há matrizes para lidar com, nenhuma ambigüidade
rogerdpack
Se houver vários parâmetros opcionais, isso funcionará apenas se forem todos do mesmo tipo de dados. Bem, você pode criar o tipo Object, mas isso está ficando muito feio.
21419 Jay
Como o @sleske observou, o uso de varargs tem a terrível desvantagem de permitir que mais de um valor seja passado. O OP perguntou claramente sobre uma solução para "opcional", o que significa um valor ou zero. Como isso pode ser considerado uma boa resposta por alguns é por mim.
Andreas Vogl
99

Você pode usar algo como isto:

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

A paramsvariável é opcional. É tratado como uma matriz anulável de objetos.

Estranhamente, não consegui encontrar nada sobre isso na documentação, mas funciona!

Isso é "novo" no Java 1.5 e posterior (não suportado no Java 1.4 ou anterior).

Vejo que o usuário bhoot mencionou isso também abaixo.

theninjagreg
fonte
55

Infelizmente, o Java não suporta parâmetros padrão diretamente.

No entanto, escrevi um conjunto de anotações JavaBean e uma delas suporta parâmetros padrão como o seguinte:

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

O processador de anotação gera sobrecargas no método para dar suporte adequado a isso.

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

Exemplo completo em http://code.google.com/p/javadude/wiki/AnnotationsDefaultParametersExample

Scott Stanchfield
fonte
53

Não há parâmetros opcionais em Java. O que você pode fazer é sobrecarregar as funções e passar valores padrão.

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

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

VarArgs e sobrecarga foram mencionados. Outra opção é um padrão Builder, que seria algo como isto:

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

Embora esse padrão seja mais apropriado para quando você precisar de parâmetros opcionais em um construtor.

Yishai
fonte
Eu quero adicionar dependência de parâmetro para que. Vamos dizer que eu quero definir param3 apenas se eu definir param1. Por exemplo. Eu quero definir a mensagem de progresso apenas se eu definir o progresso visível. isProgressVisible (). setProgressMessage ("loading"). como posso conseguir isso?
Harshal Bhatt
14

No JDK> 1.5, você pode usá-lo assim;

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

Você pode fazer algo usando a sobrecarga de método como esta.

 public void load(String name){ }

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

Além disso, você pode usar a anotação @Nullable

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

simplesmente passe nulo como primeiro parâmetro.

Se você está passando a mesma variável de tipo, pode usar este

public void load(String name...){}
Ishan Fernando
fonte
7

Versão curta :

Usando três pontos :

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

(com base na resposta de @ VitaliiFedorenko)

T.Todua
fonte
2

Sobrecarregar é bom, mas se houver muitas variáveis ​​que precisam de valor padrão, você terá:

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

Então, eu sugiro usar o argumento variável fornecido pelo Java. Aqui está um link para explicação.

Jigar Shah
fonte
o uso de varargs é considerado uma má prática. se o sistema precisar desses métodos (mencionados acima), pense em um novo design, pois o design da classe parece ruim.
Diablo
2
É uma prática ainda pior inventar desculpas pelas deficiências do Java e acusar outras pessoas de práticas inadequadas por perceberem esses inconvenientes e criar soluções alternativas.
Briano
1
Por favor, adicione todas as informações relevantes para a sua resposta em vez de ligar a fontes externas - o link fornecido está morto
Nico Haase
2

Você pode usar uma classe que funciona como um construtor para conter seus valores opcionais como este.

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

Use como

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

Saída é

someString = something, someInt = 5

Para pular todos os valores opcionais que você teria que chamar assim foo(o -> {});ou, se preferir, você pode criar um segundo foo()método que não aceita os parâmetros opcionais.

Usando essa abordagem, você pode especificar valores opcionais em qualquer ordem sem ambiguidade. Você também pode ter parâmetros de diferentes classes, diferentemente dos varargs. Essa abordagem seria ainda melhor se você pudesse usar anotações e geração de código para criar a classe Options.

Rybai
fonte
1

O Java agora suporta opcionais no 1.8. Estou preso à programação no Android, então estou usando nulos até que eu possa refatorar o código para usar tipos opcionais.

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

Object optionalObject = canBeNull();
if (optionalObject != null) {
    // new object returned
} else {
    // no new object returned
}
Pellet
fonte
você pode dar um exemplo, por favor?
sepehr
1

Argumentos padrão não podem ser usados ​​em Java. Onde em C #, C ++ e Python, podemos usá-los.

Em Java, precisamos usar 2 métodos (funções) em vez de um com parâmetros padrão.

Exemplo:

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-

Parvinder Singh
fonte
28
Versões mais recentes do C # permitem parâmetros padrão.
Sogger
2
java também tem a opção "..." para qualquer parâmetro.
Cacho Santa
0

Essa é uma pergunta antiga, talvez antes mesmo da introdução do tipo opcional real, mas hoje em dia você pode considerar algumas coisas: - sobrecarregar o método - usar o tipo opcional que tem a vantagem de evitar passar NULLs ao redor do tipo opcional que foi introduzido no Java 8 antes de ser normalmente usado de lib de terceiros, como o Guava do Google. O uso opcional de parâmetros / argumentos pode ser considerado um uso excessivo, pois o objetivo principal era usá-lo como um tempo de retorno.

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

xproph
fonte
0

Podemos tornar o parâmetro opcional por Sobrecarga de método ou Usando DataType ...

| * | Sobrecarga de método:

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

A maneira mais fácil é

| * | DataType ... pode ser parâmetro opcional

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

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

Sujay UN
fonte
8
RetDtaTyp... a sério? É RetDataTypemuito difícil digitar?
Alexander - Restabelecer Monica
Você pode adicionar mais explicações para esse código? O que todas essas variáveis ​​estranhas fazem?
Nico Haase
Mudou os nomes das variáveis para facilitar a compreensão ...
Sujay da ONU
0

Se você planeja usar uma interface com vários parâmetros , pode-se usar o seguinte padrão estrutural e implementar ou substituir aplicar - um método baseado em seus requisitos .

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

Se for um ponto de extremidade da API, uma maneira elegante é usar as anotações "Spring":

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

Observe, nesse caso, que o innerFunc exigirá a variável e, como não é um ponto de extremidade da API, não pode usar esta anotação do Spring para torná-la opcional. Referência: https://www.baeldung.com/spring-request-param

Sophie Cooperman
fonte