重构 Java 循环代码使用 Java 8 个流 API
Refactoring Java For loop code to use Java 8 streams API
我有以下方法用于在数据库中创建订单,订单有很多项目,项目有很多账单。 iPadPOSOrderDTO 是要存入数据库的订单。
所以,创建订单的基于循环的代码如下
private void createNewOrder(IPadPOSOrderDTO iPadPOSOrderDTO) {
IPadPOSOrderV2 order = mapper.map(iPadPOSOrderDTO, IPadPOSOrderV2.class);
if(order.getOrderV2Bills()!=null && order.getOrderV2Bills().size()>0){
for(IPadPOSOrderV2Bill orderBill : order.getOrderV2Bills()){
orderBill.setOrder(order);
if(orderBill.getiPadPOSOrderV2BillItems()!=null && orderBill.getiPadPOSOrderV2BillItems().size()>0){
for(IPadPOSOrderV2BillItems orderBillItem : orderBill.getiPadPOSOrderV2BillItems()){
orderBillItem.setiPadPOSOrderV2Bill(orderBill);
orderBillItem.setOrderId(order.getOrderId());
}
}
}
}
sessionFactory.
getCurrentSession().save(order);
}
我想重构以上代码以使用 Java 8 个流 API。
所以,我做了以下
private void createNewOrderV2(IPadPOSOrderDTO iPadPOSOrderDTO) {
IPadPOSOrderV2 order = mapper.map(iPadPOSOrderDTO, IPadPOSOrderV2.class);
if(order.getOrderV2Bills()!=null && order.getOrderV2Bills().size()>0){
order.getOrderV2Bills().stream().forEach(e -> { createBill(order,e);});
}
sessionFactory.
getCurrentSession().save(order);
}
private void createBill(IPadPOSOrderV2 ipadExistingOrderFromDatabase, IPadPOSOrderV2Bill iPadPOSOrderV2Bill) {
iPadPOSOrderV2Bill.setOrder(ipadExistingOrderFromDatabase);
if(iPadPOSOrderV2Bill.getiPadPOSOrderV2BillItems()!=null && iPadPOSOrderV2Bill.getiPadPOSOrderV2BillItems().size()>0){
iPadPOSOrderV2Bill.getiPadPOSOrderV2BillItems().stream().forEach(e -> createBillItem(ipadExistingOrderFromDatabase,iPadPOSOrderV2Bill,e));
}
}
private void createBillItem(IPadPOSOrderV2 ipadExistingOrderFromDatabase, IPadPOSOrderV2Bill iPadPOSOrderV2Bill, IPadPOSOrderV2BillItems iPadPOSOrderV2BillItem) {
iPadPOSOrderV2BillItem.setiPadPOSOrderV2Bill(iPadPOSOrderV2Bill);
iPadPOSOrderV2BillItem.setOrderId(ipadExistingOrderFromDatabase.getOrderId());
ipadExistingOrderFromDatabase.getOrderV2Bills().stream().forEach(e -> { createBill(ipadExistingOrderFromDatabase,e);});
}
如果我在重构中正确使用流 API,有人可以分享他们的经验并给我建议。
过滤掉省略空值检查的空值
private void createNewOrderV2(IPadPOSOrderDTO iPadPOSOrderDTO) {
IPadPOSOrderV2 order = mapper.map(iPadPOSOrderDTO, IPadPOSOrderV2.class);
order.getOrderV2Bills().stream().filter(Objects::nonNull).forEach(e -> createBill(order, e));
sessionFactory.getCurrentSession().save(order);
}
private void createBill(IPadPOSOrderV2 ipadExistingOrderFromDatabase, IPadPOSOrderV2Bill iPadPOSOrderV2Bill) {
iPadPOSOrderV2Bill.setOrder(ipadExistingOrderFromDatabase);
iPadPOSOrderV2Bill.getiPadPOSOrderV2BillItems().stream().filter(Objects::nonNull).forEach(e -> {
e.setiPadPOSOrderV2Bill(iPadPOSOrderV2Bill);
e.setOrderId(ipadExistingOrderFromDatabase.getOrderId());
});
}
顺便说一句,您的 createBill() 是由 createBillItem 调用的,反之亦然,这是正确的吗?
请注意,这些尺寸检查并不是真正必要的。空列表将导致空流,因此不会应用任何内容。唯一的好处是您可以避免完全创建流,但我非常怀疑性能差异是否会很明显。
如果您想将可能为 null 的集合转换为流,您可能需要使用一个小的辅助函数:
public <T> Stream<T> collectionToStream(Collection<T> collection) {
return Optional.ofNullable(collection).map(Collection::stream).orElseGet(Stream::empty);
}
使用 forEach()
然后你可以做这样的事情:
private void createNewOrder(IPadPOSOrderDTO iPadPOSOrderDTO) {
IPadPOSOrderV2 order = mapper.map(iPadPOSOrderDTO, IPadPOSOrderV2.class);
collectionToStream(order.getOrderV2Bills()).forEach( orderBill -> {
orderBill.setOrder(order);
collectionToStream(orderBill.getiPadPOSOrderV2BillItems()).forEach(orderBillItem -> {
orderBillItem.setiPadPOSOrderV2Bill(orderBill);
orderBillItem.setOrderId(order.getOrderId());
}
}
}
}
sessionFactory.getCurrentSession().save(order);
}
请注意,这与您的初始代码没有太大区别,因此您应该考虑这种转换是否有意义。
将嵌套循环转换为完全顺序的流会更难,但最终并没有什么不同,因为您不能只是将 orderBill
平面映射到 orderBillItem
的流。这样做不会使 orderBill
在下游可用,因此您必须在 返回嵌套流之前调用 orderBillItem.setiPadPOSOrderV2Bill(orderBill);
。这将以与上述非常相似的代码结束,并且不会增加任何好处,因为您没有使用返回的流。
我有以下方法用于在数据库中创建订单,订单有很多项目,项目有很多账单。 iPadPOSOrderDTO 是要存入数据库的订单。
所以,创建订单的基于循环的代码如下
private void createNewOrder(IPadPOSOrderDTO iPadPOSOrderDTO) {
IPadPOSOrderV2 order = mapper.map(iPadPOSOrderDTO, IPadPOSOrderV2.class);
if(order.getOrderV2Bills()!=null && order.getOrderV2Bills().size()>0){
for(IPadPOSOrderV2Bill orderBill : order.getOrderV2Bills()){
orderBill.setOrder(order);
if(orderBill.getiPadPOSOrderV2BillItems()!=null && orderBill.getiPadPOSOrderV2BillItems().size()>0){
for(IPadPOSOrderV2BillItems orderBillItem : orderBill.getiPadPOSOrderV2BillItems()){
orderBillItem.setiPadPOSOrderV2Bill(orderBill);
orderBillItem.setOrderId(order.getOrderId());
}
}
}
}
sessionFactory.
getCurrentSession().save(order);
}
我想重构以上代码以使用 Java 8 个流 API。
所以,我做了以下
private void createNewOrderV2(IPadPOSOrderDTO iPadPOSOrderDTO) {
IPadPOSOrderV2 order = mapper.map(iPadPOSOrderDTO, IPadPOSOrderV2.class);
if(order.getOrderV2Bills()!=null && order.getOrderV2Bills().size()>0){
order.getOrderV2Bills().stream().forEach(e -> { createBill(order,e);});
}
sessionFactory.
getCurrentSession().save(order);
}
private void createBill(IPadPOSOrderV2 ipadExistingOrderFromDatabase, IPadPOSOrderV2Bill iPadPOSOrderV2Bill) {
iPadPOSOrderV2Bill.setOrder(ipadExistingOrderFromDatabase);
if(iPadPOSOrderV2Bill.getiPadPOSOrderV2BillItems()!=null && iPadPOSOrderV2Bill.getiPadPOSOrderV2BillItems().size()>0){
iPadPOSOrderV2Bill.getiPadPOSOrderV2BillItems().stream().forEach(e -> createBillItem(ipadExistingOrderFromDatabase,iPadPOSOrderV2Bill,e));
}
}
private void createBillItem(IPadPOSOrderV2 ipadExistingOrderFromDatabase, IPadPOSOrderV2Bill iPadPOSOrderV2Bill, IPadPOSOrderV2BillItems iPadPOSOrderV2BillItem) {
iPadPOSOrderV2BillItem.setiPadPOSOrderV2Bill(iPadPOSOrderV2Bill);
iPadPOSOrderV2BillItem.setOrderId(ipadExistingOrderFromDatabase.getOrderId());
ipadExistingOrderFromDatabase.getOrderV2Bills().stream().forEach(e -> { createBill(ipadExistingOrderFromDatabase,e);});
}
如果我在重构中正确使用流 API,有人可以分享他们的经验并给我建议。
过滤掉省略空值检查的空值
private void createNewOrderV2(IPadPOSOrderDTO iPadPOSOrderDTO) {
IPadPOSOrderV2 order = mapper.map(iPadPOSOrderDTO, IPadPOSOrderV2.class);
order.getOrderV2Bills().stream().filter(Objects::nonNull).forEach(e -> createBill(order, e));
sessionFactory.getCurrentSession().save(order);
}
private void createBill(IPadPOSOrderV2 ipadExistingOrderFromDatabase, IPadPOSOrderV2Bill iPadPOSOrderV2Bill) {
iPadPOSOrderV2Bill.setOrder(ipadExistingOrderFromDatabase);
iPadPOSOrderV2Bill.getiPadPOSOrderV2BillItems().stream().filter(Objects::nonNull).forEach(e -> {
e.setiPadPOSOrderV2Bill(iPadPOSOrderV2Bill);
e.setOrderId(ipadExistingOrderFromDatabase.getOrderId());
});
}
顺便说一句,您的 createBill() 是由 createBillItem 调用的,反之亦然,这是正确的吗?
请注意,这些尺寸检查并不是真正必要的。空列表将导致空流,因此不会应用任何内容。唯一的好处是您可以避免完全创建流,但我非常怀疑性能差异是否会很明显。
如果您想将可能为 null 的集合转换为流,您可能需要使用一个小的辅助函数:
public <T> Stream<T> collectionToStream(Collection<T> collection) {
return Optional.ofNullable(collection).map(Collection::stream).orElseGet(Stream::empty);
}
使用 forEach()
然后你可以做这样的事情:
private void createNewOrder(IPadPOSOrderDTO iPadPOSOrderDTO) {
IPadPOSOrderV2 order = mapper.map(iPadPOSOrderDTO, IPadPOSOrderV2.class);
collectionToStream(order.getOrderV2Bills()).forEach( orderBill -> {
orderBill.setOrder(order);
collectionToStream(orderBill.getiPadPOSOrderV2BillItems()).forEach(orderBillItem -> {
orderBillItem.setiPadPOSOrderV2Bill(orderBill);
orderBillItem.setOrderId(order.getOrderId());
}
}
}
}
sessionFactory.getCurrentSession().save(order);
}
请注意,这与您的初始代码没有太大区别,因此您应该考虑这种转换是否有意义。
将嵌套循环转换为完全顺序的流会更难,但最终并没有什么不同,因为您不能只是将 orderBill
平面映射到 orderBillItem
的流。这样做不会使 orderBill
在下游可用,因此您必须在 返回嵌套流之前调用 orderBillItem.setiPadPOSOrderV2Bill(orderBill);
。这将以与上述非常相似的代码结束,并且不会增加任何好处,因为您没有使用返回的流。