面试题答案
一键面试Java Stream中函数式接口的延迟执行特性
Java Stream的函数式接口(如filter
、map
等)的延迟执行特性指的是,这些操作并不会立即执行,而是等到一个终端操作(如collect
、forEach
等)被调用时才会真正执行。这意味着在中间操作(函数式接口相关操作)被调用时,Stream只是记录下要执行的操作,而不会马上处理数据。这样做可以优化操作流程,避免不必要的计算。
性能提升场景举例
- 减少不必要计算
假设有一个包含大量整数的列表,需要找出其中第一个大于100的数并将其翻倍。如果没有延迟执行特性,在
filter
操作时就会对所有元素进行过滤检查,即使找到符合条件的元素后还会继续检查剩余元素。而延迟执行可以在找到第一个符合条件的元素后就停止后续操作。
List<Integer> numbers = Arrays.asList(1, 50, 150, 200, 300);
Optional<Integer> result = numbers.stream()
.filter(n -> {
System.out.println("Filtering: " + n);
return n > 100;
})
.findFirst()
.map(n -> {
System.out.println("Mapping: " + n);
return n * 2;
});
result.ifPresent(System.out::println);
// 输出:
// Filtering: 1
// Filtering: 50
// Filtering: 150
// Mapping: 150
// 300
在上述代码中,filter
和map
操作都是延迟执行的,当findFirst
终端操作被调用时,Stream从列表开始处理元素,找到第一个大于100的元素150后,就停止对剩余元素的过滤检查,直接执行map
操作。
- 优化复杂操作链 当有多个中间操作组成的复杂操作链时,延迟执行可以对整个操作链进行优化。例如,对一个大文件的文本行进行处理,先过滤掉空行,再转换为大写,最后统计行数。
Path path = Paths.get("largeFile.txt");
try (Stream<String> lines = Files.lines(path)) {
long count = lines
.filter(line ->!line.isEmpty())
.map(String::toUpperCase)
.count();
System.out.println("Non - empty lines count: " + count);
} catch (IOException e) {
e.printStackTrace();
}
这里filter
和map
操作都是延迟执行,Stream可以在count
终端操作调用时,以更高效的方式处理文件,而不是对每一行先进行过滤再进行转换,可能会减少内存占用和磁盘I/O操作。