Parámetros opcionales de Java


Respuestas:


517

varargs podría hacer eso (de alguna manera). Aparte de eso, se deben proporcionar todas las variables en la declaración del método. Si desea que una variable sea opcional, puede sobrecargar el método utilizando una firma que no requiera el parámetro.

private boolean defaultOptionalFlagValue = true;

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

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

La sobrecarga de métodos es una buena respuesta en mi opinión, mientras que varargs es una muy mala respuesta. Elimine el comentario en varargs o explique la seria desventaja causada por la posibilidad de más de un valor de retorno.
Andreas Vogl

Agregar variables globales puede causar otros problemas.
Helen Cui

1654

Hay varias formas de simular parámetros opcionales en Java:

  1. Método de sobrecarga.

    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 de las limitaciones de este enfoque es que no funciona si tiene dos parámetros opcionales del mismo tipo y cualquiera de ellos puede omitirse.

  2. Varargs

    a) Todos los parámetros opcionales son del mismo 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) Los tipos de parámetros opcionales pueden 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");

    El principal inconveniente de este enfoque es que si los parámetros opcionales son de diferentes tipos, pierde la comprobación de tipo estático. Además, si cada parámetro tiene un significado diferente, necesita alguna forma de distinguirlos.

  3. Nulos Para abordar las limitaciones de los enfoques anteriores, puede permitir valores nulos y luego analizar cada parámetro en un cuerpo 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);

    Ahora se deben proporcionar todos los valores de argumentos, pero los valores predeterminados pueden ser nulos.

  4. Clase opcional Este enfoque es similar a los nulos, pero usa la clase Java 8 Opcional para parámetros que tienen un valor predeterminado:

    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 hace que un contrato de método sea explícito para una persona que llama, sin embargo, uno puede encontrar esa firma demasiado detallada.

    Actualización: Java 8 incluye la clase lista java.util.Optionalpara usar, por lo que no es necesario usar guayaba por esta razón particular en Java 8. Sin embargo, el nombre del método es un poco diferente.

  5. Patrón de constructor. El patrón de constructor se utiliza para constructores y se implementa mediante la introducción de una clase de constructor 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. Mapas Cuando el número de parámetros es demasiado grande y para la mayoría de los valores predeterminados generalmente se usan, puede pasar argumentos de método como un mapa de sus nombres / 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")); 

    En Java 9, este enfoque se hizo más 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"));

Tenga en cuenta que puede combinar cualquiera de estos enfoques para lograr un resultado deseable.


2
@Vitalii Fedorenko Hmm, creo que cometiste un ligero error de copiar y pegar en el n. ° 6: estás verificando el tipo de un entero aunque tu avariable es una cadena (el reparto es correcto).
Identificación desconocida

55
@Aetos tu enlace está muerto.
Robino

2
@Robino enlace alternativo argumentando que Opcional no debe usarse como parámetro aquí . A pesar del uso de Optionalcomo parámetro en una de las opciones, esta respuesta es muy buena.
Dherik

La solución más común al problema anterior es probablemente la sobrecarga de métodos. Aunque nunca fui realmente fanático de eso. Personalmente, preferiría que agregaran algún tipo de identificador para los parámetros de configuración.
Alexander Heim

1
esta debería ser probablemente la mejor respuesta - cubre todo
xproph

104

Hay parámetros opcionales con Java 5.0. Simplemente declara tu función así:

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

puedes llamar con doSomething();o doSomething(true);ahora.


13
Esta es realmente la respuesta correcta. Es simple y compacto. Solo recuerde que puede obtener más de un parámetro para que Java los coloque dentro de una matriz. Por ejemplo, para recuperar un solo parámetro, primero debe verificar el contenido de la matriz: 'código' boolean flag = (optionalFlag.length <1)? False: optionalFlag [0];
Salvador Valencia

46
No, no es la respuesta correcta, porque esto no permite un solo parámetro opcional, sino cualquier número de parámetros opcionales. Si bien esto está cerca de lo que OP quiere, no es lo mismo. Es una fuente potencial de errores y malentendidos aceptar más parámetros de los que necesita.
sleske

2
De esta manera funciona si solo tiene un parámetro opcional, pero necesitaría verificar la longitud de la matriz, etc. para que no esté súper limpio: | Si desea un parámetro opcional de "un parámetro", entonces también puede declarar dos métodos (uno sobrecargado doSomething() { doSomething(true); }sin matrices para tratar, sin ambigüedad)
rogerdpack

Si hay varios parámetros opcionales, esto solo funciona si todos son del mismo tipo de datos. Bueno, podrías hacer el tipo Objeto, pero eso se está poniendo realmente feo.
Jay

Como señaló @sleske, el uso de varargs tiene la terrible desventaja de permitir que se pase más de un valor. OP preguntó claramente sobre una solución para "opcional", que significa un valor o cero. Cómo esto puede considerarse una buena respuesta por parte de algunos es algo que no me importa.
Andreas Vogl

99

Puedes usar algo como esto:

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

La paramsvariable es opcional. Se trata como una matriz de objetos anulables.

Curiosamente, no pude encontrar nada sobre esto en la documentación, ¡pero funciona!

Esto es "nuevo" en Java 1.5 y posteriores (no compatible con Java 1.4 o anterior).

