首页 > 编程语言 >Java 中的 Lambda 表达式不能访问局部变量?

Java 中的 Lambda 表达式不能访问局部变量?

时间:2022-11-02 21:05:02浏览次数:65  
标签:Java String void 局部变量 str final Lambda

问题现象

从 Java 8 开始新增的 Lambda 表达式,可以使代码变的更加简洁紧凑,使用中还会碰到一个问题:

Variable used in lambda expression should be final or effectively final

Lambda 表达式中使用的局部变量必须是 final 或者有效的 final 类型。

问题原因

从参考资料可以得知,对于如下的 Lambda:

// 使用注解 @FunctionalInterface 告诉编译器这是一个函数式接口
@FunctionalInterface
interface Print {
    void output(String str);
}

public class Main {
    private static void handle(String str, Print p) {
        p.output(str);
    }

    public static void main(String[] args) {
        handle("abc", str -> System.out.println(str));
    }
}

其等价于下面的代码:

interface Print {
    void output(String str);
}

public class Main {
    private static void handle(String str, Print p) {
        p.output(str);
    }

    // 编译后生成的私有静态方法,方法内容就是 Lambda 里的内容
    private static void lambda$main$0(String str) {
        System.out.println(str);
    }

    // 运行时生成的内部类,实现函数式接口,实现方法中调用私有静态方法
    final class Main$$Lambda$1 implements Print {
        @Override
        public void output(String str) {
            lambda$main$0(str);
        }
    }

    public static void main(String[] args) {
        Print print = new Main().new Main$$Lambda$1();
        handle("abc", print);
    }
}

即 Lambda 表达式是通过运行时实现函数式接口的匿名内部类来调用编译后生成的私有静态方法来实现的。而 Java 8 之前,匿名类中如果要访问局部变量的话,那个局部变量必须显式的声明为 final(为了避免数据不一致,局部变量值变化无法通知匿名类)。Java 8 之后,在匿名类或 Lambda 表达式中访问的局部变量,如果不是 final 类型的话,编译器自动加上 final 修饰符,即 Java 8 新特性:effectively final(有效的 final)。

解决方案

使用全局变量

将局部变量修改为全局变量即可在 Lambda 表达式中使用,不建议使用。

将局部变量放入数组中

将局部变量放入长度为 1 的数组中:

// 总装机容量
BigDecimal[] totalPowerCapacity = {BigDecimal.ZERO};
thingFilterMap.forEach((stationId, thingInfo) -> {
    totalPowerCapacity[0] = totalPowerCapacity[0].add(thingInfo.getPowerCapacity);
}

参考资料

Variable used in lambda expression should be final or effectively final
【JAVA】Lambda 执行原理

标签:Java,String,void,局部变量,str,final,Lambda
From: https://www.cnblogs.com/ageovb/p/16852418.html

相关文章

  • JAVA的HALF_DOWN和HALF_UP的区别?
    Java代码:publicclassBigDecimalDemo{publicstaticvoidmain(String[]args){BigDecimalbd2=BigDecimal.valueOf(11);......
  • JavaWeb三大组件之Servlet学习
    JavaWeb三大组件之Servlet学习平时直接用springmvc较多,都没怎么接触底层的Servlet,导致对一些基本的知识点了解都不够,所以今天专门的抽出时间来学习一下带着问题出发,看下可以......
  • JavaWeb三大组件之Filter学习详解
    JavaWeb三大组件之Filter学习详解Filter基本上可以说存在所有的JavaWeb项目中,比如最基本的一个请求参数的编码​​CharacterEncodingFilter​​,大家一般都会配置下,那么filte......
  • Java可以如何实现文件变动的监听
    Java可以如何实现文件变动的监听应用中使用logback作为日志输出组件的话,大部分会去配置​​logback.xml​​这个文件,而且生产环境下,直接去修改logback.xml文件中的日志级......
  • java 接口的应用
    总结,接口可以在一个类继承别的父类后,如果父类不满足当前的需求,可以通过接口的形式添加方法,进行功能的扩充publicclassInter_Demo{publicstaticvoidmain(String......
  • 性能测试(7)----Java监控
    1.8堆和原空间1.7堆(普通数据放到堆)栈(基础数据放到栈) JDKbin目录下有两个java监控工具:jvisualvm(安装一个插件visualgc可以看到堆栈使用情况)和 jconsole.exe(监控......
  • Java-抽象模板模式
    什么是模板模式?定义程序的骨架,而将一些步骤延迟到子类中。模板模式使得子类可以不需要改变程序的结构即可重定义该程序的某些特定步骤。通俗的讲,模......
  • JAVA中的堆栈数据存储
    结论引用类型,总是储存在堆上(数组同样属于引用类型,只不过他是使用c实现的);基础类型,在方法中的局部变量储存在栈,对象实例中的实例字段则随对象一同存储在堆上;线程享有自......
  • JavaWeb期中考试-2021年版(一)
    终于轮到了我自己的期中考试,总体来说本次的期中考试并不难,和19年的期中考试可以说是一模一样,以下要提醒的是,程序在我的电脑上是没什么问题,但是有些配置原因可能在别的设备......
  • JavaWeb之Servlet1
    Servlet方法初始化方法,在Servlet被创建时执行,只执行一次voidinit(ServletConfigconfig)提供服务方法,每次Servlet被访问,都会调用该方法voidservice(ServletRequestr......