2017-02-27 67 views
4

我想爲下面的實現使用Java 8流。基本上我想解析一個列表並形成不同對象的另一個列表。如何用Java 8流代替嵌套循環

輸入 - 人的POJO列表, 輸出 - PersonInfo的POJO列表

List<Person> persons = new ArrayList<Person>(); 

    Person max = new Person(); 
    max.setName("Max"); 
    max.setAge(10); 
    max.addAddress(new Address("Street1", "City1")); 
    max.addAddress(new Address("Street2", "City2")); 

    Person peter = new Person(); 
    peter.setName("Peter"); 
    peter.setAge(20); 
    peter.addAddress(new Address("Street1", "City1")); 
    peter.addAddress(new Address("Street2", "City2")); 

    persons.add(max); 
    persons.add(peter); 

    System.out.println("Input: " + persons); 

    List<PersonInfo> personInfos = new ArrayList<PersonInfo>(); 
    PersonInfo personInfo = null; 
    for (Person person : persons) { 
     for (Address addr : person.getCurrAndPrevAddrs()) { 
      personInfo = new PersonInfo(); 
      personInfo.setName(person.getName()); 
      personInfo.setAge(person.getAge()); 
      personInfo.setAddrs(addr);    
      personInfos.add(personInfo); 
     } 
    } 

    System.out.println("Output: " + personInfos.toString()); 

樣本輸出輸入:[最大10 [Street1 City1,STREET2城2]

,彼得20 Street1 City1,STREET2城2]]

輸出:[最大10 Street1 City1

,最多10 STREET2城2

,彼得20 Street1 City1

,彼得20 STREET2城2]

+0

輸出:輸入:?? –

+0

@Elise van Looij,我提供了關於我的問題的示例輸出和輸入。如果您需要更多信息,請告訴我。 – Pons

回答

4
List<PersonInfo> personInfos = persons.stream().flatMap(person -> person.getCurrAndPrevAddrs().stream().map(addr -> { 
     PersonInfo personInfo = new PersonInfo(); 
     personInfo.setName(person.getName()); 
     personInfo.setAge(person.getAge()); 
     personInfo.setAddrs(addr);    
     return personInfo; 
})).collect(Collectors.toList()); 
+0

我收到一些編譯錯誤。 1.'persons.flatMap',「人」是列表或流,我想你的意思是說'persons.stream()flatMap' 2「類型不匹配:不能從流轉換到列表」。 – Pons

+1

@Pons我在我的手機上,所以我很難驗證。你可以說得更詳細點嗎? – shmosel

+1

@Pons你說得對第一點。我也錯過了一個括號。現在試試。 – shmosel

2

下面是一個簡化你正在嘗試做什麼的版本。我簡化了Pojos的測試。 (1)提高可讀性和(2)簡化代碼的維護

List<Person> persons = new ArrayList<Person>(); 

Person person1 = new Person("person1"); 
Person person2 = new Person("person2"); 

persons.add(person1); 
persons.add(person2); 

List<PersonInfo> personInfos = new ArrayList<PersonInfo>(); 
persons.stream().forEach(person -> {  
    person.getCurrAndPrevAddrs().stream().forEach(address -> { 
    PersonInfo personInfo = new PersonInfo("personInfo"); 
    personInfo.setAddress(address); 
    personInfos.add(personInfo); 
    }); 
}); 

System.out.println("Output: " + personInfos.toString()); 
+0

謝謝,這工作正常。但有一點是,'forEach'可用於'Iterable',所以,我試圖讓我的頭腦發現,這會給我帶來什麼樣的好處? – Pons

+0

這看起來像它會在並行實現上拋出一個ConcurrentModificationException異常。 – MikaelF

1

一種方式是一個toPersonInfo方法添加到您的Person類,如下所示:

public class Person { 
    //getters, setters, etc. 
    public List<PersonInfo> toPersonInfos() { 
     List<PersonInfo> result = new ArrayList<>(); 
     for (Address addr : getCurrentAndPrevAddrs()) { 
      PersonInfo pi = new PersonInfo(); 
      pi.setName(this::getName); 
      pi.setAge(this::getAge); 
      pi.setAddrs(this::addr); 
      result.add(pi); 
     } 
     return result; 
    } 
} 

這樣,如果你更改過自己的PersonInfo或您的Person類,你只需要改變一個方法,這是正確的,在你的Person類。

這也大大簡化了流操作:

personInfos = persons.stream().flatMap(p -> p.toPersonInfos.stream()).collect(Collectors.toList()); 

注意,這不一定會返回一個有序列表。