当前位置: 首页 > 知识库问答 >
问题:

从lambda内部修改局部变量

裴经义
2023-03-14

forEach中修改局部变量会导致编译错误:

典型的

    int ordinal = 0;
    for (Example s : list) {
        s.setOrdinal(ordinal);
        ordinal++;
    }

和Lambda

    int ordinal = 0;
    list.forEach(s -> {
        s.setOrdinal(ordinal);
        ordinal++;
    });

你知道怎么解决这个问题吗?

共有3个答案

岳玉书
2023-03-14

如果您只需要将值从外部传递到lambda,而不需要将其传递出去,您可以使用常规的匿名类来代替lambda:

list.forEach(new Consumer<Example>() {
    int ordinal = 0;
    public void accept(Example s) {
        s.setOrdinal(ordinal);
        ordinal++;
    }
});
袁良弼
2023-03-14

这相当接近于XY问题。也就是说,被问到的问题本质上是如何从lambda突变捕获的局部变量。但是手头的实际任务是如何给列表中的元素编号。

根据我的经验,80%以上的情况下,有一个问题是如何从lambda中变异捕获的局部,有更好的方法继续。通常这涉及到减少,但在这种情况下,在列表索引上运行流的技术非常适用:

IntStream.range(0, list.size())
         .forEach(i -> list.get(i).setOrdinal(i));
公羊宇定
2023-03-14

任何包装都是好的。

对于Java10,使用此构造,因为它非常容易设置:

var wrapper = new Object(){ int ordinal = 0; };
list.forEach(s -> {
  s.setOrdinal(wrapper.ordinal++);
});

对于Java 8,请使用AtomicInteger

AtomicInteger ordinal = new AtomicInteger(0);
list.forEach(s -> {
  s.setOrdinal(ordinal.getAndIncrement());
});

... 或数组:

int[] ordinal = { 0 };
list.forEach(s -> {
  s.setOrdinal(ordinal[0]++);
});

注意:如果使用并行流,请非常小心。您可能不会得到预期的结果。像斯图尔特这样的其他解决方案可能更适合这些情况。

当然,这对于int以外的类型仍然有效。

例如,对于Java 10:

var wrapper = new Object(){ String value = ""; };
list.forEach(s->{
  wrapper.value += "blah";
});

或者,如果您一直使用Java8或Java9,请使用与上面相同的构造,但是使用原子引用。。。

AtomicReference<String> value = new AtomicReference<>("");
list.forEach(s -> {
  value.set(value.get() + s);
});

... 或数组:

String[] value = { "" };
list.forEach(s-> {
  value[0] += s;
});
 类似资料:
  • 问题内容: 修改中的局部变量会产生编译错误: 正常 与Lambda 任何想法如何解决这个问题? 问题答案: 任何一种包装纸都是好的。 对于 Java 8+ ,请使用: …或数组: 使用 Java 10+ : 注意: 如果使用并行流, 请 非常小心。您可能无法获得预期的结果。诸如Stuart的其他解决方案可能更适合这些情况。 对于除 当然,这对于之外的其他类型仍然有效。您只需要将包装类型更改为或该类

  • 假设我有一个和一个。我想将每个变压器应用于列表中的每个字符串。 使用Java8 lambdas,我可以这样做: 但我想做更像这样的事情,但这会导致编译时错误: 我刚刚开始玩lambdas,所以也许我只是没有正确的语法。

  • 问题内容: 为什么我需要声明一个方法,好像我在方法中定义的需要使用它一样? 范例: } 为什么String 需要是最终常量?它如何影响? 问题答案: 答案是两者在不同的范围内。因此该变量可以在内部类访问它之前更改。将其最终确定可以防止这种情况。

  • 但是,如果我在内部类中声明了一个同名的variabe呢?有什么方法可以显式引用外部变量吗? 顺便说一句,这和这个问题不同,因为它考虑的是局部堆栈变量。