java - 如何使用 lambda 表达式调试 stream().map(...)?

标签 java debugging lambda java-8

在我们的项目中,我们正在迁移到 java 8,并且正在测试它的新功能。

在我的项目中,我使用 Guava 谓词和函数来过滤和转换使用 Collections2.transformCollections2.filter 的一些集合。

在此迁移中,我需要将例如 Guava 代码更改为 java 8 更改。所以,我正在做的改变是这样的:

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

到...

List<Integer> result2 = naturals.stream()
    .map(n -> n * 2)
    .collect(Collectors.toList());

使用 Guava 调试代码我很舒服,因为我可以调试每个转换过程,但我关心的是如何调试例如 .map(n -> n*2)

使用调试器,我可以看到如下代码:

@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];
}

但是调试代码不像Guava那么简单,实际上我找不到n * 2转换。

有没有办法查看这种转换或轻松调试这段代码?

编辑:我添加了来自不同评论的答案并发布了答案

感谢 Holger 评论回答了我的问题,使用 lambda block 的方法让我能够看到转换过程并调试 lambda 体内发生的事情:

.map(
    n -> {
        Integer nr = n * 2;
        return nr;
    }
)

感谢 Stuart Marks 方法引用的方法也让我能够调试转换过程:

static int timesTwo(int n) {
    Integer result = n * 2;
    return result;
}
...
List<Integer> result2 = naturals.stream()
    .map(Java8Test::timesTwo)
    .collect(Collectors.toList());
...

感谢 Marlon Bernardes 的回答,我注意到我的 Eclipse 没有显示它应该显示的内容,并且 peek() 的使用有助于显示结果。

最佳答案

在使用 Eclipse 或 IntelliJ IDEA 时,我通常可以毫无问题地调试 lambda 表达式。只需设置一个断点并确保不要检查整个 lambda 表达式(仅检查 lambda 主体)。

Debugging Lambdas

另一种方法是使用 peek 来检查流的元素:

List<Integer> naturals = Arrays.asList(1,2,3,4,5,6,7,8,9,10,11,12,13);
naturals.stream()
    .map(n -> n * 2)
    .peek(System.out::println)
    .collect(Collectors.toList());

更新:

我认为你会感到困惑,因为 map 是一个 intermediate operation - 换句话说:它是一个惰性操作,只会在 之后执行终端操作被执行。因此,当您调用 stream.map(n -> n * 2) 时,lambda 主体目前没有被执行。您需要设置断点并在调用终端操作后对其进行检查(在本例中为 collect)。

查看Stream Operations进一步解释。

更新 2:

引用 Holger's评论:

What makes it tricky here is that the call to map and the lambda expression are in one line so a line breakpoint will stop on two completely unrelated actions.

Inserting a line break right after map( would allow you to set a break point for the lambda expression only. And it’s not unusual that debuggers don’t show intermediate values of a return statement. Changing the lambda to n -> { int result=n * 2; return result; } would allow you to inspect result. Again, insert line breaks appropriately when stepping line by line…

关于java - 如何使用 lambda 表达式调试 stream().map(...)?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/24541786/

相关文章:

java - 从 ResultSet 获取所有结果

c++ - 如何在 Mac OS X 上使用 gdb 打印出 vector<unique_ptr> 中的内容

java - Lambda 流中的 ClassCastException

javascript - 如何将此 javascript 代码重写为 C++11?

java - 如何在内部函数中使用类变量?

java - setAutocommit(true) 进一步解释

java - 划掉文字

.net - 存储元数据 "CurrentBind"无效。错误

c++ - 调试断言失败!内存释放错误

C++错误: expected primary-expression before ‘[’ token