在使用Java 8及以上版本的Stream API时,如果你想要优雅地处理可能为空的List,可以使用以下方法
在调用stream之前,先检查list是否为空或null。这是最直接的方法,可以避免调用stream的开销。
List<String> list = null;
if (list != null && !list.isEmpty()) {
list.stream().forEach(item -> {
// 处理每一个item
});
} else {
// 处理空或null的list
}
使用Optional来封装可能为null的List,然后使用flatMap将其转换为一个空的Stream或List的Stream。
Optional.ofNullable(list1)
// 如果list1非空,应用List::stream方法,如果list为空,map不做任何操作
.map(List::stream)
// 如果list1为空,提供一个空的Stream
.orElseGet(Stream::empty)
.forEach(item -> {
// 处理每一个item
System.out.println(item);
});
这段代码是Java中用于处理可能为空或非空的List
对象的方式,旨在以函数式风格避免出现NullPointerException
。下面分步解释这段代码的含义:
Optional.ofNullable(list1)
: 这将list1
包装在一个Optional
对象中。如果list1
是null
,那么得到的Optional
对象将是空的。.map(List::stream)
: 这一步尝试将Optional
中的list1
转换为一个流(Stream
)。如果list1
是非空的,map
操作将会应用传入的lambda表达式或方法引用(这里是List::stream
),从而将列表转化为一个流。如果list1
是空的,map
操作不会做任何事情,Optional
仍然为空。.orElseGet(Stream::empty)
: 如果前面的Optional
是空的(这意味着list1
是null
或者map
操作没有执行因为Optional
是空的),orElseGet
方法会被调用并执行其参数(方法引用Stream::empty
),该方法返回一个空的流。因此,无论list1
是否为null
,这一步都保证了一个流(Stream
)会被返回,而不是null
。.forEach(item -> { ... })
: 这是终端操作,会对前面步骤生成的流中的每个元素执行括号内的代码块。这里的代码块只是打印每个元素的内容。简单来说,这段代码的作用是,无论list1
是否为null
或者为空列表,都能安全地对其元素进行遍历操作,而不会引发NullPointerException
。如果list1
为空或为null
,流操作简单地不会执行任何操作,因为它会是一个空的流。
这种方法的好处在于,它不要求先检查list是否为null或空,代码更加简洁,并且在list为null时不会抛出NullPointerException。
如果你可以使用Apache Commons Collections或Guava库,它们提供的工具类可以帮助处理null的情况。
使用Apache Commons Collections:
CollectionUtils.emptyIfNull(list).forEach(item -> {
// 处理每一个item
});
使用Guava:
Iterables.emptyIfNull(list).forEach(item -> {
// 处理每一个item
});
这两个方法都会安全地处理null值,如果list为null,它们会返回一个空的集合,这样就可以安全地进行迭代操作而不担心NullPointerException。
在这两种方式中,第二种方法使用Apache Commons Collections的CollectionUtils.emptyIfNull
可能会更高效,原因如下:
CollectionUtils.emptyIfNull
直接返回原始集合或空集合,不涉及额外的包装和解包步骤。它是一个简单的条件检查,如果输入为null
,则返回一个预先定义的空集合。Optional
的map
和orElseGet
方法会创建更多的对象和函数调用。虽然这种开销在现代JVM上通常很小,但在大量或高频的调用中可能变得显著。CollectionUtils.emptyIfNull
的表达更加直观,它清晰地表达了操作的目的——如果集合为null
,则使用一个空的集合替代。这使得代码的阅读者很容易理解代码的意图。然而,实际上,性能差异可能是微不足道的,特别是对于小型或中等规模的集合。如果性能是一个关键考虑因素,你应该基于实际的应用场景进行基准测试。很多时候,代码的清晰性和维护性可能比微小的性能差异更为重要。
在现代Java版本中(特别是Java 9及更高),Optional
和流的性能得到了大幅优化。因此,如果不是在极端性能敏感的环境下
选择哪个方法更多的是:基于代码风格和可读性的考虑,而不是基于性能。