Considere el siguiente código:

Integer[] arr = new Integer[] {1,2};
Consumer<Integer> lm1 = a -> {
    arr[1] = a; // accepted without any problem
    System.out.println(arr[1]);
};

lm1.accept(100);

Pero el compilador tiene problemas con esto:

Integer b = 10;
Consumer<Integer> lm2 = a -> {
    b = a; // compiler complains
    System.out.println(b);
};

lm2.accept(20);

Entiendo que si reinicio arr con new Integer[]{1} en el fragmento 1 provocará un error, pero estoy más interesado en comprender por qué el fragmento 1 no causó ningún error.

1
Aniket Sahrawat 20 ene. 2018 a las 20:11

3 respuestas

La mejor respuesta

La diferencia está en el número de niveles de indirección:

  • El primer ejemplo se cierra sobre una matriz, que permanece sin cambios cuando asigna: arr es fijo, arr[1] no es
  • El segundo ejemplo se cierra sobre un objeto Integer, que intenta cambiar en una asignación b=a. Esto no esta permitido.

Tenga en cuenta que este comportamiento no es específico de la matriz: cualquier objeto mutable se puede usar para lograr la indirección. Por ejemplo, podría usar AtomicInteger, que es configurable:

AtomicInteger b = new AtomicInteger(10);
Consumer<Integer> lm2 = a -> {
    b.set(a); // compiler complains
    System.out.println(b);
};
lm2.accept(20);
3
dasblinkenlight 20 ene. 2018 a las 17:19

Bueno, la cosa es que Integer es una referencia de objeto y su referencia se puede cambiar.

Cuando tiene una matriz en el otro lado, es un conjunto fijo de direcciones en la memoria, que no se puede cambiar (es por eso que las matrices son de longitud fija). Por lo tanto, solo puede cambiar el valor en una matriz y no su referencia.

Y la lambda se invocará más adelante, por lo que el compilador quiere que la finalices para asegurarte de no cambiar la referencia.

1
Aniket Sahrawat 20 ene. 2018 a las 17:53

Las lambdas de Java requieren que cualquier variable a la que haga referencia dentro de la lambda debe ser efectivamente final , es decir, no puede modificar el valor que contiene la variable.

Cuando crea un simple Integer, es un tipo de valor regular (dejando de lado el boxeo automático); asignarle ese valor cambia y no está permitido.

Sin embargo, cuando envuelve el Integer en una matriz, no está modificando el contenido de la variable en sí, ya que es una referencia a la matriz, está modificando la matriz a la que hace referencia.

1
Aniket Sahrawat 20 ene. 2018 a las 17:33