2015-06-10 98 views
2

給定以下Transaction類的List,使用Java 8 lambda,我想要獲得ListResultantDTO,每個帳戶類型一個。Java 8 lambda分組縮減和映射

public class Transaction { 

    private final BigDecimal amount; 
    private final String accountType; 
    private final String accountNumber; 

} 

public class ResultantDTO { 

    private final List<Transaction> transactionsForAccount; 

    public ResultantDTO(List<Transaction> transactionsForAccount){ 
     this.transactionsForAccount = transactionsForAccount; 
    } 

} 

到目前爲止,我通過accountType使用下面的代碼組List<Transaction>

Map<String, List<Transaction>> transactionsGroupedByAccountType = transactions 
    .stream() 
    .collect(groupingBy(Transaction::getAccountType)); 

我如何返回List<ResultantDTO>,從每個地圖鑰匙插入構造函數傳遞的列表,包含每一個accountTypeResultantDTO

+4

你可以證明你如何在沒有Stream操作的情況下做你想做的事情嗎? – Radiodef

回答

5

可以採用單流操作做到這一點:

public List<ResultantDTO> convert(List<Transaction> transactions) { 
    return transactions.stream().collect(
      collectingAndThen(
       groupingBy(
         Transaction::getAccountType, 
         collectingAndThen(toList(), ResultantDTO::new)), 
       map -> new ArrayList<>(map.values()))); 
} 

這裏collectingAndThen使用兩次:一次是針對下游Collector到列表轉換爲ResultantDTO對象,一次將結果映射轉換爲其值的列表。

2

假設你有一個:

static ResultantDTO from(List<Transaction> transactions) {...} 

你可以寫:

Map<String, List<Transaction>> transactionsGroupedByAccountType = transactions 
    .stream() 
    .collect(groupingBy(Transaction::getAccountType)); 

Map<String, ResultantDTO> result = transactionsGroupedByAccountType.entrySet().stream() 
     .collect(toMap(Entry::getKey, e -> from(e.getValue))); 

您可以做一個流,但是這可能是更清潔和更簡單。

1

您可以使用toMap收集:

Map<String, ResultantDTO> transactionsGroupedByAccountType = transactions 
       .stream() 
       .collect(toMap(Transaction::getAccountType, 
         t -> new ResultantDTO(t.getAmount(), 
               Stream.of(new SimpleEntry<>(t.getAccountNumber(), t.getAmount())) 
                .collect(toMap(SimpleEntry::getKey, SimpleEntry::getValue))), 
         (dt1, dt2) -> new ResultantDTO(dt1.getSumOfAmountForAccountType().add(dt2.getSumOfAmountForAccountType()), 
                 Stream.of(dt1.getAccountNumberToSumOfAmountForAccountNumberMap(), dt2.getAccountNumberToSumOfAmountForAccountNumberMap()) 
                  .flatMap(m -> m.entrySet().stream()) 
                  .collect(toMap(Map.Entry::getKey, Map.Entry::getValue))))); 

雖然它不是很有可讀性。也許你可以添加一個構造函數一個Transaction作爲參數,並在ResultantDTO類合併:

public ResultantDTO(Transaction t) { 
    /// 
} 

static ResultantDTO merger(ResultantDTO r1, ResultantDTO r2) { 
    /// 
} 

而且更易讀:

Map<String, ResultantDTO> transactionsGroupedByAccountType = transactions 
       .stream() 
       .collect(toMap(Transaction::getAccountType, 
           ResultantDTO::new, 
           ResultantDTO::merger));