我有一份订阅列表。订阅是具有频率和金额属性的类。我的目标是获得TOTALACCRUEDMONTHLYAMOUNT,因此我分两步处理它:1)按频率对订阅进行分组,以及2)每季度,每半年和每年转换频率类型的数量每月。
例如:
Subscriptions [{
subscription {
frequency: Annually,
amount : 1200
},
subscription {
frequency: Annually,
amount : 1200
},
subscription {
frequency: Quarterly,
amount : 400
},
subscription {
frequency: Quarterly,
amount : 400
},
subscription {
frequency: Monthly,
amount : 100
},
subscription {
frequency: Semi Annually,
amount : 600
},
subscription {
frequency: Semi Annually,
amount : 600
}
}]
我能够使用以下逻辑进行分组
Map<String,BigDecimal> amountByFrequency = subscriptions.stream()
.collect(Collectors.groupingBy(
subscription::getFrequency,
Collectors.mapping(
Subscription::getAmount,
Collectors.reducing(
BigDecimal.ZERO,
(total,elm) ->(total.add(elm))))));
这样我就可以获得现在的地图了
{[Monthly, 100],[Quarterly, 800],[Annually, 2400 ],[Semi Annually, 1200]}
但是,仍然没有将金额转换为每月金额,所以我使用下面的switch语句实现了这一点。
for(Map.Entry<String, BigDecimal> entry : amountByFrequency.entrySet()) {
switch(entry.getKey()) {
case "Monthly":
sum = sum.add(entry.getValue());
break;
case "Quaterly":
sum = sum.add(entry.getValue().divide(new BigDecimal("4"),2,RoundingMode.HALF_UP));
break;
case "Semiannually":
sum = sum.add(entry.getValue().divide(new BigDecimal("6"),2,RoundingMode.HALF_UP));
break;
case "Yearly":
case "Annually":
sum = sum.add(entry.getValue().divide(new BigDecimal("12"),2,RoundingMode.HALF_UP));
break;
}
}
有没有办法用Stream API替换上面的代码? 整个主要课程如下。
class Main {
public static void main(String[] args) {
List<Subscription> subscriptions = getSubscriptionsList();
BigDecimal sum = BigDecimal.ZERO;
//Group by frequency.
Map<String, BigDecimal> amountByFrequency = subscriptions.stream()
.collect(Collectors.groupingBy(Subscription::getFrequency, Collectors.mapping(Subscription::getAmount,
Collectors.reducing(BigDecimal.ZERO, (total, elm) -> (total.add(elm))))));
//convert amount to monthly
for (Map.Entry<String, BigDecimal> entry : amountByFrequency.entrySet()) {
switch (entry.getKey()) {
case "Monthly":
sum = sum.add(entry.getValue());
break;
case "Quaterly": // divide by 4, to convert to Monthly
sum = sum.add(entry.getValue().divide(new BigDecimal("4"), 2, RoundingMode.HALF_UP));
break;
case "Semiannually": // divide by 6, to convert to Monthly
sum = sum.add(entry.getValue().divide(new BigDecimal("6"), 2, RoundingMode.HALF_UP));
break;
case "Yearly":
case "Annually": // divide by 12, to convert to Monthly
sum = sum.add(entry.getValue().divide(new BigDecimal("12"), 2, RoundingMode.HALF_UP));
break;
}
}
System.out.println("java 8--" + sum); // accrued total subscription amount
}
static class Subscription {
private String frequency;
private BigDecimal amount;
public String getFrequency() {
return frequency;
}
public void setFrequency(String frequency) {
this.frequency = frequency;
}
public BigDecimal getAmount() {
return amount;
}
public void setAmount(BigDecimal amount) {
this.amount = amount;
}
}
//build dummy subscription list.
public static List<Subscription> getSubscriptionsList() {
List<Subscription> SubscriptionsList = new ArrayList<>();
Subscription SubscriptionMonthly1 = new Subscription();
SubscriptionMonthly1.setFrequency("Monthly");
SubscriptionMonthly1.setAmount(new BigDecimal(1000.00));
Subscription SubscriptionMonthly2 = new Subscription();
SubscriptionMonthly2.setFrequency("Monthly");
SubscriptionMonthly2.setAmount(new BigDecimal(1000.00));
Subscription SubscriptionQuaterly1 = new Subscription();
SubscriptionQuaterly1.setFrequency("Quaterly");
SubscriptionQuaterly1.setAmount(new BigDecimal(1000.00));
Subscription SubscriptionQuaterly2 = new Subscription();
SubscriptionQuaterly2.setFrequency("Quaterly");
SubscriptionQuaterly2.setAmount(new BigDecimal(1000.00));
Subscription SubscriptionSemiannually1 = new Subscription();
SubscriptionSemiannually1.setFrequency("Semiannually");
SubscriptionSemiannually1.setAmount(new BigDecimal(1000.00));
Subscription SubscriptionSemiannually2 = new Subscription();
SubscriptionSemiannually2.setFrequency("Semiannually");
SubscriptionSemiannually2.setAmount(new BigDecimal(1000.00));
Subscription SubscriptionYearly1 = new Subscription();
SubscriptionYearly1.setFrequency("Yearly");
SubscriptionYearly1.setAmount(new BigDecimal(1000.00));
Subscription SubscriptionYearly2 = new Subscription();
SubscriptionYearly2.setFrequency("Yearly");
SubscriptionYearly2.setAmount(new BigDecimal(1000.00));
Subscription SubscriptionAnnually1 = new Subscription();
SubscriptionAnnually1.setFrequency("Annually");
SubscriptionAnnually1.setAmount(new BigDecimal(1000.00));
Subscription SubscriptionAnnually2 = new Subscription();
SubscriptionAnnually2.setFrequency("Annually");
SubscriptionAnnually2.setAmount(new BigDecimal(1000.00));
SubscriptionsList.add(SubscriptionMonthly1);
SubscriptionsList.add(SubscriptionMonthly2);
SubscriptionsList.add(SubscriptionQuaterly1);
SubscriptionsList.add(SubscriptionQuaterly2);
SubscriptionsList.add(SubscriptionSemiannually1);
SubscriptionsList.add(SubscriptionSemiannually2);
SubscriptionsList.add(SubscriptionYearly1);
SubscriptionsList.add(SubscriptionYearly2);
SubscriptionsList.add(SubscriptionAnnually1);
SubscriptionsList.add(SubscriptionAnnually2);
return SubscriptionsList;
}
}
答案 0 :(得分:3)
你可以沿着这些方向使用:
private static Map<String,Double> frequencyFactor = new HashMap<>();
frequencyFactor.add("Monthly", 1);
frequencyFactor.add("Annualy", 1.0/12);
frequencyFactor.add("Yearly", 1.0/12);
frequencyFactor.add("Quaterly", 1.0/4);
frequencyFactor.add("Semiannually", 1.0/6);
Integer sum = subs.stream()
.mapToDouble(sub -> sub.getAmount() * frequencyFactor.get(sub.getFrequency()))
.sum();
答案 1 :(得分:2)
根据Aaron的建议,我能够使用流将以下行替换为switch语句。
Map<String,BigDecimal> frequencyFactor = new HashMap<>();
frequencyFactor.put("Monthly", new BigDecimal(1.0));
frequencyFactor.put("Annually", new BigDecimal(1.0/12));
frequencyFactor.put("Yearly", new BigDecimal(1.0/12));
frequencyFactor.put("Quaterly", new BigDecimal(1.0/4));
frequencyFactor.put("Semiannually", new BigDecimal(1.0/6));
amountByFrequency.replaceAll((k,v) -> v .multiply(frequencyFactor.get(k)));
BigDecimal sum = amountByFrequency.entrySet().stream().map(Map.Entry::getValue).reduce(BigDecimal.ZERO, BigDecimal::add ).setScale(2, RoundingMode.HALF_UP);
System.out.println(amountByFrequency);