Java 8个lambdas分组归约和映射
Java 8 lambdas grouping reducing and mapping
给定 List
的 Transaction
class,使用 Java 8 个 lambda,我想获得 List
的 ResultantDTO
, 每个帐户类型一个。
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;
}
}
到目前为止,我使用以下代码将 List<Transaction>
按 accountType
分组。
Map<String, List<Transaction>> transactionsGroupedByAccountType = transactions
.stream()
.collect(groupingBy(Transaction::getAccountType));
我如何return一个List<ResultantDTO>
,将列表从每个映射键传递到构造函数,每个accountType
包含一个ResultantDTO
?
假设你有:
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)));
您可以在一个流中完成,但这可能更干净、更简单。
您可以使用 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
class:
中进行合并
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));
您可以在单流操作中执行此操作:
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
对象,一次将生成的映射转换为其值的列表。
给定 List
的 Transaction
class,使用 Java 8 个 lambda,我想获得 List
的 ResultantDTO
, 每个帐户类型一个。
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;
}
}
到目前为止,我使用以下代码将 List<Transaction>
按 accountType
分组。
Map<String, List<Transaction>> transactionsGroupedByAccountType = transactions
.stream()
.collect(groupingBy(Transaction::getAccountType));
我如何return一个List<ResultantDTO>
,将列表从每个映射键传递到构造函数,每个accountType
包含一个ResultantDTO
?
假设你有:
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)));
您可以在一个流中完成,但这可能更干净、更简单。
您可以使用 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
class:
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));
您可以在单流操作中执行此操作:
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
对象,一次将生成的映射转换为其值的列表。