754 votos

¿Soporte de Java valores de parámetro predeterminados?

Me encontré con algunos de código Java que tenía la siguiente estructura:

public MyParameterizedFunction(String param1, int param2)
{
    this(param1, param2, false);
}

public MyParameterizedFunction(String param1, int param2, boolean param3)
{
    //use all three parameters here
}

Sé que en C++ se puede asignar un parámetro a un valor predeterminado. Por ejemplo:

void MyParameterizedFunction(String param1, int param2, bool param3=false);

¿Soporte de Java este tipo de sintaxis? Hay alguna razones por las que este paso dos sintaxis es preferible?

428voto

Kathy Van Stone Puntos 10310

No, la estructura que has encontrado es cómo Java maneja (esto es, con una sobrecarga en lugar de los parámetros por defecto).

Para los constructores, Ver Eficaz Java: Lenguaje de Programación de la Guía en el Punto 1 de la punta (Considerar métodos de fábrica estáticos en lugar de los constructores) si la sobrecarga es complicado llegar. Para otros métodos, el cambio de nombre de algunos casos o mediante un parámetro de objeto puede ayudar. Esto es cuando usted tiene suficiente complejidad que la diferenciación es difícil. Un caso concreto es donde se tienen que diferenciar el uso de la orden de los parámetros, no sólo el número y el tipo.

354voto

Eli Courtwright Puntos 53071

No, pero puedes utilizar el Generador de Patrón, como se describe en este Stack Overflow respuesta.

Como se describe en los enlaces de respuesta, el Generador de Patrón le permite escribir código como

Student s1 = new StudentBuilder().name("Eli").buildStudent();
Student s2 = new StudentBuilder()
                 .name("Spicoli")
                 .age(16)
                 .motto("Aloha, Mr Hand")
                 .buildStudent();

en la que algunos campos pueden tener valores predeterminados o ser de otra manera opcional.

149voto

Vitalii Fedorenko Puntos 17469

Hay varias formas para simular los parámetros por defecto en Java:

  1. La sobrecarga de métodos.

    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 usted tiene dos parámetros opcionales del mismo tipo y cualquiera de ellos puede ser omitido.

  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) Tipos de parámetros opcionales que 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 que pierden la comprobación de tipo estático. Además, si cada parámetro tiene un significado diferente que usted necesita una cierta manera de distinguirlos.

  3. Valores nulos. Para hacer frente a las limitaciones de los planteamientos anteriores se puede permitir valores nulo y, a continuación, analizar cada parámetro de un método de cuerpo:

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

    Ahora todos los argumentos valores deben ser suministrados, pero el defecto puede ser null.

  4. Clase opcional. Este enfoque es similar a los nulos, pero utiliza la guayaba clase Opcional de parámetros que tienen un valor por defecto:

    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 método de contrato explícito para una persona que llama, sin embargo, uno puede encontrar a dicha firma demasiado detallado.

  5. Generador de patrón. El generador de patrón se utiliza para los constructores y que es implementado por la introducción de un independiente Constructor de la clase:

     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 ellos los valores predeterminados se utilizan generalmente, usted 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 = (String)parameters.get("a");
        }
        if (parameters.containsKey("b")) { 
            //... 
        }
        //...
    }
    
    foo(ImmutableMap.<String, Object>of(
        "a", "a",
        "b", 2, 
        "d", "value")); 
    

Por favor, tenga en cuenta que usted puede combinar cualquiera de estos enfoques para lograr un resultado deseable.

128voto

Rob H Puntos 5599

Lamentablemente, no.

68voto

ebelisle Puntos 639

Por desgracia, sí.

void MyParameterizedFunction(String param1, int param2, bool param3=false) {}

podría ser escrito en Java 1.5 como:

void MyParameterizedFunction(String param1, int param2, Boolean... params) {
    assert params.length <= 1;
    bool param3 = params.length > 0 ? params[0].booleanValue() : false;
}

Pero si usted debe o no dependerá de cómo se sienten acerca del compilador generar un

new Boolean[]{}

para cada llamada.

Para varios defaultable parámetros:

void MyParameterizedFunction(String param1, int param2, bool param3=false, int param4=42) {}

podría ser escrito en Java 1.5 como:

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

Esto coincide con sintaxis de C++, que sólo permite la mora de los parámetros al final de la lista de parámetros.

Más allá de la sintaxis, hay una diferencia donde esta tiene tiempo de ejecución el tipo de comprobación de pasado defaultable parámetros y C++ tipo de comprobaciones de ellos durante la compilación.

Iteramos.com

Iteramos es una comunidad de desarrolladores que busca expandir el conocimiento de la programación mas allá del inglés.
Tenemos una gran cantidad de contenido, y también puedes hacer tus propias preguntas o resolver las de los demás.

Powered by:

X