¿Cómo uso parámetros opcionales en Java?

Resuelto Mike Pone asked hace 15 años • 17 respuestas

¿Qué especificación admite parámetros opcionales?

Mike Pone avatar Jun 08 '09 23:06 Mike Pone
Aceptado

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

  1. Sobrecarga de métodos.

    void foo(Cadena a, Entero b) { //... }

    void foo(Cadena a) { foo(a, 0); // aquí, 0 es el valor predeterminado para 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.

  1. 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, se pierde la verificación de tipos estáticos. Además, si cada parámetro tiene un significado diferente, necesita alguna forma de distinguirlos.

  1. Nulos. Para abordar las limitaciones de los enfoques anteriores, puede permitir valores nulos y luego analizar cada parámetro en el cuerpo de un método:

    void foo(Cadena a, Entero b, Entero c) { b = b != nulo? b: 0; c = c != nulo ? c: 0; //... }

    foo("a", nulo, 2);

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

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

    void foo(String a, Opcional bOpt) { Entero b = bOpt.isPresent() ? bOpt.get() : 0; //... }

    foo("a", Opcional.de(2)); foo("a", Opcional.ausente());

    Opcional hace que un contrato de método sea explícito para una persona que llama; sin embargo, uno puede encontrar que dicha firma es demasiado detallada.

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

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

    void foo(Map<String, Object> parámetros) { String a = ""; Entero b = 0; if (parameters.containsKey("a")) { if (!(parameters.get("a") instancia de Integer)) { throw new IllegalArgumentException("..."); } a = (Entero)parámetros.get("a"); } if (parameters.containsKey("b")) { //... } //... }

    foo(ImmutableMap.<String, Object>of( "a", "a", "b", 2, "d", "value"));

    En Java 9, este enfoque se volvió más sencillo:

    @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.

Vitalii Fedorenko avatar Oct 21 '2012 01:10 Vitalii Fedorenko

varargs podría hacer eso (en cierto modo). 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 usando una firma que no requiera el parámetro.

private boolean defaultOptionalFlagValue = true;

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

public void doSomething() {
    doSomething(defaultOptionalFlagValue);
}
laginimaineb avatar Jun 08 '2009 16:06 laginimaineb

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

Podrías llamar con doSomething();o doSomething(true);ahora.

bhoot avatar Apr 02 '2010 12:04 bhoot

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 que acepta valores NULL.

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

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

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

theninjagreg avatar Dec 03 '2010 21:12 theninjagreg