开发者社区 问答 正文

重构Java For循环代码以使用Java 8流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);});
    }

如果我正确地使用了Streams API进行重构,可以有人分享他们的经验并为我提供建议。

问题来源:Stack Overflow

展开
收起
montos 2020-03-27 15:31:46 577 分享 版权
1 条回答
写回答
取消 提交回答
  • 请注意,这些尺寸检查并不是必需的。空列表将导致空流,因此将不会应用任何内容。唯一的好处是您可以避免完全创建流,但是我非常怀疑性能差异是否会很明显。

    如果要将潜在的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); 在返回嵌套流之前进行调用。最终将得到与上面非常相似的代码,并且没有任何好处,因为您没有使用返回的流。

    回答来源:Stack Overflow

    2020-03-27 15:32:36
    赞同 展开评论