methods parametros - ¿Java soporta valores de parámetros por defecto?




opcionales variables (17)

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

es decir

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

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 parámetro a un valor predeterminado. 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 sea preferible?


No se admite, pero hay varias opciones, como usar el patrón de objeto de parámetro con algo de sintaxis de azúcar:

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 reemplazamos en la sección de inicialización de instancia de clase { param1 = 10; param2 = "bar";} { param1 = 10; param2 = "bar";}


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

Hay media docena o mejores problemas como este, eventualmente llegas al patrón de fábrica estático ... mira la api de cripto para eso. Es difícil de explicar, pero piénselo de esta manera: si tiene un constructor, predeterminado o no, la única forma de propagar el estado más allá de las llaves es tener un valor booleano isValid; (junto con el valor nulo como valor predeterminado del constructor fallido) o lanzar una excepción que nunca es informativa cuando se lo devuelve a los usuarios de campo.

Maldición del código correcto, 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. Parece que puede hacer mucho si en una llamada de método, todavía hay problemas de sincronización (), pero los valores predeterminados pueden ser "sustituidos" mejor (más seguros)

Creo que lo que debemos hacer aquí es abordar el problema de nulo como valor predeterminado con respecto a algo String one = new String (""); como una variable miembro, luego hacer una comprobación de nulo antes de asignar una cadena pasada al constructor.

Muy notable la cantidad de ciencia computacional estratosférica en bruto realizada en Java.

C ++ y así sucesivamente tiene librerías, sí. Java puede superarlos en servidores a gran escala debido a su enorme caja de herramientas. Estudia los bloques de inicialización estática, quédate con nosotros.


No. En general, Java no tiene mucha azúcar sintáctica, ya que intentaron hacer un lenguaje simple.


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

Como se describe en la respuesta vinculada, el patrón del generador 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.


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

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

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

O establezca cualquiera de los valores predeterminados a otra cosa.

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

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 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, perderá la verificació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 utiliza la clase opcional de Java 8 para los 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 tal firma demasiado detallada.

  5. Patrón constructor. El patrón de constructor se usa para los constructores y se implementa introduciendo una clase de Generador 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 normalmente se usan 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.


Pruebe esta solución:

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

    return score;
}

Como se mencionó a Scala, también vale la pena mencionar a Kotlin . En la función de Kotlin, los parámetros 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.


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;

} 

se llama cuando se pasa 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
} 

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

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


No, pero puedes emularlos muy 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 de C ++: sí, quizás pueda crear casos ambiguos, pero este problema se puede manejar fácilmente. Simplemente no se desarrolló en Java, probablemente porque los creadores querían un lenguaje mucho más simple como C ++, si tenían razón, es otra pregunta. Pero la mayoría de nosotros no creemos que use Java debido a su simplicidad.


No.

Puede lograr el mismo comportamiento pasando un Objeto que tiene valores predeterminados inteligentes. Pero otra vez depende de lo que su caso está a la mano.


Un enfoque similar a https://.com/a/13864910/2323964 que funciona en Java 8 es usar una interfaz con los getters predeterminados. Esto será más espacio en blanco, pero se puede simular, y es ideal para cuando tiene un montón de casos en los que realmente desea 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 que esté indicando lo obvio aquí, pero ¿por qué no implementar el parámetro "predeterminado"?

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 sería el uso de éter

func ("mi cuerda");

y si no desea utilizar el valor predeterminado, debe utilizar

func ("mi cadena", falso);


Una referencia siempre es un valor cuando se representa, independientemente del idioma que utilice.

Al obtener una vista externa de la caja, veamos Ensamblado o alguna administración de memoria de bajo nivel. En el nivel de la CPU, una referencia a cualquier cosa se convierte inmediatamente en un valor si se escribe en la memoria o en uno de los registros de la CPU. (Es por eso que el puntero es una buena definición. Es un valor, que tiene un propósito al mismo tiempo).

Los datos en la memoria tienen una ubicación y en esa ubicación hay un valor (byte, palabra, lo que sea). En Ensamblaje tenemos una solución conveniente para dar un Nombre a cierta Ubicación (también conocida como variable), pero al compilar el código, el ensamblador simplemente reemplaza Nombre por la ubicación designada al igual que su navegador reemplaza los nombres de dominio con direcciones IP.

Básicamente, es técnicamente imposible pasar una referencia a cualquier cosa en cualquier idioma sin representarlo (cuando se convierte de inmediato en un valor).

