Java 8使用stream,flatMap和lambda

inv*_*s04 2 java lambda java-8 java-stream flatmap

我有这段代码,我想返回一个postCodes列表:

List<String> postcodes = new ArrayList<>();
List<Entry> entries = x.getEntry(); //getEntry() returns a list of Entry class
for (Entry entry : entries) {
    if (entry != null) {
       Properties properties = entry.getContent().getProperties();
       postcodes.addAll(Arrays.asList(properties.getPostcodes().split(",")));
   }
} 
return postcodes;
Run Code Online (Sandbox Code Playgroud)

这是我尝试使用stream()方法和以下链式方法:

...some other block of code
List<Entry> entries = x.getEntry.stream()
    .filter(entry -> recordEntry != null)
    .flatMap(entry -> {
        Properties properties = recordEntry.getContent().getProperties();
        postCodes.addAll(Arrays.asList(properties.getPostcodes().split(",")));
});
Run Code Online (Sandbox Code Playgroud)

Ous*_* D. 5

你的代码有几个问题,即:

  1. postCodes.addAll副作用,因此你应该避免这样做,否则当代码并行执行时,你将收到n 个确定性结果.
  2. flatMap期待一个流,而不是布尔值; 这是您的代码当前尝试传递给的内容flatMap.
  3. flatMap在这种情况下,使用一个也消耗一个值并返回一个值的函数,并且考虑到你决定使用一个lambda语句块,那么你必须在lambda语句块中包含一个return语句,指定要返回的值.在您的代码中不是这种情况.
  4. 流管道由终端操作驱动,终端操作是将流转换为非流值的操作,而您的代码当前根本不会执行,因为您只是设置了成分但实际上没有从流中请求结果.
  5. 您的查询的接收器类型应该List<String>不在List<Entry>您当前的代码中,该调用将Arrays.asList(properties.getPostcodes().split(","))返回一个List<String>您随后通过该调用添加到累加器的调用addAll.
  6. 感谢Holger指出它,你总是无法确定变量是否被命名entryrecordEntry.

这就是说我是如何重写你的代码的:

List<String> entries = x.getEntry.stream()
        .filter(Objects::nonNull)
        .map(Entry::getContent)
        .map(Content::getProperties)
        .map(Properties::getPostcodes?)
        .flatMap(Pattern.co?mpile(",")::splitAsS?tream)
        .collect(Collectors.toList());
Run Code Online (Sandbox Code Playgroud)

Collectors.toCollection如果认为合适,您可能希望用于指定返回列表的特定实现.

编辑:

通过shmosel的一些好建议,我们实际上可以在整个流管道中使用方法引用,从而实现更好的代码意图,并且更容易遵循.

或者你可以继续这种方法:

List<String> entries = x.getEntry.stream()
       .filter(e -> e != null)
       .flatMap(e -> Arrays.asList(
         e.getContent().getProperties().getPostcodes().split(",")).stream()
       )
       .collect(Collectors.toList());
Run Code Online (Sandbox Code Playgroud)

如果它对你来说更舒服

  • 你可以用'Arrays.stream(...)`或`Stream.of(...)`替换`Arrays.asList(...).stream()`. (3认同)
  • 如果你更喜欢方法引用,你也可以做`.map(Entry :: getContent).map(Content :: getProperties).map(Properties :: getPostcodes).flatMap(Pattern.compile(","):: splitAsStream) `. (2认同)
  • 你不需要`Arrays.asList(...).stream()`; 使用`Arrays.stream(...)`来获取流.问题清单不完整.原始代码的另一个问题是OP经常无法确定变量是否被命名为`entry`或`recordEntry`. (2认同)