Coding in the small with Google Collections: Constraints.constrainedList
Part 8 in a Series.Constraints.constrainedList allows you to enforce rules about what can be added to a List instance. By letting the List manage its constraints, your API users get instant feedback if they insert invalid values. It also allows you to expose convenient methods like addAll() and set() without writing additional code:
Before:
private final List<LineItem> purchases = new ArrayList<LineItem>();
/**
* Don't modify this! Instead, call {@link #addPurchase(LineItem)} to add
* new purchases to this order.
*/
public List<LineItem> getPurchases() {
return Collections.unmodifiableList(purchases);
}
public void addPurchase(LineItem purchase) {
Preconditions.checkState(catalog.isOffered(getAddress(), purchase.getProduct()));
Preconditions.checkState(purchase.getCharge().getUnits() > 0);
purchases.add(purchase);
}
...
public static Order createGreyCupSpecialOrder(Customer customer) {
Order order = new Order(customer);
for (LineItem lineItem : GREY_CUP_SPECIAL_ITEMS) {
order.addPurchase(lineItem);
}
return order;
}
After:
private final List<LineItem> purchases = Constraints.constrainedList(
new ArrayList<LineItem>(),
new Constraint<LineItem>() {
public void checkElement(LineItem element) {
Preconditions.checkState(catalog.isOffered(getAddress(), element.getProduct()));
Preconditions.checkState(element.getCharge().getUnits() > 0);
}
});
/**
* Returns the modifiable list of purchases in this order.
*/
public List<LineItem> getPurchases() {
return purchases;
}
...
public static Order createGreyCupSpecialOrder(Customer customer) {
Order order = new Order(customer);
order.getPurchases().addAll(GREY_CUP_SPECIAL_ITEMS);
return order;
}
This new code is both more robust and more convenient. Possibly the most common constraint, NOT_NULL is provided to make that easy. And as a special treat, there's constraint factory methods for Sets, Maps and the supplementary collections.
Part 9