En nuestro proyecto estamos migrando a java 8 y estamos probando las nuevas características del mismo.
En mi proyecto, estoy usando predicados y funciones de Guava para filtrar y transformar algunas colecciones usando Collections2.transform
y Collections2.filter
.
En esta migración, necesito cambiar, por ejemplo, el código de guayaba a los cambios de java 8. Entonces, los cambios que estoy haciendo son del tipo:
List<Integer> naturals = Lists.newArrayList(1,2,3,4,5,6,7,8,9,10,11,12,13);
Function <Integer, Integer> duplicate = new Function<Integer, Integer>(){
@Override
public Integer apply(Integer n)
{
return n * 2;
}
};
Collection result = Collections2.transform(naturals, duplicate);
A...
List<Integer> result2 = naturals.stream()
.map(n -> n * 2)
.collect(Collectors.toList());
Usando guayaba me sentí muy cómodo depurando el código ya que podía depurar cada proceso de transformación, pero mi preocupación es cómo depurar, por ejemplo .map(n -> n*2)
.
Usando el depurador puedo ver un código como:
@Hidden
@DontInline
/** Interpretively invoke this form on the given arguments. */
Object interpretWithArguments(Object... argumentValues) throws Throwable {
if (TRACE_INTERPRETER)
return interpretWithArgumentsTracing(argumentValues);
checkInvocationCounter();
assert(arityCheck(argumentValues));
Object[] values = Arrays.copyOf(argumentValues, names.length);
for (int i = argumentValues.length; i < values.length; i++) {
values[i] = interpretName(names[i], values);
}
return (result < 0) ? null : values[result];
}
Pero no es tan sencillo como Guava depurar el código, en realidad no pude encontrar la n * 2
transformación.
¿Hay alguna forma de ver esta transformación o una forma de depurar fácilmente este código?
EDITAR: agregué respuestas de diferentes comentarios y publiqué respuestas
Gracias al Holger
comentario que respondió a mi pregunta, el enfoque de tener un bloque lambda me permitió ver el proceso de transformación y depurar lo que sucedió dentro del cuerpo lambda:
.map(
n -> {
Integer nr = n * 2;
return nr;
}
)
Gracias al Stuart Marks
enfoque de tener referencias de métodos también me permitió depurar el proceso de transformación:
static int timesTwo(int n) {
Integer result = n * 2;
return result;
}
...
List<Integer> result2 = naturals.stream()
.map(Java8Test::timesTwo)
.collect(Collectors.toList());
...
Gracias a la Marlon Bernardes
respuesta, noté que mi Eclipse no muestra lo que debería y el uso de peek () ayudó a mostrar los resultados.
result
variable temporal comoInteger
. Un simpleint
debería funcionar también si está haciendomap
pingint
a unint
…Respuestas:
Por lo general, no tengo problemas para depurar expresiones lambda mientras uso Eclipse o IntelliJ IDEA. Simplemente establezca un punto de interrupción y asegúrese de no inspeccionar toda la expresión lambda (inspeccione solo el cuerpo lambda).
Otro enfoque es utilizar
peek
para inspeccionar los elementos de la secuencia:ACTUALIZAR:
Creo que se está confundiendo porque
map
es unaintermediate operation
, en otras palabras: es una operación perezosa que se ejecutará solo después de queterminal operation
se haya ejecutado. Entonces, cuando llamasstream.map(n -> n * 2)
al cuerpo lambda, no se está ejecutando en este momento. Debe establecer un punto de interrupción e inspeccionarlo después de llamar a una operación de terminal (collect
, en este caso).Consulte Operaciones de transmisión para obtener más explicaciones.
ACTUALIZACIÓN 2:
Citando el comentario de Holger :
fuente
inspect
anddisplay
y getn cannot be resolved to a variable
. Por cierto, peek también es útil, pero imprime todos los valores a la vez. Quiero ver cada proceso de iteración para verificar la transformación. Es posible.map
línea y presione F8 varias veces.map
la expresión lambda están en una línea, por lo que un punto de interrupción de línea se detendrá en dos acciones completamente no relacionadas. Insertar un salto de línea justo despuésmap(
le permitiría establecer un punto de interrupción solo para la expresión lambda. Y no es inusual que los depuradores no muestren valores intermedios de unareturn
declaración. Cambiar la lambda an -> { int result=n * 2; return result; }
le permitiría inspeccionarresult
. Una vez más, inserte los saltos de línea de manera apropiada al pasar línea por línea ...IntelliJ tiene un complemento tan agradable para este caso como un complemento Java Stream Debugger . Debería comprobarlo: https://plugins.jetbrains.com/plugin/9696-java-stream-debugger?platform=hootsuite
Extiende la ventana de la herramienta IDEA Debugger agregando el botón Trace Current Stream Chain, que se activa cuando el depurador se detiene dentro de una cadena de llamadas Stream API.
Tiene una interfaz agradable para trabajar con operaciones de secuencias separadas y le brinda la oportunidad de seguir algunos valores que debe depurar.
Puede iniciarlo manualmente desde la ventana Depurar haciendo clic aquí:
fuente
La depuración de lambdas también funciona bien con NetBeans. Estoy usando NetBeans 8 y JDK 8u5.
Si establece un punto de interrupción en una línea donde hay un lambda, en realidad golpeará una vez cuando se configure la canalización, y luego una vez para cada elemento de flujo. Usando su ejemplo, la primera vez que llegue al punto de interrupción será la
map()
llamada que está configurando el flujo de flujo:Puede ver la pila de llamadas y las variables locales y los valores de los parámetros
main
como era de esperar. Si continúa avanzando, se vuelve a tocar el "mismo" punto de interrupción, excepto que esta vez está dentro de la llamada a la lambda:Tenga en cuenta que esta vez la pila de llamadas se encuentra en lo más profundo de la maquinaria de flujos, y las variables locales son las variables locales de la lambda en sí, no el
main
método adjunto . (Cambié los valores en lanaturals
lista para aclarar esto).Como señaló Marlon Bernardes (+1), puede usarlo
peek
para inspeccionar los valores a medida que pasan en la tubería. Sin embargo, tenga cuidado si está usando esto desde una transmisión paralela. Los valores se pueden imprimir en un orden impredecible en diferentes subprocesos. Si está almacenando valores en una estructura de datos de depuración depeek
, esa estructura de datos, por supuesto, tendrá que ser segura para subprocesos.Finalmente, si está haciendo mucha depuración de lambdas (especialmente lambdas de declaración de varias líneas), podría ser preferible extraer el lambda en un método con nombre y luego consultarlo usando una referencia de método. Por ejemplo,
Esto podría hacer que sea más fácil ver lo que sucede mientras está depurando. Además, extraer métodos de esta manera facilita la prueba unitaria. Si su lambda es tan complicado que necesita realizar un solo paso a través de él, probablemente desee tener un montón de pruebas unitarias para él de todos modos.
fuente
{ int result=n * 2; return result; }
diferentes líneas y pude aceptar la respuesta ya que ambas respuestas fueron útiles. +1 por supuesto.Intellij IDEA 15 parece hacerlo aún más fácil, permite detenerse en una parte de la línea donde está lambda, vea la primera característica: http://blog.jetbrains.com/idea/2015/06/intellij-idea-15 -eap-is-open /
fuente
Solo para proporcionar detalles más actualizados (octubre de 2019), IntelliJ ha agregado una integración bastante agradable para depurar este tipo de código que es extremadamente útil.
Cuando nos detenemos en una línea que contiene un lambda si presionamos F7(entrar), IntelliJ resaltará cuál será el fragmento para depurar. Podemos cambiar el fragmento con el que depurar Taby una vez que lo decidimos, hacemos clic de F7nuevo.
Aquí algunas capturas de pantalla para ilustrar:
1- Presione la F7tecla (entrar), se mostrarán los aspectos más destacados (o el modo de selección)
2- Use Tabvarias veces para seleccionar el fragmento para depurar
3- Presione la F7tecla (entrar) para entrar
fuente
La depuración con IDE siempre es útil, pero la forma ideal de depurar cada elemento en una secuencia es usar peek () antes de una operación de método de terminal, ya que los Steam de Java se evalúan de forma perezosa, por lo que, a menos que se invoque un método de terminal, la secuencia respectiva no ser evaluado.
fuente