简体   繁体   English

Java 8使用流,flatMap和lambda

[英]Java 8 using stream, flatMap and lambda

I have this piece of code and I want to return a list of postCodes: 我有这段代码,我想返回一个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;

Here's my attempt to use stream() method and the following chained methods: 这是我尝试使用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(",")));
});

you've got several issues with your code ie: 您的代码有几个问题,即:

  1. postCodes.addAll is a side-effect and therefore you should avoid doing that otherwise when the code is executed in parallel you'll receive n on-deterministic results. postCodes.addAll是一个副作用 ,因此应避免这样做,否则当并行执行代码时,您将收到n 个确定性结果。
  2. flatMap expects a stream, not a boolean; flatMap需要一个流,而不是布尔值; which is what your code currently attempts to pass to flatMap . 这是您的代码当前尝试传递给flatMap
  3. flatMap in this case consumes a function that also consumes a value and returns a value back and considering you've decide to use a lambda statement block then you must include a return statement within the lambda statement block specifying the value to return. 在这种情况下, flatMap使用一个函数,该函数也使用一个值并返回一个值,并且考虑到您已决定使用lambda语句块,则必须在lambda语句块中包括一个return语句,以指定要返回的值。 this is not the case within your code. 在您的代码中情况并非如此。
  4. stream pipelines are driven by terminal operations which are operations that turn a stream into a non-stream value and your code currently will not execute at all as you've just set up the ingredients but not actually asked for a result from the stream. 流管道由终端操作驱动,这些操作将流转换为非流值,并且您的代码当前根本不会执行,因为您刚刚设置了成分,但实际上并未从流中请求结果
  5. the receiver type of your query should be List<String> not List<Entry> as within your current code the call to Arrays.asList(properties.getPostcodes().split(",")) returns a List<String> which you then add to an accumulator with the call addAll . 查询的接收者类型应为List<String>而不是List<Entry>因为在当前代码中,对Arrays.asList(properties.getPostcodes().split(","))的调用将返回List<String>然后通过调用addAll将其添加到累加器中。
  6. thanks to Holger for pointing it out, you're constantly failing to decide whether the variable is named entry or recordEntry . 感谢Holger指出来,您一直无法确定变量是命名为entry还是recordEntry

That said here's how I'd rewrite your code: 这就是我重写您的代码的方法:

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());

and you may want to use Collectors.toCollection to specify a specific implementation of the list returned if deemed appropriate. 并且您可能希望使用Collectors.toCollection指定返回列表的特定实现(如果认为合适)。

edit: 编辑:

with a couple of good suggestions from shmosel we can actually use method references throughout the stream pipelines and therefore enabling better intent of the code and a lot easier to follow. 借助shmosel的一些好的建议,我们实际上可以在整个流管道中使用方法引用,因此可以更好地实现代码意图,并且更易于遵循。

or you could proceed with the approach: 或者您可以继续使用该方法:

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

if it's more comfortable to you. 如果对您来说更舒适。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM