son recorrer que lista las interfaces funcionales funcional expresiones explicacion ejemplos con java lambda java-8 java-9

java - que - recorrer lista con lambda



Determine si una expresión lambda es sin estado o con estado en Java (4)

¿Existe una función que acepte una referencia a una expresión lambda y devuelva un booleano que diga si la expresión lambda es sin estado o no? ¿Cómo se puede determinar la condición de estado de una expresión lambda?


Aquí hay una idea simple y estúpida. Solo verifica si tu lambda tiene campos.

Por ejemplo, considere la siguiente lambda con estado.

List<Integer> serialStorage = new ArrayList<>(); Function<? super Integer, ? extends Integer> statefulLambda = e -> { serialStorage.add(e); return e; };

Este statefulLambda tiene un campo interno final privado arg$1 que obviamente hace referencia a serialStorage . Asi que

statefulLambda.getClass().getDeclaredFields().length > 0

Podría ser utilizado como indicador de que lambda es de estado.

Sin embargo, no tengo idea si esto funcionará en general.


Bueno, una expresión lambda es solo una instancia de una clase anónima especial que solo tiene un método. Las clases anónimas pueden " capturar " variables que se encuentran en el ámbito circundante. Si su definición de una clase con estado es una que lleva cosas mutables en sus campos (de lo contrario es prácticamente una constante), entonces está de suerte, porque así es como se implementa la captura . Aquí hay un pequeño experimento:

import java.lang.reflect.Field; import java.util.function.Function; public class Test { public static void main(String[] args) { final StringBuilder captured = new StringBuilder("foo"); final String inlined = "bar"; Function<String, String> lambda = x -> { captured.append(x); captured.append(inlined); return captured.toString(); }; for (Field field : lambda.getClass().getDeclaredFields()) System.out.println(field); } }

La salida se ve algo como esto:

private final java.lang.StringBuilder Test$$Lambda$1/424058530.arg$1

La referencia de StringBuilder se convirtió en un campo de la clase lambda anónima (y la constante en final String inlined estaba en línea para la eficiencia, pero eso no viene al caso). Así que esta función debería hacer en la mayoría de los casos:

public static boolean hasState(Function<?,?> lambda) { return lambda.getClass().getDeclaredFields().length > 0; }

EDITAR: como lo señaló @Federico, este es un comportamiento específico de la implementación y podría no funcionar en algunos entornos exóticos o futuras versiones de la JVM Oracle / OpenJDK .


No, generalmente no es posible. El enfoque sugerido de verificar si la lambda pertenece a una clase con un campo es la mejor opción, pero tener un campo no es lo mismo que tener un estado.

class Stateless { int result = 0; public int getResult() { return result; } }

Es posible probar el estado de estado al encontrar dos secuencias de entrada para las cuales una combinación de entrada dada devuelve un resultado diferente. Sin embargo, no es posible probar que tal secuencia de entrada no existe (cualquier secuencia de entrada podría producir un resultado diferente si es precedida por otra invocación).

(Incluso si verifica los valores de los campos encontrados mediante la reflexión, estos pueden cambiar sin influir en el resultado de la lambda, por lo tanto, en realidad no lo hacen estable).

Aquí hay un breve ejemplo compilable que muestra falsos positivos y negativos, refutando la noción:

public class StatefulLambda { static AtomicInteger counter = new AtomicInteger(); public static void main(String[] args) { // false negative: will return different result each call System.out.println(hasState(i -> counter.incrementAndGet())); // false positive: will always return the same result Object object = new Object() { final int i = 0; }; System.out.println(hasState(i -> object.toString())); } private static boolean hasState(Function<?,?> lambda) { return lambda.getClass().getDeclaredFields().length > 0; } }


Yo diría que no es posible escribir una función que pueda determinar si un lambda es sin estado o no:

Al observar, por ejemplo, el método de filter de la API Stream, el javadoc declara que el parámetro debe ser "un predicado sin [...] estado" y también se vincula con la definición de la API de stateless .

Si hubiera una manera de determinar si el parámetro del método de filter (o cualquier otro) era sin estado o no, la clase Stream habría incluido la posibilidad de lanzar una IllegalArgumentException en caso de que el parámetro fuera un lambda con estado. Como esto no se ha implementado y solo se agregó una advertencia a los javadocs, se puede concluir que no hay forma de escribir una función que pueda determinar si un lambda lambda no tiene estado.

Editar (después de leer los comentarios de Eric): hay muchas situaciones en las que un equipo de implementación toma decisiones de implementación para no implementar una característica en particular; Por lo general , no podemos concluir de esas elecciones que la característica es imposible de implementar para otra persona. En este caso especial, creo que es improbable que los diseñadores de Java 8 no lo hubieran encontrado o hecho si hubiera una solución (computacional barata).