我想做的是,如果连续订单的邮政编码相同,则增加 10 分钟,否则,增加 30 分钟。 例如,如果我有一个像下面这样的类,这就是我强制实现这一目标的方法。
@Data
@AllArgsConstructor
public static class Order{
private String orderNumber;
private final String postCode;
}
Order order1 = new Order("1","N1");
Order order2 = new Order("2","N1");
Order order3 = new Order("3","N3");
Order order4 = new Order("4","N4");
List<Order> orders = List.of(order1, order2, order3, order4);
int totalMin = 0;
for (int i=0;i < orders.size()-1 ; i++ ){
if (orders.get(i+1).getPostCode().equals(orders.get(i).getPostCode())){
totalMin+=10;
}
else{
totalMin+=30;
}
}
System.out.println(totalMin) // 70
// if order 2 is new Order("2","N2"); // 90
我怎样才能实现同样的事情,或者使用 Java 8 流转换上面的内容?我尝试了
reduce
功能,但无法理解它。
您可以使用
IntStream
来实现:
int totalMin =
IntStream.range(0, orders.size()-1)
.map(i-> orders.get(i+1).getPostCode().equals(orders.get(i).getPostCode()) ? 10 : 30)
.sum();
这是一个基于
Collector
的方法,可以实现预期目标:
class State {
String firstPostCode;
String lastPostCode;
int total;
}
int totalMin = orders.stream().collect(Collector.of(
State::new,
(State s, Order o) -> {
if (s.firstPostCode == null) {
s.firstPostCode = o.postCode;
} else {
s.total += o.postCode.equals(s.lastPostCode) ? 10 : 30;
}
s.lastPostCode = o.postCode;
},
(State s1, State s2) -> {
s1.total += s2.total +
(s1.lastPostCode.equals(s2.firstPostCode) ? 10 : 30);
s1.lastPostCode = s2.lastPostCode;
return s1;
},
(State s) -> s.total)
);
这个(可并行的)收集器根据所需的规则对元素求和。
由于收集器需要支持并行执行(例如
orders.parallelStream().collect(collector)
),因此实现增加了一些复杂性。值得注意的是,State
会跟踪每次运行的第一个和最后一个后置代码,以便在组合两个相邻状态时,就知道相邻订单是否处于相同的邮政编码。
累加器比较当前元素和前一个元素的邮政编码,并根据它们是否相同将总数加 10 或 30。 如果它是遇到的第一个元素,则设置第一个邮政编码。 它还将最后一个邮政编码设置为当前邮政编码。
组合器将两个州的总数相加,加上 10 或 30,具体取决于第一个州的最后一个邮政编码是否等于第二个州的第一个邮政编码(即相邻边界元素是否在同一邮政编码中)代码)。 它使用第一个州的第一个邮政编码和第二个州的最后一个邮政编码。
supplier 函数创建一个总计为 0 的空状态,finisher 函数返回状态的总计(丢弃其余的状态数据)。