¿Java admite valores de parámetros predeterminados?


Me encontré con un 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++ puedo asignar un valor predeterminado a un parámetro. Por ejemplo:

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

¿Java soporta este tipo de sintaxis? ¿Hay alguna razón por la que esta sintaxis de dos pasos es preferible?

Author: peterh, 2009-06-15

19 answers

No, la estructura que encontró es cómo Java la maneja (es decir, con sobrecarga en lugar de parámetros predeterminados).

Para constructores, Vea la Guía Efectiva de Java: Lenguaje de Programación Consejo del ítem 1 (Considere métodos de fábrica estáticos en lugar de constructores) si la sobrecarga se está complicando. Para otros métodos, cambiar el nombre de algunos casos o usar un objeto de parámetro puede ayudar. Esto es cuando tienes suficiente complejidad que diferenciar es difícil. Un caso definido es donde hay que diferenciar utilizando el orden de los parámetros, no solo el número y el tipo.

 773
Author: Kathy Van Stone,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2013-09-13 17:12:48

No, pero puede usar el Patrón de constructor , como se describe en esta respuesta de desbordamiento de pila.

Como se describe en la respuesta vinculada, el Patrón de constructor 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 el que algunos campos pueden tener valores predeterminados o ser opcionales.

 551
Author: Eli Courtwright,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2017-05-23 12:34:53

Hay varias formas de simular los parámetros predeterminados 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 se puede omitir.

  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 el inconveniente de este enfoque es que si los parámetros opcionales son de diferentes tipos, pierde la comprobación de tipos estáticos. Además, si cada parámetro tiene un significado diferente, necesita alguna forma de distinguirlos.

  3. Nulls. 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 los argumentos, pero los predeterminados pueden ser nulo.

  4. Clase Opcional. Este enfoque es similar a nulls, pero usa la clase opcional Java 8 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 un contrato de método explícito para una persona que llama, sin embargo, uno puede encontrar dicha firma demasiado detallada.

  5. Patrón constructor. El patrón de constructor se usa para los constructores y se implementa introduciendo 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 ellos se suelen usar valores predeterminados, 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");
        } else if (parameters.containsKey("b")) { 
            //... 
        }
        //...
    }
    
    foo(ImmutableMap.<String, Object>of(
        "a", "a",
        "b", 2, 
        "d", "value")); 
    

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

 365
Author: Vitalii Fedorenko,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2018-06-14 23:10:44

Lamentablemente, no.

 198
Author: Rob H,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2009-06-15 18:05:16

Desafortunadamente, sí.

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

Podría escribirse 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 debe depender o no de cómo se siente acerca de que el compilador genere un

new Boolean[]{}

Para cada llamada.

Para múltiples parámetros predeterminados:

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

Podría escribirse 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 la sintaxis de C++, que solo permite parámetros predeterminados al final de la lista de parámetros.

Más allá de la sintaxis, hay una diferencia donde se ha ejecutado time type comprueba los parámetros predeterminados pasados y C++ type los comprueba durante la compilación.

 76
Author: ebelisle,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2013-10-03 21:37:48

No, pero puedes emularlas fácilmente. Lo que en C++ era:

public: void myFunction(int a, int b=5, string c="test") { ... }

En Java, será una función sobrecargada:

public void myFunction(int a, int b, string c) { ... }

public void myFunction(int a, int b) {
    myFunction(a, b, "test");
}

public void myFunction(int a) {
    myFunction(a, 5);
}

Anteriormente se mencionó que los parámetros predeterminados causaban casos ambiguos en la sobrecarga de funciones. Eso simplemente no es cierto, podemos ver en el caso del C++: sí, tal vez puede crear casos ambiguos, pero estos problemas se pueden manejar fácilmente. Simplemente no se desarrolló en Java, probablemente porque los creadores querían un lenguaje mucho más simple como era C++, si tenían razón, es otra pregunta. Pero la mayoría de nosotros no creemos que utiliza Java debido a su simplicidad.

 35
Author: peterh,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2017-10-18 03:39:53

Esto se puede hacer en Scala, que se ejecuta en la JVM y es compatible con programas Java. http://www.scala-lang.org /

Es decir,

