I'm trying to implement a good design in my code. There is a Entity purchaseOrder and I need to navigate inside that object that has a list of stockOrder and each StockOrder has a list of StockOrderItem. There is no guarantee that a stockOrder or stockOrderItem exists so I needed to check a lot of nulls. Is there a elegant way to do that?
PurchaseOrder purchaseOrder = purchaseOrderRepository.
findByIdentifierAndBrandId(po.getPurchaseOrderIdentifier(), po.getBrandId());
List<StockOrder> stockOrders = Optional.ofNullable(
purchaseOrder.getStockOrders()).orElse(Collections.emptyList());
for (StockOrder stockOrder : stockOrders) {
for (StockOrderItem stockOrderItem : Optional.
ofNullable(stockOrder.getStockOrderItems()).orElse(Collections.emptyList())) {
InventoryDataLoad inventoryDataload = new InventoryDataLoad();
inventoryDataload.setSku(stockOrderItem.getSku());
inventoryDataLoadList.add(inventoryDataload);
}
}
It's not a good practice to return nulls for collection fields. Considering you have access to these classes, return an empty list from the get methods instead:
StockOrder.java
public List<StockOrderItem> getStockOrderItems() {
return this.getStockOrderItems != null this.getStockOrderItems ? Collections.emptyList();
}
Or better, as @Ridiculon pointed out in the comments, initialize the collection fields with a new ArrayList()
directly.
StockOrder.java
private final List<StockOrderItem> stockOrderItems;
public StockOrder() {
this.stockOrderItems = new ArrayList();
}
With that in place, you can use a more elegant functional approach to populate your list, such as:
List<InventoryDataLoad> inventoryDataLoadList = purchaseOrderRepository
.findByIdentifierAndBrandId(po.getPurchaseOrderIdentifier(), po.getBrandId())
.getStockOrders()
.stream()
.map(StockOrder::getStockOrderItems)
.flatMap(Collection::stream)
.map(item -> {
InventoryDataLoad inventoryDataload = new InventoryDataLoad();
inventoryDataload.setSku(item.getSku());
return inventoryDataload;
})
.collect(Collectors.toList());
If you don't have access to the classes to change the get method, you can create your own get methods:
private List<StockOrderItem> getStockOrderItems(StockOrder stockOrder) {
return stockOrder.getStockOrderItems() != null ? stockOrder.getStockOrderItems() : Collections.emptyList();
}
private List<StockOrder> getStockOrders(PurchaseOrderRepository purchaseOrderRepository, PurchaseOrder po) {
List<StockOrder> stockOrders = purchaseOrderRepository
.findByIdentifierAndBrandId(po.getPurchaseOrderIdentifier(), po.getBrandId())
.getStockOrders();
return stockOrders != null ? stockOrders : Collections.emptyList();
}
And then do the functional approach using those:
List<InventoryDataLoad> inventoryDataLoadList = getStockOrders(purchaseOrderRepository, po)
.stream()
.map(this::getStockOrderItems)
.flatMap(Collection::stream)
.map(item -> {
InventoryDataLoad inventoryDataload = new InventoryDataLoad();
inventoryDataload.setSku(item.getSku());
return inventoryDataload;
})
.collect(Collectors.toList());
EDIT: In both cases you can also improve it a little further by creating a separate method for creating the InventoryDataLoad
object, such as:
private InventoryDataLoad createInventoryDataLoad(StockOrderItem item) {
InventoryDataLoad inventoryDataload = new InventoryDataLoad();
inventoryDataload.setSku(item.getSku());
return inventoryDataload;
}
And then:
List<InventoryDataLoad> inventoryDataLoadList = getStockOrders(purchaseOrderRepository, po)
.stream()
.map(this::getStockOrderItems)
.flatMap(Collection::stream)
.map(this::createInventoryDataLoad)
.collect(Collectors.toList());
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.