2015-06-10 72 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));