一文让你轻松理解Java中的变量捕获机制

目录

一、什么是变量捕获?

二、匿名内部类的变量捕获

三、Lambda表达式的变量捕获

四、变量捕获机制的好处 


一、什么是变量捕获?

在Java中,变量捕获(Variable Capturing)通常指的是在匿名内部类或Lambda表达式中,引用外部作用域的局部变量当在一个匿名内部类或Lambda表达式中引用外部作用域的局部变量时,该局部变量会被捕获并保存下来,以便在内部类或Lambda表达式中访问和使用。

二、匿名内部类的变量捕获

class Test {
    public void func() {
        System.out.println("func()");
    }
}

public class TestDemo {
    public static void main(String[] args) {
        int a = 100;
        Test test = new Test() {
            @Override
            public void func() {
                System.out.println("我是内部类,且重写了func这个方法!");
                System.out.println("我是捕获到变量 a == " + a
                        + " 我是一个常量,或者是一个没有改变过值的变量!");
            }
        };

        test.func();
    }
}

 在上述代码当中的变量a就是捕获的变量。

可以看到,a=100被正确地捕获了。 

重点!被匿名内部类或lambda表达式捕获的变量,要满足一下两种要求之一:

  1. 这个变量被final修饰。
  2. 如果这个变量不是被final修饰,要求事实上是最终的,即这个变量在被捕获之后没有被修改。

原因:

  • 被Lambda表达式或匿名内部类捕获的局部变量必须在编译时确定其值,并且在捕获之后不能再被修改,以确保在Lambda表达式或匿名内部类中能够安全地访问。

在Java 8之前,如果在匿名内部类或Lambda表达式中引用了外部作用域的局部变量,则这个局部变量必须显式声明为final。从Java 8开始,对于实际上不会发生更改的局部变量,可以省略final关键字,编译器会隐式地将其视为final。

因此,如果一个局部变量被Lambda表达式或匿名内部类捕获,那么它必须满足以上要求。

这些规定是为了保证在Lambda表达式或匿名内部类中能够正确地访问和使用外部作用域的局部变量,并且避免由于多线程等因素导致的并发访问问题。

如下代码就是错误的代码:

class Test {
    public void func() {
        System.out.println("func()");
    }
}

public class TestDemo {
    public static void main(String[] args) {
        int a = 100;
        Test test = new Test() {
            @Override
            public void func() {
                a = 99;
                System.out.println("我是内部类,且重写了func这个方法!");
                System.out.println("我是捕获到变量 a == " + a
                        + " 我是一个常量,或者是一个没有改变过值的变量!");
            }
        };

        test.func();
    }
}

可以看到a在匿名内部类中又被修改了,该代码直接编译报错。

三、Lambda表达式的变量捕获

Lambda 可以理解为: Lambda 就是匿名内部类的简化,实际上是创建了一个类,实现了接
口,重写了接口的方法 。 在Lambda当中也可以进行变量的捕获,具体我们看一下代码。
先写一个函数式接口:
@FunctionalInterface
interface NoParameterNoReturn {
    void test();
}
再通过 Lambda 表达式的方式重写函数式接口,实现NoParameterNoReturn的对象:
public class TestDemo {
    public static void main(String[] args) {
        int a = 10;
        NoParameterNoReturn noParameterNoReturn = () -> {
            a = 99; //error
            System.out.println("捕获变量:" + a);
        };
        noParameterNoReturn.test();
    }
}

同样的,如果在Lambda重写test方法中,尝试修改了外部变量 a 的值,此时会和匿名内部类一样编译报错。

将Lambda内的 a = 99 注释掉,此时a = 10就能够被正确捕获了。

四、变量捕获机制的好处 

变量捕获机制主要有以下几个方面的好处:

  1. 简化代码逻辑:通过变量捕获机制,内部类或Lambda表达式可以访问外部作用域的变量,避免了需要额外传递参数的繁琐过程,使得代码逻辑更为简洁明了。

  2. 提高代码可读性:将相关的变量直接捕获到内部类或Lambda表达式中,使得代码的依赖关系更加清晰,提高了代码的可读性和可维护性。

  3. 减少重复代码:通过变量捕获机制,可以避免在内部类或Lambda表达式中重复定义外部作用域的变量,减少了代码冗余,使代码更为简洁。

  4. 保证数据一致性:变量捕获机制要求外部作用域的局部变量是 final 或 effectively final 的,这种限制确保了在多线程环境下数据的一致性,避免了潜在的并发问题。

  5. 提升代码可靠性:由于变量捕获机制的限制,能够在编译阶段检查变量的赋值情况,减少了出错的可能性,从而提高了代码的可靠性。

综上所述,变量捕获机制能够使代码更加清晰、可靠和优雅,帮助开发人员编写出结构清晰、易读易懂的代码,提高代码质量和开发效率。 

  • 26
    点赞
  • 28
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Spark是一个快速通用的集群计算框架,它可以处理大规模数据,并且具有高效的内存计算能力。Spark可以用于各种计算任务,包括批处理、流处理、机器学习等。本文将带你了解Spark计算框架的基本概念和使用方法。 一、Spark基础概念 1. RDD RDD(Resilient Distributed Datasets)是Spark的基本数据结构,它是一个分布式的、可容错的、不可变的数据集合。RDD可以从Hadoop、本地文件系统等数据源读取数据,并且可以通过多个转换操作(如map、filter、reduce等)进行处理。RDD也可以被持久化到内存,以便下次使用。 2. Spark应用程序 Spark应用程序是由一个驱动程序和多个执行程序组成的分布式计算应用程序。驱动程序是应用程序的主要入口点,它通常位于用户的本地计算机上,驱动程序负责将应用程序分发到执行程序上并收集结果。执行程序是运行在集群节点上的计算单元,它们负责执行驱动程序分配给它们的任务。 3. Spark集群管理器 Spark集群管理器负责管理Spark应用程序在集群的运行。Spark支持多种集群管理器,包括Standalone、YARN、Mesos等。 二、Spark计算框架使用方法 1. 安装Spark 首先需要安装Spark,可以从Spark官网下载并解压缩Spark安装包。 2. 编写Spark应用程序 编写Spark应用程序通常需要使用Java、Scala或Python编程语言。以下是一个简单的Java代码示例,用于统计文本文件单词的出现次数: ```java import org.apache.spark.SparkConf; import org.apache.spark.api.java.JavaRDD; import org.apache.spark.api.java.JavaSparkContext; import java.util.Arrays; import java.util.Map; public class WordCount { public static void main(String[] args) { SparkConf conf = new SparkConf().setAppName("WordCount").setMaster("local"); JavaSparkContext sc = new JavaSparkContext(conf); JavaRDD<String> lines = sc.textFile("input.txt"); JavaRDD<String> words = lines.flatMap(line -> Arrays.asList(line.split(" ")).iterator()); Map<String, Long> wordCounts = words.countByValue(); for (Map.Entry<String, Long> entry : wordCounts.entrySet()) { System.out.println(entry.getKey() + " : " + entry.getValue()); } sc.stop(); } } ``` 3. 运行Spark应用程序 将编写好的Spark应用程序打包成jar包,并通过以下命令运行: ```bash spark-submit --class WordCount /path/to/wordcount.jar input.txt ``` 其,--class参数指定应用程序的主类,后面跟上打包好的jar包路径,input.txt是输入文件的路径。 4. 查看运行结果 Spark应用程序运行完毕后,可以查看应用程序的输出结果,例如上述示例的单词出现次数。 以上就是Spark计算框架的基本概念和使用方法。通过学习Spark,我们可以更好地处理大规模数据,并且提高计算效率。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值