Veo que el usuario bhoot menciona esto también a continuación.


55

Desafortunadamente, Java no admite parámetros predeterminados directamente.

Sin embargo, he escrito un conjunto de anotaciones JavaBean, y una de ellas admite parámetros predeterminados como los siguientes:

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

El procesador de anotaciones genera las sobrecargas del método para soportar esto correctamente.

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

Ejemplo completo en http://code.google.com/p/javadude/wiki/AnnotationsDefaultParametersExample


53

No hay parámetros opcionales en Java. Lo que puede hacer es sobrecargar las funciones y luego pasar los valores predeterminados.

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

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

23

VarArgs y sobrecarga se han mencionado. Otra opción es un patrón Builder, que se vería así:

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

Aunque ese patrón sería más apropiado para cuando necesita parámetros opcionales en un constructor.


Quiero agregar dependencia de parámetros para eso. Digamos que quiero establecer param3 solo si configuro param1. Por ej. Quiero configurar el mensaje de progreso solo si configuro el progreso visible. isProgressVisible (). setProgressMessage ("cargando"). ¿Cómo puedo lograr eso?
Harshal Bhatt

14

En JDK> 1.5 puedes usarlo así;

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

Puede hacer cosas usando la sobrecarga de métodos de esta manera.

 public void load(String name){ }

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

También puedes usar la anotación @Nullable

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

simplemente pase nulo como primer parámetro.

Si está pasando la misma variable de tipo, puede usar esto

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

7

Version corta :

Usando tres puntos :

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

(basado en la respuesta de @ VitaliiFedorenko)


2

La sobrecarga está bien, pero si hay muchas variables que necesitan un valor predeterminado, terminarás 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) {  }

Por lo tanto, sugeriría utilizar el argumento variable proporcionado por Java. Aquí hay un enlace para la explicación.


El uso de varargs se considera una mala práctica. Si el sistema necesita tales métodos (mencionados anteriormente), entonces debe pensar en un nuevo diseño ya que el diseño de la clase se ve mal.
Diablo

2
Es una práctica aún peor inventar excusas para las deficiencias de Java, y acusar a otros de mala práctica por notar esos inconvenientes e idear soluciones.
BrianO

1
Agregue toda la información relevante a su respuesta en lugar de vincular a fuentes externas: el enlace dado está inactivo
Nico Haase,

2

Puede usar una clase que funcione de manera muy similar a un generador para contener sus valores opcionales 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);
}

Usar como

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

La salida es

someString = something, someInt = 5

Para omitir todos los valores opcionales, debería llamarlo así foo(o -> {});o, si lo prefiere, puede crear un segundo foo()método que no tome los parámetros opcionales.

Con este enfoque, puede especificar valores opcionales en cualquier orden sin ninguna ambigüedad. También puede tener parámetros de diferentes clases a diferencia de varargs. Este enfoque sería aún mejor si puede usar anotaciones y generación de código para crear la clase Opciones.


1

Java ahora admite opciones en 1.8, estoy atascado con la programación en Android, así que estoy usando nulos hasta que pueda refactorizar el código para usar tipos opcionales.

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

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

¿Puedes dar un ejemplo por favor?
Sepehr

1

Los argumentos predeterminados no se pueden usar en Java. Donde en C #, C ++ y Python, podemos usarlos.

En Java, debemos usar 2 métodos (funciones) en lugar de uno con parámetros predeterminados.

Ejemplo:

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
Las versiones más recientes de C # permiten parámetros predeterminados.
Sogger

2
Java tiene la opción "..." para cualquier parámetro también.
Cacho Santa

0

Esta es una pregunta antigua tal vez incluso antes de que se introdujera el tipo opcional real, pero en estos días puede considerar algunas cosas: - use la sobrecarga del método - use el tipo opcional que tiene la ventaja de evitar pasar NULLs alrededor del tipo opcional se introdujo en Java 8 antes de que generalmente se usara de librerías de terceros, como la guayaba de Google. El uso de opcional como parámetros / argumentos puede considerarse un uso excesivo ya que el propósito principal era usarlo como un tiempo de retorno.

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


0

Podemos hacer parámetros opcionales por sobrecarga de métodos o usando DataType ...

| * | Método de sobrecarga:

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

La forma más fácil es

| * | DataType ... puede ser un parámetro opcional

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

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


8
RetDtaTyp... ¿seriamente? ¿Es RetDataTypedemasiado difícil de escribir?
Alexander - Restablece a Monica el

¿Puedes agregar alguna explicación más a ese código? ¿Qué hacen todas estas variables extrañas?
Nico Haase

Cambió los nombres de las variables para facilitar su comprensión ...
Sujay UN

0

Si planea usar una interfaz con múltiples parámetros , uno puede usar el siguiente patrón estructural e implementar o anular la aplicación, un método basado en sus requisitos .

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

0

Si se trata de un punto final de API, una forma elegante es usar anotaciones "Spring":

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

Observe en este caso que innerFunc requerirá la variable y, dado que no es un punto final de API, no puede usar esta anotación Spring para hacerlo opcional. Referencia: https://www.baeldung.com/spring-request-param

Al usar nuestro sitio, usted reconoce que ha leído y comprende nuestra Política de Cookies y Política de Privacidad.
Licensed under cc by-sa 3.0 with attribution required.