class Foo(var prime: Boolean = false, val rib: String)  {}
 19
Author: lythic,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2012-04-03 13:58:02

Podría estar diciendo lo obvio aquí, pero ¿por qué no simplemente implementar el parámetro "predeterminado" usted mismo?

public class Foo() {
        public void func(String s){
                func(s, true);
        }
        public void func(String s, boolean b){
                //your code here
        }
}

Para el valor predeterminado usarías ether

Func("mi cadena");

Y si no te gustaría usar el valor predeterminado, usarías

Func("mi cadena", false);

 11
Author: IronWolf,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2013-02-18 14:05:09

No. En general Java no tiene mucho (ningún) azúcar sintáctico, ya que trataron de hacer un lenguaje simple.

 6
Author: tomjen,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2009-06-15 18:49:17

No.

Puede lograr el mismo comportamiento pasando un objeto que tiene valores predeterminados inteligentes. Pero de nuevo depende de cuál sea su caso.

 6
Author: Santosh Gokak,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2013-09-13 17:13:45

No pero la forma más sencilla de implementar este es:

public myParameterizedFunction(String param1, int param2, Boolean param3) {

    param3 = param3 == null ? false : param3;
}

public myParameterizedFunction(String param1, int param2) {

    this(param1, param2, false);
}

O en lugar del operador ternario se puede utilizar si:

public myParameterizedFunction(String param1, int param2, Boolean param3) {

    if (param3 == null) {
        param3 = false;
    }
}

public myParameterizedFunction(String param1, int param2) {

    this(param1, param2, false);
}
 6
Author: simhumileco,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2018-08-29 13:51:29

Como Scala fue mencionado, Kotlin también vale la pena mencionar. En Kotlin los parámetros de la función también pueden tener valores predeterminados e incluso pueden referirse a otros parámetros:

fun read(b: Array<Byte>, off: Int = 0, len: Int = b.size) {
    ...
}

Al igual que Scala, Kotlin se ejecuta en la JVM y se puede integrar fácilmente en proyectos Java existentes.

 4
Author: mrts,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2017-11-26 19:51:08

No es compatible, pero hay varias opciones como el uso de patrón de objeto de parámetro con un poco de sintaxis sugar:

public class Foo() {
    private static class ParameterObject {
        int param1 = 1;
        String param2 = "";
    }

    public static void main(String[] args) {
        new Foo().myMethod(new ParameterObject() {{ param1 = 10; param2 = "bar";}});
    }

    private void myMethod(ParameterObject po) {
    }
}

En este ejemplo construimos ParameterObject con valores predeterminados y los sobrescribimos en la sección de inicialización de instancias de clase { param1 = 10; param2 = "bar";}

 3
Author: hoaz,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2012-12-13 17:15:14

Prueba esta solución:

public int getScore(int score, Integer... bonus)
{
    if(bonus.length > 0)
    {
        return score + bonus[0];
    }

    return score;
}
 3
Author: Hamzeh Soboh,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2014-09-03 16:45:05

Hay media docena o mejores problemas como este, eventualmente se llega al patrón de fábrica estático ... vea la api crypto para eso. Ordenar difícil de explicar, pero piénsalo de esta manera: Si tiene un constructor, por defecto o de otra manera, la única manera de propagar el estado más allá de las llaves es tener un isValid booleano; (junto con el null como valor por defecto v constructor fallido ) o lanzar una excepción que nunca es informativa al recuperarlo del campo usuario.

Code Correct maldita sea, escribo miles de constructores de líneas y hago lo que necesito. Encuentro el uso de isValid en la construcción de objetos, en otras palabras, dos constructores de líneas, pero por alguna razón estoy migrando al patrón de fábrica estático. Solo parece que puedes hacer mucho si en una llamada a un método, todavía hay problemas de sync (), pero los valores predeterminados se pueden 'sustituir' mejor ( más seguro)

Creo que lo que tenemos que hacer aquí es abordar el problema de null como valor predeterminado vis-a-vis algo String one = new String(""); como variable miembro, entonces haciendo una comprobación de null antes de asignar string pasado al constructor.

Muy notable la cantidad de ciencia de la computación estratosférica cruda hecha en Java.

