面试题答案
一键面试可能导致NullPointerException
出现在Stream操作中的场景:
- 数据源包含
null
元素:当Stream的数据源(如List、数组等)中存在null
元素,而后续的Stream操作(如map
、filter
等)对这些null
元素进行处理时,可能会引发NullPointerException
。例如:
List<String> list = Arrays.asList("a", null, "c");
list.stream()
.map(String::length)
.forEach(System.out::println);
在上述代码中,map
操作尝试调用null
元素的length
方法,从而导致NullPointerException
。
2. 中间操作返回null
:某些自定义的中间操作方法可能返回null
,如果后续的Stream操作依赖于这个返回值,也会引发异常。例如:
class CustomMapper {
public static Integer customMap(String s) {
if (s == null) {
return null;
}
return s.length();
}
}
List<String> list = Arrays.asList("a", "b", "c");
list.stream()
.map(CustomMapper::customMap)
.filter(Objects::nonNull)
.forEach(System.out::println);
// 如果不添加filter(Objects::nonNull),当customMap返回null时,后续操作可能报错
- 终端操作依赖于
null
值:例如reduce
操作,如果初始值为null
且流为空,或者累加器函数在处理过程中返回null
,可能会导致NullPointerException
。如:
List<Integer> numbers = Collections.emptyList();
Integer result = numbers.stream()
.reduce(null, (a, b) -> a + b);
// 这里初始值为null且流为空,会导致NullPointerException
调试方法:
- 添加日志输出:在Stream操作的关键节点(如
map
、filter
等操作前后)添加日志输出,打印当前处理的元素,以确定哪个元素或操作导致了异常。例如:
List<String> list = Arrays.asList("a", null, "c");
list.stream()
.peek(e -> System.out.println("Before map: " + e))
.map(String::length)
.peek(len -> System.out.println("After map: " + len))
.forEach(System.out::println);
- 使用调试工具:利用IDE(如IntelliJ IDEA、Eclipse等)的调试功能,在Stream操作的代码行设置断点,逐步调试代码,观察变量的值和执行流程,找出引发异常的具体位置。
解决方法:
- 过滤掉
null
元素:在进行可能引发NullPointerException
的操作之前,使用filter
操作过滤掉null
元素。例如:
List<String> list = Arrays.asList("a", null, "c");
list.stream()
.filter(Objects::nonNull)
.map(String::length)
.forEach(System.out::println);
- 提供默认值或进行空值处理:在
map
等操作中,对可能为null
的输入提供默认值或进行空值处理。例如:
List<String> list = Arrays.asList("a", null, "c");
list.stream()
.map(s -> s == null? 0 : s.length())
.forEach(System.out::println);
- 检查终端操作的初始值和累加器:对于
reduce
等终端操作,确保初始值合理且累加器函数不会返回null
。例如:
List<Integer> numbers = Collections.emptyList();
Integer result = numbers.stream()
.reduce(0, (a, b) -> a + b);
// 使用合理的初始值0