¿Admite Java los valores de parámetro predeterminados?

Encontré 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 parámetro a un valor predeterminado. Por ejemplo:

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

¿Admite Java este tipo de syntax? ¿Hay alguna razón por la cual esta syntax de dos pasos es preferible?

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

Para constructores, consulte la sugerencia de Artículo 1 de Java Effective Java: Programming Language Guide (Considere los métodos de fábrica estáticos en lugar de los constructores) si la sobrecarga se está complicando. Para otros métodos, puede cambiar el nombre de algunos casos o usar un objeto de parámetro. Esto es cuando tienes suficiente complejidad que la diferenciación es difícil. Un caso definido es cuando debe diferenciar usando el orden de los parámetros, no solo el número y tipo.

No, pero puede usar el patrón de construcción , como se describe en esta respuesta de desbordamiento de stack .

Tal como se describe en la respuesta vinculada, el patrón del generador le permite escribir códigos 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 de lo contrario ser opcionales.

Hay varias formas de simular 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 inconveniente de este enfoque es que si los parámetros opcionales son de tipos diferentes, se pierde la comprobación del 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 los argumentos, pero los predeterminados pueden ser nulos.

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

     void foo(String a, Optional bOpt) { Integer b = bOpt.isPresent() ? bOpt.get() : 0; //... } foo("a", Optional.of(2)); foo("a", Optional.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.

  5. Patrón de constructor El patrón de constructor se usa para constructores y se implementa mediante la introducción de una clase de generador por separado:

      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 usan generalmente los valores predeterminados, puede pasar los argumentos del método como un mapa de sus nombres / valores:

     void foo(Map 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.of( "a", "a", "b", 2, "d", "value")); 

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

Tristemente no.

Por desgracia 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 debes depender de cómo te sientes acerca del comstackdor generando un

 new Boolean[]{} 

para cada llamada.

Para múltiples parámetros eliminables:

 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 syntax de C ++, que solo permite los parámetros predeterminados al final de la lista de parámetros.

Más allá de la syntax, existe una diferencia cuando esto ha ejecutado el tipo de verificación de tiempo para los parámetros pasibles de errores y el tipo de C ++ los verifica durante la comstackción.

No, pero puedes emularlos fácilmente. Lo que en C ++ fue:

 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 de 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 que C ++, si tenían razón, es otra cuestión. Pero la mayoría de nosotros no cree que use Java por su simplicidad.

Puede hacer esto en Scala, que se ejecuta en JVM y es compatible con los progtwigs de Java. http://www.scala-lang.org/

es decir

 class Foo(var prime: Boolean = false, val rib: String) {} 

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

por defecto, usarías el éter

func (“mi cadena”);

y si no desea utilizar el valor predeterminado, usaría

func (“mi cadena”, falso);

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

No.

Puede lograr el mismo comportamiento pasando un Objeto que tiene valores predeterminados inteligentes. Pero de nuevo depende de lo que su caso tiene a mano.

Como se mencionó a Scala, también vale la pena mencionar a Kotlin . 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, 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.

No , pero la forma más sencilla de implementar esto 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, puede usar si:

 public myParameterizedFunction(String param1, int param2, Boolean param3) { if (param3 == null) { param3 = false; } } public myParameterizedFunction(String param1, int param2) { this(param1, param2, false); } 

No es compatible, pero hay varias opciones, como utilizar el patrón de objeto de parámetro con un poco de azúcar de syntax:

 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 esta muestra, construimos ParameterObject con valores predeterminados y los { param1 = 10; param2 = "bar";} sección de inicialización de la instancia de clase { param1 = 10; param2 = "bar";} { param1 = 10; param2 = "bar";}

Prueba esta solución:

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

Hay media docena o más problemas como este, eventualmente llegas al patrón de fábrica estático … mira la API astackda para eso. Clasificar es difícil de explicar, pero piénselo de esta manera: si tiene un constructor, predeterminado o de otro modo, la única forma de propagar el estado más allá de las llaves es tener un Boolean isValid; (junto con el valor nulo como valor predeterminado v constructor fallido) o lanzar una excepción que nunca es informativa cuando la obtienen de los usuarios del campo.

Code Correct maldito, escribo miles de constructores de líneas y hago lo que necesito. Me parece usar 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. Me parece que puedes hacer mucho si en una llamada a método, todavía hay problemas de sincronización () pero los valores predeterminados pueden ser ‘sustituidos’ mejor (más seguros)

Creo que lo que tenemos que hacer aquí es abordar el problema de nulo como valor predeterminado frente a algo String one = new String (“”); como una variable miembro, luego haciendo una comprobación de nulo antes de asignar la cadena pasada al constructor.

Muy notable es la cantidad de informática en bruto y estratosférica realizada en Java.

C ++ y así sucesivamente tiene librerías de vendedores, sí. Java puede superarlos en servidores a gran escala debido a su enorme caja de herramientas. Estudie los bloques de inicializadores estáticos, quédese con nosotros.

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

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

También observe que no estoy repitiendo el 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.

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

Un enfoque similar a https://stackoverflow.com/a/13864910/2323964 que funciona en Java 8 es utilizar una interfaz con getters predeterminados. Esto será más detallado en blanco, pero se puede burlar, y es genial para cuando tienes un montón de instancias en las 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; } }); } } 

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

Simplemente agregue @GenerateMethodInvocationBuilder a la clase o interfaz, y los parámetros @Default to en los métodos en los que desea valores predeterminados. Se generará un generador en tiempo de comstackció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 puedes invocar los métodos.

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

O configure cualquiera de los valores predeterminados a otra cosa.

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

NO, pero tenemos una alternativa en forma de sobrecarga de funciones.

llamado cuando no pasó 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 } 

llamado cuando el parámetro b pasó

 void operation(int a , int b){ //code }