Functional Programming: Using BiFunction to Eliminate Repetitive Multi‑Type Branches

The article shows how a Java 14 switch expression combined with a BiFunction and method references can replace duplicated if‑else branches in inventory‑change code, reducing maintenance effort and lowering the risk of missed updates when new types are added.

samdeepthink
samdeepthink
samdeepthink
Functional Programming: Using BiFunction to Eliminate Repetitive Multi‑Type Branches

In a production inventory‑report module there are three change types—opening, in‑transit, and received—each with its own update method ( updateOpeningInventory, updateInTransitInventory, updateReceivedInventory) on DailyInventoryRecord. Both the "add new record" and the "update existing record" paths contain identical if‑else chains that select the proper method based on the type.

Problem

The duplicated conditional logic means that adding a new type requires changes in two separate places, increasing the chance of forgetting one of them.

Solution: switch expression + BiFunction + method reference

Java 8’s BiFunction (in java.util.function) accepts two arguments and returns a result. The update methods all have the signature

(DailyInventoryRecord, InventoryChangeParam) → DailyInventoryRecord

, so they match the generic type

BiFunction<DailyInventoryRecord, InventoryChangeParam, DailyInventoryRecord>

.

BiFunction<DailyInventoryRecord, InventoryChangeParam, DailyInventoryRecord> fn =
    switch (type) {
        case TYPE_OPENING   -> DailyInventoryRecord::updateOpeningInventory;
        case TYPE_IN_TRANSIT -> DailyInventoryRecord::updateInTransitInventory;
        case TYPE_RECEIVED -> DailyInventoryRecord::updateReceivedInventory;
    };

The switch expression (Java 14) maps each enum value to an unbound method reference; the compiler treats the target object as the first argument, yielding the required BiFunction instance.

With fn defined, both the add‑new and update paths call fn.apply(...) directly, eliminating all if‑else statements.

// Build new records
private List<DailyInventoryRecord> buildNewRecords(
        BiFunction<DailyInventoryRecord, InventoryChangeParam, DailyInventoryRecord> fn,
        Set<String> newMaterialCodes,
        Map<String, InventoryChangeParam> paramMap) {
    return newMaterialCodes.stream().map(code -> {
        DailyInventoryRecord record = new DailyInventoryRecord(code);
        return fn.apply(record, paramMap.get(code));
    }).toList();
}
// Update existing records
for (DailyInventoryRecord record : existingRecords) {
    fn.apply(record, paramMap.get(record.getMaterialCode()));
}

All type‑checking logic is now centralized in the single switch that creates fn. The calling code no longer contains any branching.

Preconditions

The methods assigned to the BiFunction must have identical parameter counts, parameter types, and return type. If any method’s signature differs, the generic constraints of BiFunction will cause a compile‑time error, and the pattern should not be forced.

Before‑after comparison

Type‑checking code : duplicated if‑else in each path → single switch expression.

Places to modify when adding a type : two separate edits → one edit inside the switch.

Risk of missed updates : high (easy to forget one branch) → low (only one entry point).

Calling code : contains branching logic → unified call to fn.apply() with no branches.

The decision rule is simple: if the methods in the branches share the same signature, use a functional interface like BiFunction; otherwise keep the explicit if‑else.

Conclusion

Java’s built‑in functional interfaces are most useful when they can collapse "same structure, different method" repetitions. The key is to recognize when method signatures align; then a BiFunction (or Consumer, Function, etc.) can replace scattered conditionals, making the codebase cleaner and less error‑prone.

Original Source

Signed-in readers can open the original source through BestHub's protected redirect.

Sign in to view source
Republication Notice

This article has been distilled and summarized from source material, then republished for learning and reference. If you believe it infringes your rights, please contactadmin@besthub.devand we will review it promptly.

javafunctional programmingSwitch ExpressionMethod ReferenceBiFunction
samdeepthink
Written by

samdeepthink

Knowledge Planet: Old Dock's Tech Chronicles Zhihu: SamDeepThinking A technical manager who still codes heavily on the front line. From junior developer to tech lead, then tech manager, now leading the whole front‑ and back‑end development team—leveling up along the way. I have some insights on programming, career development, and tech management.

0 followers
Reader feedback

How this landed with the community

Sign in to like

Rate this article

Was this worth your time?

Sign in to rate
Discussion

0 Comments

Thoughtful readers leave field notes, pushback, and hard-won operational detail here.