C++ y así sucesivamente tiene libs de proveedores, sí. Java puede superarlos en servidores a gran escala debido a su caja de herramientas masiva. Estudia los bloques del inicializador estático, quédate con nosotros.

 1
Author: Nicholas Jordan,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2009-09-28 02:33:40

Así es como lo hice ... no es tan conveniente tal vez como tener un 'argumento opcional' contra su parámetro definido, pero hace el trabajo:

public void postUserMessage(String s,boolean wipeClean)
{
    if(wipeClean)
    {
        userInformation.setText(s + "\n");
    }
    else
    {
        postUserMessage(s);
    }
}

public void postUserMessage(String s)
{
    userInformation.appendText(s + "\n");
}

Observe que puedo invocar el mismo nombre del método con solo una cadena o puedo invocarlo con una cadena y un valor booleano. En este caso, establecer wipeClean a true reemplazará todo el texto en mi área de texto con la cadena proporcionada. Establecer wipeClean a false o dejarlo todo junto simplemente agrega el texto proporcionado a el TextArea.

También observe que no estoy repitiendo código en los dos métodos, simplemente estoy agregando la funcionalidad de poder restablecer el área de texto creando un nuevo método con el mismo nombre solo con el booleano agregado.

Realmente creo que esto es un poco más limpio que si Java proporcionara un 'argumento opcional' para nuestros parámetros, ya que necesitaríamos codificar los valores predeterminados, etc. En este ejemplo, no necesito preocuparme por nada de eso. Sí, he añadido otro método para mi clase, pero es más fácil de leer a largo plazo en mi humilde opinión.

 1
Author: Michael Sims,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2015-01-18 15:40:19

Un enfoque similar a https://stackoverflow.com/a/13864910/2323964 lo que funciona en Java 8 es usar una interfaz con getters predeterminados. Esto será más detallado en espacios en blanco, pero es burlable, y es ideal para cuando tienes un montón de casos en los que realmente quieres llamar la atención sobre los parámetros.

public class Foo() {
    public interface Parameters {
        String getRequired();
        default int getOptionalInt(){ return 23; }
        default String getOptionalString(){ return "Skidoo"; }
    }

    public Foo(Parameters parameters){
        //...
    }

    public static void baz() {
        final Foo foo = new Foo(new Person() {
            @Override public String getRequired(){ return "blahblahblah"; }
            @Override public int getOptionalInt(){ return 43; }
        });
    }
}
 1
Author: Novaterata,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2017-05-23 11:47:32

Puede usar Java Method Invocation Builder para generar automáticamente el constructor con valores predeterminados.

Simplemente agregue @GenerateMethodInvocationBuilder a la clase, o interfaz, y el @Default a los parámetros en los métodos donde desea valores predeterminados. Se generará un constructor en tiempo de compilación, utilizando los valores predeterminados que especificó con sus anotaciones.

@GenerateMethodInvocationBuilder
public class CarService {
 public CarService() {
 }

 public String getCarsByFilter(//
   @Default("Color.BLUE") Color color, //
   @Default("new ProductionYear(2001)") ProductionYear productionYear,//
   @Default("Tomas") String owner//
 ) {
  return "Filtering... " + color + productionYear + owner;
 }
}

Y luego puede invocar los métodos.

CarService instance = new CarService();
String carsByFilter = CarServiceGetCarsByFilterBuilder.getCarsByFilter()//
  .invoke(instance);

O establecer cualquiera de los valores predeterminados a algo más.

CarService instance = new CarService();
String carsByFilter = CarServiceGetCarsByFilterBuilder.getCarsByFilter()//
  .withColor(Color.YELLOW)//
  .invoke(instance);
 0
Author: Tomas Bjerre,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2016-06-13 17:42:50

NO, Pero tenemos alternativa en forma de sobrecarga de funciones.

Se llama cuando no se pasa ningún parámetro

void operation(){

int a = 0;
int b = 0;

} 

Llamado cuando se pasó el parámetro" a "

void operation(int a){

int b = 0;
//code

} 

Se llama cuando se pasa el parámetro b

void operation(int a , int b){
//code
} 
 0
Author: Umair Khalid,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2016-09-01 06:51:15