在讲闭包之前,我们先了解一下函数式接口。你可能已经见过这样的代码:
// 传统写法:创建一个接口的实现
Runnable task = new Runnable() {
@Override
public void run() {
System.out.println("Hello World");
}
};
这里的Runnable
就是一个函数式接口,它的特点是:只有一个抽象方法需要实现。
Java中有很多这样的函数式接口:
Runnable
接口只有一个run()
方法Function<T,R>
接口只有一个apply()
方法 Consumer<T>
接口只有一个accept()
方法既然函数式接口只有一个方法,Java 8就提供了Lambda表达式来简化写法:
// 传统写法
Function<Integer, Integer> 加1 = new Function<Integer, Integer>() {
@Override
public Integer apply(Integer x) {
return x + 1;
}
};
// Lambda简化写法
Function<Integer, Integer> 加1简化版 = x -> x + 1;
看到了吗?Lambda表达式x -> x + 1
其实就是在实现Function
接口的apply
方法。
闭包听起来很高大上,其实就是一个简单的概念:函数能够"记住"并使用它外面的变量。
就像你在家里(函数)能够使用客厅里的电视(外部变量)一样,即使你后来搬到了别的地方,你依然记得那台电视。
import java.util.function.Function;
public class 简单闭包例子 {
public static void main(String[] args) {
int 外面的数字 = 10;
// 这个Lambda表达式实际上是在实现Function接口
// 但它"记住"了外面的数字 - 这就是闭包!
Function<Integer, Integer> 乘法器 = x -> x * 外面的数字;
System.out.println(乘法器.apply(5)); // 输出: 50
}
}
看到了吗?乘法器
这个Lambda表达式实际上是在实现Function
接口,但它神奇的地方在于:它能使用外面的外面的数字
变量。这就是闭包!
换句话说,闭包就是:Lambda表达式 + 它能访问的外部变量。
import java.util.function.Function;
public class 计算器例子 {
// 这个方法返回一个"专门乘某个数"的函数
public static Function<Integer, Integer> 做个乘法器(int 倍数) {
return 数字 -> 数字 * 倍数; // 闭包:记住了"倍数"
}
public static void main(String[] args) {
// 做一个专门乘2的函数
Function<Integer, Integer> 乘以2 = 做个乘法器(2);
// 做一个专门乘10的函数
Function<Integer, Integer> 乘以10 = 做个乘法器(10);
System.out.println(乘以2.apply(5)); // 输出: 10
System.out.println(乘以10.apply(5)); // 输出: 50
}
}
import java.util.Arrays;
import java.util.List;
import java.util.stream.Collectors;
public class 过滤例子 {
public static void main(String[] args) {
List<Integer> 数字们 = Arrays.asList(1, 2, 3, 4, 5, 6, 7, 8, 9, 10);
int 标准 = 5;
// 闭包:记住了"标准"这个变量
List<Integer> 大数字们 = 数字们.stream()
.filter(数字 -> 数字 > 标准) // 这里用了外面的"标准"
.collect(Collectors.toList());
System.out.println(大数字们); // 输出: [6, 7, 8, 9, 10]
}
}
Java的闭包有个规定:被"记住"的变量不能改变。
public class 限制例子 {
public static void main(String[] args) {
int 计数器 = 0;
// 这样写会报错,因为试图改变"计数器"
// Runnable 任务 = () -> 计数器++; // 编译错误!
// 正确的做法:用个盒子装着
AtomicInteger 计数器盒子 = new AtomicInteger(0);
Runnable 任务 = () -> {
int 新值 = 计数器盒子.incrementAndGet();
System.out.println("计数: " + 新值);
};
任务.run(); // 输出: 计数: 1
任务.run(); // 输出: 计数: 2
}
}
JButton 按钮 = new JButton("点我");
String 消息 = "你点击了按钮!";
// 闭包:记住了"消息"
按钮.addActionListener(事件 -> {
JOptionPane.showMessageDialog(null, 消息);
});
List<String> 名字们 = Arrays.asList("小明", "小红", "小刚");
String 前缀 = "同学";
// 闭包:记住了"前缀"
List<String> 称呼们 = 名字们.stream()
.map(名字 -> 前缀 + 名字)
.collect(Collectors.toList());
System.out.println(称呼们); // 输出: [同学小明, 同学小红, 同学小刚]
闭包就是这么简单:
下次看到Lambda表达式用了外面的变量,你就知道了:哦,这就是闭包!
没那么复杂,对吧?
原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。
如有侵权,请联系 cloudcommunity@tencent.com 删除。
原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。
如有侵权,请联系 cloudcommunity@tencent.com 删除。