Java Lambda的变量捕获

来源:互联网 发布:unity网络游戏源码 编辑:程序博客网 时间:2024/06/14 22:40

如果曾经使用过C++的Lambda表达式,那么就会知道C++有一个变量捕获列表

有两种捕获方式,一种是引用捕获,一种是变量捕获。与C++函数的传引用、传值相对应。

而Java与C++不同 ,java只有引用捕获

例如:

        ScheduledExecutorService ses = Executors.newScheduledThreadPool(5);

        int a=0;

        for(inti=1;i<=10;i++){

            ses.schedule(()->{

                System.out.println(a);

            },i,TimeUnit.MILLISECONDS);

        }

通过编译

 

        ScheduledExecutorService ses = Executors.newScheduledThreadPool(5);

        int a=0;

        for(inti=1;i<=10;i++){

            ses.schedule(()->{

                System.out.println(a);

            },i,TimeUnit.MILLISECONDS);

        }

  a=1;

编译失败

 

那么此时我们可以输出i吗? 答案是不可以的

因为i并不final

那么如何才能输出变量i

i作为field是否可以呢?

    private int i = 0;

    public void run(){

       ScheduledExecutorService ses = Executors.newScheduledThreadPool(5);

       for(i=1;i<=10;i++){

           ses.schedule(()->{

              System.out.println(i);

           },i,TimeUnit.MILLISECONDS);

       }

    }

编译通过,结果不正确

输出10个 “11”

这是因为执行计划任务的时候 i已经变了。这也说明java不是值捕获。

此时可以创建final的变量作为跳板,帮助我们实现此功能

        ScheduledExecutorService ses = Executors.newScheduledThreadPool(5);

        for(inti=1;i<=10;i++){

            final int curi=i;

            ses.schedule(()->{

                System.out.println(curi);

            },i,TimeUnit.MILLISECONDS);

        }

 

为什么这样声明就可以了呢?

在创建lambda表达式的时候,lambda用到的外部引用都被复制了一份(因为局部变量在栈内存中,稍后会被销毁)。

 

这样看来java的lambda在需要捕获基础类型值的场景下,不如C++灵活

而final的限制,可以减少人为的错误

原创粉丝点击