Atom Feed SITE FEED   ADD TO GOOGLE READER

Bean-independent Properties

I just posted the first draft of a proposal for Bean-independent Properties for the Java language.

This started when I was CC'd on email from Mikael Grev who prefers bean-attached properties. I prefer the opposite, so I figured I'd make my preference concrete. This is quite similar to an implementation by Remi Forax, who seems like a pretty damn smart guy from what I've seen so far.

What does it look like to use?
  Customer customer = ...
String city = customer#city;
customer#city = "San Francisco";


And to declare?
  public property Property<Customer,String> city
= new BasicPropertyBuilder(property(""))
.nonNull()
.observable(##propertyChangeSupport)
.build();


Read the Full Proposal.

JSRs aren't appropriate for classlibraries

In addition to more platformey changes and language changes, the JCP develops standard classlibraries for the JDK. Let's contrast this process to open source development of classlibraries. In particular I'm thinking about libraries like binding, app frameworks, units/measures, date/time, module systems, and object-relational mapping.

Code Quality


JCP: consistently very good.
Open source: hit and miss. Some are excellent, some are trash. There's a current trend of porting or reinventing the excellent ones as JSRs.

API Stability


JCP: fixed in stone. These APIs never change. As a consequence, we're permanently stuck with every bad design decision released in a JDK.
Open source: flexible. If you're happy, you can keep your current version. If you want new features, migration to the latest and greatest may require effort.

API Choice


JCP: one-size-fits-all. Even if there are open source alternatives, the JDK API is 'standard', and not using it is an uphill battle that will require thorough justification to your team.
Open source: a marketplace. For example, there's a variety of PDF libraries for Java, each with their own relative merits.

Development Pace:


JCP: a few people work their asses off for six to twelve months and release something that meets the spec. If they missed feature you need, wait eighteen months for the next JDK.
Open source: agile. All interested parties can contribute fixes, bug reports and enhancements. If you need a missing feature, add it yourself. You can even patch your own version if necessary!

Coping with bad APIs


JCP: if the JDK includes an API I don't like, I'm pretty much stuck with it. Tough shit! We're already stuck with tons of crappy code in the JDK. Some JSRs will be flops, and we will be stuck with their code forever.
Open source: if it sucks, something better will be written. Free markets are awesome!

So...


So what's my problem? I just don't see the benefit of a giant process for writing 'blessed' libraries. Does every JRE really need a KinematicViscosity class? Why grant some libraries first-class status when we could let the market decide?

Instead, why not compliment the JCP (still great for language-type changes) with something like Perl's CPAN or Ruby's Gems? We could combine the benefits of easy access to classlibraries with the flexibility of open source libraries. We could even include ratings of APIs, so you could have confidence when choosing an API.

Series Recap: Coding in the small with Google Collections

Robert Konigsberg, Jerome Mourits and myself have written several snippets that highlight the carefully designed Google Collections Library:

Preconditions
Preconditions.checkNotNull(order.getAddress(), "order address");

Iterables.getOnlyElement
assertEquals(jesse, Iterables.getOnlyElement(usersOnDuty));

Comparators.max
return Comparators.max(perKm, minimumDeliveryCharge);

Objects.equal and hashCode
return Objects.hashCode(address, targetArrivalDate, lineItems);

Lists.immutableList
this.steps = Lists.immutableList(steps);

Objects.nonNull
his.familyName = Objects.nonNull(familyName);

Iterables.concat
for (LineItem lineItem : Iterables.concat(getPurchasedItems(), getFreeItems())) { 
...
}

Constraints.constrainedList
public void checkElement(LineItem element) { ... }

Multimap
Multimap<Salesperson, Sale> multimap 
= new ArrayListMultimap<Salesperson,Sale>();

Join
return Join.join(" and ", items);

Maps, Sets and Lists
Set<String> workdays = Sets.newLinkedHashSet(
"Monday", "Tuesday", "Wednesday", "Thursday", "Friday");

Comparators.fromFunction
return Comparators.fromFunction(new Function<Product,Money>() { ... });

BiMap
return NUMBER_TO_NAME_BIMAP.inverse().get(elementName);

ClassToInstanceMap
T result = optionalValuesByType.getInstance(type);

ImmutableSet
public static final ImmutableSet<Integer> LUCKY_NUMBERS 
= ImmutableSet.of(4, 8, 15, 16, 23, 42);

Sets.union, intersection and difference
Sets.difference(requestParameters.keySet(), LEGAL_PARAMETERS)


Get it


Consider downloading the library to put to use in your project. It will make your code more expressive!
Project downloads

More Documentation


Javadoc API
Faq
Users list
Developer list

Coding in the small with Google Collections: ClassToInstanceMap

Part 14 in a Series.

ClassToInstanceMap is a specialized Map whose keys are class literals like PizzaPromotion.class or RestockingInformation.class and whose values are instances of those types. It provides a convenient balance between type safety and model flexibility.

In some code I wrote recently, I needed to attach a RestockingInformation object to a Product without explicitly mentioning (and depending on) RestockingInformation in the Product class. I also wanted to allow other objects to be attached as necessary in the future:

Before:

public class Product {

...

private final Map<Class<?>, Optional> optionalValuesByType
= new HashMap<Class<?>, Optional>();

public <T extends Optional> void putOptional(Class<T> type, T value) {
type.cast(value); /* ensure the value is assignable to T */
optionalValuesByType.put(type, value);
}

@SuppressWarnings({"unchecked"})
public <T extends Optional> T getOptional(Class<T> type) {
return Objects.nonNull((T)optionalValuesByType.get(type));
}

@SuppressWarnings({"unchecked"})
public <T extends Optional> T getOptional(Class<T> type, T defaultValue) {
T result = (T)optionalValuesByType.get(type);
return result != null
? result
: defaultValue;
}

private interface Optional {
/* marker interface */
}
}

After:

public class Product {

...

private final ClassToInstanceMap<Optional> optionalValuesByType
= Maps.newClassToInstanceMap();

public <T extends Optional> void putOptional(Class<T> type, T value) {
optionalValuesByType.putInstance(type, value);
}

public <T extends Optional> T getOptional(Class<T> type) {
return Objects.nonNull(optionalValuesByType.getInstance(type));
}

public <T extends Optional> T getOptional(Class<T> type, T defaultValue) {
T result = optionalValuesByType.getInstance(type);
return result != null
? result
: defaultValue;
}

private interface Optional {
/* marker interface */
}
}

Class literals are ideal map keys because they already have a global namespace - Java class names are distinct! Anyone can introduce their own Optional implementation without fear of clobbering someone else's value.

Suppose the inventory team added an optional type called com.publicobject.pizza.inventory.DeliveryInfo to describe how a product is transported from the warehouse to the storefront. This doesn't prevent the customer service team from tracking a 30-minute guarantee in their own com.publicobject.pizza.customers.DeliveryInfo class. Both keys can be added to a map without clobbering each other. Using Strings for keys is not nearly as safe!

The idea of using class literals as map keys is useful everywhere, but Guice made it famous. ClassToInstanceMap makes it easy to do everywhere else.

Coding in the small with Google Collections: BiMap

Part 13 in a Series by Jerome Mourits, Guest blogger...

A BiMap is a map that supports an inverse view. If you need to map from key to value and also from value to key, then a BiMap is what you want! Note that the values of a BiMap must be unique so that the inverse view makes sense.

Before:

  private static final Map<Integer, String> NUMBER_TO_NAME;
private static final Map<String, Integer> NAME_TO_NUMBER;

static {
NUMBER_TO_NAME = Maps.newHashMap();
NUMBER_TO_NAME.put(1, "Hydrogen");
NUMBER_TO_NAME.put(2, "Helium");
NUMBER_TO_NAME.put(3, "Lithium");

/* reverse the map programatically so the actual mapping is not repeated */
NAME_TO_NUMBER = Maps.newHashMap();
for (Integer number : NUMBER_TO_NAME.keySet()) {
NAME_TO_NUMBER.put(NUMBER_TO_NAME.get(number), number);
}
}

public static int getElementNumber(String elementName) {
return NUMBER_TO_NAME.get(elementName);
}

public static string getElementName(int elementNumber) {
return NAME_TO_NUMBER.get(elementNumber);
}

After:

  private static final BiMap<Integer,String> NUMBER_TO_NAME_BIMAP;

static {
NUMBER_TO_NAME_BIMAP = Maps.newHashBiMap();
NUMBER_TO_NAME_BIMAP.put(1, "Hydrogen");
NUMBER_TO_NAME_BIMAP.put(2, "Helium");
NUMBER_TO_NAME_BIMAP.put(3, "Lithium");
}

public static int getElementNumber(String elementName) {
return NUMBER_TO_NAME_BIMAP.inverse().get(elementName);
}

public static string getElementName(int elementNumber) {
return NUMBER_TO_NAME_BIMAP.get(elementNumber);
}

Even Better:

  private static final BiMap<Integer,String> NUMBER_TO_NAME_BIMAP
= new ImmutableBiMapBuilder<Integer,String>()
.put(1, "Hydrogen")
.put(2, "Helium")
.put(3, "Lithium")
.getBiMap();
...


The Google Collections Library provides three BiMap implementations:
  • EnumBiMap is backed by EnumMaps in both directions.
  • EnumHashBiMap is backed by an EnumMap in the foward direction and a Hashmap in the inverse direction.
  • HashBiMap is backed by HashMaps in both directions.

    Part 14
  • Coding in the small with Google Collections: Comparators.fromFunction

    Part 12 in a Series.

    Comparators.fromFunction() allows you to create a Comparator based on the properties and attributes of a your business objects. Since the same function is applied to both of the values to compare, this method makes it easier to write a symmetric comparator:

    Before:

      public Comparator<Product> createRetailPriceComparator(
    final CurrencyConverter currencyConverter) {
    return new Comparator<Product>() {
    public int compare(Product a, Product b) {
    return getRetailPriceInUsd(a).compareTo(getRetailPriceInUsd(b));
    }
    public Money getRetailPriceInUsd(Product product) {
    Money retailPrice = product.getRetailPrice();
    return retailPrice.getCurrency() == CurrencyCode.USD
    ? retailPrice
    : currencyConverter.convert(retailPrice, CurrencyCode.USD);
    }
    };
    }

    After:

      public Comparator<Product> createRetailPriceComparator(
    final CurrencyConverter currencyConverter) {
    return Comparators.fromFunction(new Function<Product,Money>() {
    /** returns the retail price in USD */
    public Money apply(Product product) {
    Money retailPrice = product.getRetailPrice();
    return retailPrice.getCurrency() == CurrencyCode.USD
    ? retailPrice
    : currencyConverter.convert(retailPrice, CurrencyCode.USD);
    }
    });
    }

    This makes it easy to write expressive comparators. As a special treat, there's an overloaded version of fromFunction that lets you to specify which Comparator for ordering the function's return values. For example, null is supported with Comparators.nullGreatestOrder() as the second argument. Or put the priciest products first using Collections.reverseOrder() as the second argument.

    Part 13

    Coding in the small with Google Collections: Maps, Sets and Lists

    Part 11 in a Series by Jerome Mourits, Guest blogger...

    Generics are good, but they can be really wordy!

    Before:

    Map<CustomerId, BillingOrderHistory> customerOrderHistoryMap 
    = new HashMap<CustomerId, BillingOrderHistory>();

    After:

    Map<CustomerId, BillingOrderHistory> customerOrderHistoryMap 
    = Maps.newHashMap();
    Look Ma! I don't have to specify my type parameters twice! (The compiler figures it out through Type Inference from Assignment Context). Maps, Sets and Lists contain factory methods to create Collections objects. Here's another useful one:

    Before:

    Set<String> workdays = new LinkedHashSet<String>();
    workdays.add("Monday");
    workdays.add("Tuesday");
    workdays.add("Wednesday");
    workdays.add("Thursday");
    workdays.add("Friday");

    Or:

    Set<String> workdays = new LinkedHashSet<String>(
    Arrays.asList("Monday", "Tuesday", "Wednesday", "Thursday", "Friday"));

    After:

    Set<String> workdays = Sets.newLinkedHashSet(
    "Monday", "Tuesday", "Wednesday", "Thursday", "Friday");
    Google Collections provides factory methods for Maps, Sets, Lists, Multimaps, Multisets and other types.

    Part 12

    Coding in the small with Google Collections: Join

    Part 10 in a Series by Jerome Mourits, Guest blogger...

    Join makes it easy to join Strings separated by a delimiter.

    Before:

    public class ShoppingList {
    private List<Item> items = ...;

    ...

    public String toString() {
    StringBuilder stringBuilder = new StringBuilder();
    for (Iterator<Item> s = items.iterator(); s.hasNext(); ) {
    stringBuilder.append(s.next());
    if (s.hasNext()) {
    stringBuilder.append(" and ");
    }
    }
    return stringBuilder.toString();
    }
    }


    After:

    public class ShoppingList {
    private List<Item> items = ...;

    ...

    public String toString() {
    return Join.join(" and ", items);
    }
    }


    Easy! Join supports Iterators, Iterables, arrays and varargs. You can also have join append the tokens to a supplied Appendable, like StringBuilder.

    Part 11

    Coding in the small with Google Collections: Multimap

    Part 9 in a Series by Robert Konigsberg, Guest blogger...

    Multimap is like a Map, but lets you store multiple values for every key. It turns out this is frequently useful. Consider how often you have had to create, for instance, a Map<K, List<V>>.

    Before:

      Map<Salesperson, List<Sale>> map = new Hashmap<SalesPerson, List<Sale>>();

    public void makeSale(Salesperson salesPerson, Sale sale) {
    List<Sale> sales = map.get(salesPerson);
    if (sales == null) {
    sales = new ArrayList<Sale>();
    map.put(salesPerson, sales);
    }
    sales.add(sale);
    }

    After:

      Multimap<Salesperson, Sale> multimap 
    = new ArrayListMultimap<Salesperson,Sale>();

    public void makeSale(Salesperson salesPerson, Sale sale) {
    multimap.put(salesperson, sale);
    }


    This is just one facet of Multimaps. Consider finding the largest value across all keys:

    Before:

      public Sale getBiggestSale() {
    Sale biggestSale = null;
    for (List<Sale> sales : map.values()) {
    Sale biggestSaleForSalesman
    = Collections.max(sales, SALE_COST_COMPARATOR);
    if (biggestSale == null
    || biggestSaleForSalesman.getCharge() > biggestSale().getCharge()) {
    biggestSale = biggestSaleForSalesman;
    }
    }
    return biggestSale;
    }

    After:

      public Sale getBiggestSale() {
    return Collections.max(multimap.values(), SALE_COST_COMPARATOR);
    }


    The Google Collections Library comes with a large variety of Multimap implementations that you can choose from to meet your specific performance characteristics. Do you want to prevent duplicate key/value pairs? Use HashMultimap. Do you want to iterate over the maps in insertion-order? Use LinkedHashMultimap. Do you want the keys and values ordered by their natural ordering? Use TreeMultimap.
    Don't forget to read the Javadoc for Multimaps, which provides access to all the supplied implementations, and much more.

    Part 10

    Joel forecasts the SDK of the future...

    Joel Spolsky is generally a great writer, but he didn't do his research for today's post. He claims that with the web, JavaScript is the new assembly language: it's capable but not portable:
    [...] build a programming language, like C, that’s portable and efficient. It should compile down to “native” code (native code being JavaScript and DOMs) with different backends for different target platforms

    So far, so good. But then he goes on to describe how this strategy will take Google by surprise, leading the giant to its demise:
    Imagine, for example, that you’re Google with GMail, and you’re feeling rather smug. But then somebody you’ve never heard of, some bratty Y Combinator startup, maybe, is gaining ridiculous traction selling NewSDK, which combines a great portable programming language that compiles to JavaScript, and even better, a huge Ajaxy library that includes all kinds of clever interop features.

    Joel clearly hasn't heard of GWT. It's a complete implementation of his genius idea, and it was first released in May 2006. And its creator? Google.

    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

    Coding in the small with Google Collections: Iterables.concat()

    Part 7 in a Series.

    Iterables.concat() combines multiple iterables (such as ArrayList and HashSet) so you can go through multiple collections' elements in a single pass:

    Before:

      public boolean orderContains(Product product) {
    List<LineItem> allLineItems = new ArrayList<LineItem>();
    allLineItems.addAll(getPurchasedItems());
    allLineItems.addAll(getFreeItems());

    for (LineItem lineItem : allLineItems) {
    if (lineItem.getProduct() == product) {
    return true;
    }
    }

    return false;
    }


    After:

      public boolean orderContains(Product product) {
    for (LineItem lineItem : Iterables.concat(getPurchasedItems(), getFreeItems())) {
    if (lineItem.getProduct() == product) {
    return true;
    }
    }

    return false;
    }


    If ever you only have the Iterator and not the Iterable, the equivalent method is Iterators.concat. As a special treat, both concat methods are optimized so that they don't need a private collection.

    Part 8

    Coding in the small with Google Collections: Objects.nonNull

    Part 6 in a Series by Robert Konigsberg, Guest blogger...

    In the first episode, Jesse talked about the Preconditions class. That's not the only mechanism supplied by the Google Collections library for data validation. We're going to look at Objects.nonNull(T) and, by association, Objects.nonNull(T, String).

    Objects.nonNull accepts an object, and throws a NullPointerException if it is null. Otherwise it returns the value passed into the method.

    Objects.nonNull is wonderfully useful in constructors. Since any use of super in a constructor must be the first statement in the method body, Preconditions can't be used. before the superclass initialization. The Precondition can be used after the superclass initialization, but that doesn't work very well; it forces initialization prior to validation, and besides, Preconditions have a semantic inference; they're meant to be used as pre-conditions, not post-conditions.

    Before:

    public ConnectAction extends Action {
    private final Connector connector;
    public ConnectAction(ContextManager mgr, Connector connector) {
    super(mgr);
    Preconditions.checkNotNull(mgr);
    this.connector = connector;
    }
    public void run(ActionArguments args) { ... }
    }

    After:

    public ConnectAction extends Action {
    private final Connector connector;
    public ConnectAction(ContextManager mgr, Connector connector) {
    super(Objects.nonNull(mgr));
    this.connector = connector;
    }
    public void run(ActionArguments args) { ... }
    }
    See? Objects.nonNull operate like a filter within an expression, whereas Preconditions do not.

    Objects.nonNull also works well when supplying a large number of arguments:

    Before:

    public Person(String givenName, String familyName, Address address, Phone phone, String email) {
    Preconditions.checkNotNull(givenName);
    Preconditions.checkNotNull(familyName);
    Preconditions.checkNotNull(address);
    Preconditions.checkNotNull(phone);
    Preconditions.checkNotNull(email);

    this.givenName = givenName;
    this.familyName = familyName;
    this.address = address;
    this.phone = phone;
    this.email = email;
    }

    After:

    public Person(String givenName, String familyName, Address address, Phone phone, String email) {
    this.givenName = Objects.nonNull(givenName);
    this.familyName = Objects.nonNull(familyName);
    this.address = Objects.nonNull(address);
    this.phone = Objects.nonNull(phone);
    this.email = Objects.nonNull(email);
    }

    Another interesting use of Objects.nonNull is as a post-condition operator:

    Before:

    public V get(K key) {
    V value = map.get(key);
    if (value == null) {
    throw new NullPointerException();
    } else {
    return value;
    }
    }

    After:

    public V get(K key) {
    return Objects.nonNull(map.get(key));
    }

    So, when should you use Preconditions.checkNotNull and Objects.nonNull? There's a soft answer: see what feels right. You're a smart programmer, I'm sure.

    Part 7

    Coding in the small with Google Collections: ImmutableList.copyOf

    Part 5 in a Series.

    ImmutableList.copyOf() creates an immutable copy of it's arguments as a List. Wherever your code stores a List parameter, it may need an immutable copy. With the JDK, coping and preventing modification requires two steps. Lists.immutableList simplifies this code:

    Before:

      public Directions(Address from, Address to, List<Step> steps) {
    this.from = from;
    this.to = to;
    this.steps = Collections.unmodifiableList(new ArrayList<Step>(steps));
    }


    After:

      public Directions(Address from, Address to, List<Step> steps) {
    this.from = from;
    this.to = to;
    this.steps = ImmutableList.of(steps);
    }


    As usual with Google Collections, all the expected overloadings are available. There's versions that accept Iterable, Iterator, and varargs/arrays. As a special treat, there's even an overloading that takes zero parameters which allows you to add and remove elements freely without changing the signature.

    Part 6

    Coding in the small with Google Collections: Objects.equal and hashCode

    Part 4 in a Series.

    Objects.equal(Object,Object) and Objects.hashCode(Object...) provide built-in null-handling, which makes implementing your own equals() and hashCode() methods easy.

    Before:

      public boolean equals(Object o) {
    if (o instanceof Order) {
    Order that = (Order)o;

    return (address != null
    ? address.equals(that.address)
    : that.address == null)
    && (targetArrivalDate != null
    ? targetArrivalDate.equals(that.targetArrivalDate)
    : that.targetArrivalDate == null)
    && lineItems.equals(that.lineItems);
    } else {
    return false;
    }
    }

    public int hashCode() {
    int result = 0;
    result = 31 * result + (address != null ? address.hashCode() : 0);
    result = 31 * result + (targetArrivalDate != null ? targetArrivalDate.hashCode() : 0);
    result = 31 * result + lineItems.hashCode();
    return result;
    }


    After:

      public boolean equals(Object o) {
    if (o instanceof Order) {
    Order that = (Order)o;

    return Objects.equal(address, that.address)
    && Objects.equal(targetArrivalDate, that.targetArrivalDate)
    && Objects.equal(lineItems, that.lineItems);
    } else {
    return false;
    }
    }

    public int hashCode() {
    return Objects.hashCode(address, targetArrivalDate, lineItems);
    }


    This is much more concise than handwritten or IDE-generated code. As a special treat, there's deepEquals and deepHashcode methods that 'do the right thing' for arrays and nested arrays, that otherwise use identity for equals and hashCode.

    Part 5

    Coding in the small with Google Collections: Comparators.max

    Part 3 in a Series.

    Comparators.max takes two Comparables and returns the larger of the two. It improves upon the standard approach, which requires both a comparison and a ternary:

    Before:


    public Money calculateDeliveryCharge(Order order) {
    double distanceInKm = Geography.getDistance(
    storeAddress, order.getAddress());
    Money perKm = pricePerKm.times(distanceInKm);

    return perKm.compareTo(minimumDeliveryCharge) > 0
    ? perKm
    : minimumDeliveryCharge;

    }


    After:


      public Money calculateDeliveryCharge(Order order) {
    double distanceInKm = Geography.getDistance(
    storeAddress, order.getAddress());
    Money perKm = pricePerKm.times(distanceInKm);

    return Comparators.max(perKm, minimumDeliveryCharge);
    }


    Of course the Comparators.min method is also included. As a special treat, there's overloaded versions of each that allow you to specify your own comparator, such as String.CASE_INSENSITIVE_ORDER.

    Part 4

    Coding in the small with Google Collections: Iterables.getOnlyElement

    Part 2 in a Series.

    Iterables.getOnlyElement makes sure your collection or iterable contains exactly one element, and returns that. If it contains 0 or 2+ elements, it throws a RuntimeException. This comes up often in unit tests:

    Before:

      public void testWorkSchedule() {
    workSchedule.scheduleUserOnDuty(jesse, mondayAt430pm, mondayAt1130pm);

    Set<User> usersOnDuty = workSchedule.getUsersOnDuty(mondayAt800pm);
    assertEquals(1, usersOnDuty.size());
    assertEquals(jesse, usersOnDuty.iterator().next());
    }


    After:

      public void testWorkSchedule() {
    workSchedule.scheduleUserOnDuty(jesse, mondayAt430pm, mondayAt1130pm);

    Set<User> usersOnDuty = workSchedule.getUsersOnDuty(mondayAt800pm);
    assertEquals(jesse, Iterables.getOnlyElement(usersOnDuty));
    }


    Iterables.getOnlyElement() describes intent more directly than Set.iterator().next() and List.get(0). As a special treat, there's an overloaded version to use if your Iterable might be empty.

    Part 3

    Coding in the small with Google Collections: Preconditions

    Part 1 in a Series.

    In this N-part series, I'll demonstrate my favourite APIs from the recently announced Google Collections project. I'll present before and after examples that show how you can use Google Collections to write more concise code.

    Preconditions provides methods for state validation. It makes input validation compact enough that you'll always want to do it! And unlike Java's built-in assert, Preconditions is always enabled.

    Before:

      public Delivery createDelivery(Order order, User deliveryPerson) {
    if(order.getAddress() == null) {
    throw new NullPointerException("order address");
    }
    if(!workSchedule.isOnDuty(deliveryPerson, order.getArrivalTime())) {
    throw new IllegalArgumentException(
    String.format("%s is not on duty for %s", deliveryPerson, order));
    }

    return new RealDelivery(order, deliveryPerson);
    }


    After:

      public Delivery createDelivery(Order order, User deliveryPerson) {
    Preconditions.checkNotNull(order.getAddress(), "order address");
    Preconditions.checkArgument(
    workSchedule.isOnDuty(deliveryPerson, order.getArrivalTime()),
    "%s is not on duty for %s", deliveryPerson, order);

    return new RealDelivery(order, deliveryPerson);
    }


    In addition to a constraint check, Preconditions also works as programmer documentation. When the code is under maintenance, the original author's expectations are right in the code where they belong. As a special treat, Preconditions throws detailed error messages that include the offending line of code.

    Part 2

    ListDeltas and the next generation of observable lists

    Yesterday afternoon I had a great technical discussion with Joshua Bloch, a very highly respected API designer. We met to talk about something that's very close to my heart, observable lists. We explored this problem with a whiteboard and some code samples and came up with some interesting observations...

    1. Deltas are useful beyond observers
    Actually this was Zorzella's idea. Modeling changes between two lists has some interesting applications:
  • for history management: the history of a list can be stored as a series of deltas.
  • for networking: applications can exchange deltas rather than full copies of lists.
  • for branching and merging: to view and display the conflicts between different revisions of the same source.

    2. A list delta is composed of primitives
    Any delta can be expressed as a series of the following operations:
  • add a single element at some index
  • remove a single element at some index
  • replacing the element at some index with a different element
  • moving an element from one index to another

    3. There exists multiple deltas to go from any pair of lists A and B.
    Suppose we have lists L1 = { A, B, C } and L2 = { A, C, B }. The change can be expressed as { move "B" at 1 to 2 } or { move "C" at 2 to 1 } or even { remove "B" at 1, add "B" at 2 }.

    4. There exists some canonical form for a list delta
    Suppose we have a delta describing these changes: { remove D at 3, remove B at 1 }. When applied to the list { A, B, C, D, E } the end result is { A, C, E }. But the same change can also be expressed as { remove B at 1, remove D at 2 }. In the canonical form, the indices of changes are listed in non-decreasing order. This applies to everything but move events, for which I'm not yet sure what the orders are. I also don't know if the canonical forms are unique.

    5. The canonical form of a list delta may be smaller
    Natural list deltas can contain redundancy. For example { insert D at 2, insert B at 1, remove D at 3 }. The canonical form of this change is simply { insert B at 1 }, since D is inserted only to be later removed. Note that we now know less about the change. We no longer know about D. The canonical form loses the order that the changes were performed in. A nice analog to this is the duality between Collections.shuffle() and Collections.sort().

    7. Deltas are reversible
    The reverse of { remove B at 1, remove D at 2 } is { insert D at 2, insert B at 1 }. The canonical form of the reversal is { insert B at 1, insert D at 3 }. To reverse a change, reverse each operation and reverse the series.

    8. Deltas can be split and joined
    Suppose we have the following: Lists L1, L2, L3 and Deltas D1, D2, such that applying D1 to L1 gives D2, and applying D2 to L2 gives L3. Naturally we can concatenate deltas D1 and D2 to create delta D12. Naturally, applying D12 to L1 returns L3. As a consequence of point 5, the canonical form of D12, which I'll call D12', may be smaller than the sum of D1 and D2.

    Most of this knowledge exists deep in the Glazed Lists codebase, but this discussion really helped me to distill the problem domain to its primitives. I'm going to revise my original proposal so it treats ListDeltas as first-class objects and makes these functions available.