Digamos que tenemos una variable Foo, su ubicación está en el byte 47 en la memoria y su valor es 5. Tenemos otra variable Ref2Foo que está en el 223er byte en la memoria, y su valor será 47. Este Ref2Foo podría ser una variable técnica , no creado explícitamente por el programa. Si solo observa 5 y 47 sin ninguna otra información, verá solo dos valores . Si los usas como referencias entonces para llegar a ellos 5tenemos que viajar:

(Name)[Location] -> [Value at the Location]
---------------------
(Ref2Foo)[223]  -> 47
(Foo)[47]       -> 5

Así es como funcionan las tablas de salto.

Si queremos llamar a un método / función / procedimiento con el valor de Foo, hay algunas formas posibles de pasar la variable al método, dependiendo del idioma y sus varios modos de invocación de método:

  1. 5 se copia en uno de los registros de la CPU (es decir, EAX).
  2. 5 obtiene PUSHd a la pila.
  3. 47 se copia en uno de los registros de la CPU
  4. 47 PUSHd a la pila.
  5. 223 se copia en uno de los registros de la CPU.
  6. 223 obtiene PUSHd a la pila.

En todos los casos por encima de un valor, se ha creado una copia de un valor existente, ahora depende del método de recepción para manejarlo. Cuando se escribe "Foo" dentro del método, se lee en EAX, o se elimina la referencia automáticamente o se hace doble referencia, el proceso depende de cómo funciona el idioma y / o de lo que dicta el tipo de Foo. Esto se oculta al desarrollador hasta que ella elude el proceso de desreferenciación. Por lo tanto, una referencia es un valor cuando se representa, porque una referencia es un valor que debe procesarse (a nivel de idioma).

Ahora hemos pasado Foo al método:

  • en el caso 1. y 2. si cambia Foo ( Foo = 9), solo afecta el alcance local ya que tiene una copia del Valor. Desde dentro del método, ni siquiera podemos determinar dónde se ubicó el Foo original en la memoria.
  • en el caso 3. y 4. si usa construcciones de idioma predeterminadas y cambia Foo ( Foo = 11), podría cambiar Foo globalmente (depende del idioma, es decir, Java o como la procedure findMin(x, y, z: integer; var m de Pascal : integer);). Sin embargo, si el lenguaje le permite eludir el proceso de desreferencia, puede cambiar 47, digamos a 49. En ese punto, parece que Foo ha cambiado si lo lees, porque le has cambiado el puntero local . Y si tuviera que modificar este Foo dentro del método ( Foo = 12) probablemente FUBARÁ la ejecución del programa (también conocido como segfault) porque escribirá en una memoria diferente a la esperada, incluso puede modificar un área que está destinada a contener ejecutables El programa y la escritura en él modificarán el código en ejecución (Foo ahora no está en 47). PERO el valor de Foo de47No cambió globalmente, solo el que estaba dentro del método, porque 47también era una copia del método.
  • en el caso 5. y 6. si modifica 223dentro del método, crea el mismo caos que en 3. o 4. (un puntero, que apunta a un valor ahora malo, que se usa nuevamente como un puntero) pero esto sigue siendo un local Problema, ya que se copió el 223 . Sin embargo, si puede desreferenciar Ref2Foo(es decir 223), alcanzar y modificar el valor señalado 47, digamos, 49afectará a Foo globalmente , porque en este caso los métodos obtuvieron una copia 223pero la referencia 47solo existe una vez, y cambiarla que 49conducirá cada Ref2Foodoble desreferencia a un valor incorrecto.

Al optar por detalles insignificantes, incluso los idiomas que pasan por referencia pasarán valores a las funciones, pero esas funciones saben que tienen que usarlo para fines de desreferenciación. Este paso-la-referencia-como-valor está oculto para el programador porque es prácticamente inútil y la terminología es solo paso por referencia .

El paso por valor estricto también es inútil, significaría que una matriz de 100 Mbyte debería copiarse cada vez que llamamos a un método con la matriz como argumento, por lo tanto, Java no puede ser estrictamente pasado por valor. Cada idioma pasaría una referencia a esta gran matriz (como un valor) y empleará un mecanismo de copia en escritura si esa matriz puede cambiarse localmente dentro del método o permite que el método (como lo hace Java) modifique la matriz globalmente (desde la vista de la persona que llama) y algunos idiomas permiten modificar el valor de la referencia en sí.

Entonces, en resumen y en la terminología propia de Java, Java es el valor por donde el valor puede ser: un valor real o un valor que es una representación de una referencia .







java methods parameters default-value method-overloading