First Past the Post

Often, we write code to work out the first answer of a bunch of available ones. Let’s look at that in Java.

public Widget getAppropriateWidget(CustomerRequest request) {
    if (shelfstock.contains(request.getBarcode()) {
        return new ShelfWidget();
    }
    if (backroomStock.contains(request.getBarcode()) {
        return new BackroomWidget();
    }
    if (supplier.contains(request.getEan()) {
        return new SupplierWidget();
    }
    return null;
}

You’ll have to imagine the more complex scenario, hiding behind the above simplified code. What this algorithm does is try options in order of priority until it finds one that works, or it fails, in which case it returns nothing.

Let’s also imagine that the calls to contains are expensive for some reason – perhaps each of these objects is hiding a webservice, or complex database query.

Let’s start out by refactoring the above code two ways. Let’s make it use Optional, and let’s make it use subroutines for each of the methods.

public Optional<Widget> getAppropriateWidget(CustomerRequest request) {
    Optional<Widget> shelfWidget = 
        getShelfWidget(request);
    if (shelfWidget.isPresent()) {
        return shelfWidget;
    }
    Optional<Widget> backroomWidget = 
        getBackroomWidget(request);
    if (backroomWidget.isPresent()) {
        return backroomWidget;
    }
    Optional<Widget> supplierWidget = 
        getSupplierWidget(request);
    if (supplierWidget.isPresent()) {
        return supplierWidget;
    }
    return Optional.empty;
}

// imagine the subsidiary functions

So, this is sort of better than null being the return for not found and is trying hard to use subroutines to make this function describe itself, but it’s having trouble with the fact that each of the Optional objects returned can’t be chained into a chain of responsibility.

We could cheat:

Optional<Widget> shelfWidget = getShelfWidget(request);
Optional<Widget> backroomWidget = getBackroomWidget(request);
Optional<Widget> supplierWidget = getSupplierWidget(request);

return firstNonEmpty(shelfWidget, backroomWidget, supplierWidget);

private static Optional<Widget> firstNonEmpty(
            Optional<Widget> ... options) {
    return Arrays.stream(options)
        .filter(Optional::isPresent)
        .findFirst() // makes an optional of optional here...
        .orElse(Optional.empty());
}

The above code is sort of better but now has to pre-calculate all possible answers before selecting one. We need to be able to avoid costly option calculation if the answer is available sooner.

The First Past the Post with Optionals Solution

Pass either a stream or varargs array to a function, formed of objects that will supply an optional. If any of them supplies a non-empty then it wins.

// calling code
public Optional<Widget> getAppropriateWidget(CustomerRequest request) {
    return firstAvailable(() -> getShelfWidget(request),
        () -> getBackroomWidget(request),
        () -> getSupplierWidget(request));
}

// this is a general purpose solution
// feel free to use it
@SafeVarargs
private static <T> Optional<T> firstAvailable(
        Supplier<Optional<T>> ... options) {
    return Arrays.stream(options)
            .map(Supplier::get)
            .filter(Optional::isPresent)
            .findFirst()
            .orElse(Optional.empty());
}

3 comments

  1. Aye, good one Ashley. That findFirst injection is gold, taking advantage of the laziness of the Stream API.

    A variation on that theme is to use the functions directly. The various getXxxWidget functions have the same shape as thegetAppropriateWidget function so we can pass a list of ’em and say “flow the same input through each.”

    
    private static Optional getAppropriateWidget(CustomerRequest request) {
        return firstAvailable(
        	asList(getShelfWidget, getBackroomWidget, getSupplierWidget),
        	request
        );
    }
    
    private static  Optional firstAvailable(
        List<Function<I, Optional>> options, I input) {
    
        return options.stream()
                .map(option -> option.apply(input))
                .filter(Optional::isPresent)
                .findFirst()
                .orElse(Optional.empty());
    }
    
    
    
    				
    • Hey Rich – it’s a good point, and a refactoring I’ve done a few times in JavaScript. Can Java support this syntax like this these days?

      Perhaps I’m misreading the absence of the method reference syntax as an intentional thing on your part.

  2. Ha, I omitted the explicit method reference syntax ‘cos it was noisy… and then WordPress hosed the code block anyway because of the angle brackets in the generics.

    Aye, you still need the method reference syntax bobbins in Java.

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Google photo

You are commenting using your Google account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s