Master Java Callbacks & Functional Programming: Write Elegant, Structured Code Beyond CRUD

This article explains Java callback mechanisms — synchronous and asynchronous — through interfaces, anonymous classes, lambdas, and CompletableFuture, demonstrates their use in Spring's BeanFactory and a payment integration, and shows how functional interfaces enable flexible data transformation for multi-bank integration.

ITPUB
ITPUB
ITPUB
Master Java Callbacks & Functional Programming: Write Elegant, Structured Code Beyond CRUD

1. Overview

A callback is a programming pattern where a function passes another function as an argument to be invoked upon task completion or specific events. It enables asynchronous operations, event-driven programming, and improves code extensibility, flexibility, and modularity.

2. Callback Structure and Roles

2.1 What Is a Callback

The callback mechanism registers a method ( callback()) from Class A into Class B. When Class A calls methodB() on Class B, Class B later invokes the registered callback(), creating a bidirectional call: A → B → A.

Callbacks are classified as:

Synchronous callback : executed immediately during the caller's execution, no threading involved.

Asynchronous callback : invoked after a background task finishes (e.g., network request, file I/O), often on a different thread.

2.2 Three Parts of a Callback

Callback registration : passing the callback function as a parameter.

Task execution : the main function performs its work (sync or async).

Callback invocation : after completion, the callback is called with success or error data.

2.3 Roles

Event-driven programming (button clicks, page load).

Asynchronous handling (non-blocking result/error processing).

Modularity: decouples tasks via separate callback handlers.

3. Implementation Ways in Java

3.1 Via Interface

Define a callback interface with a method (e.g., onComplete(String)), accept it in a task class, and invoke it upon completion. The example uses an anonymous inner class to implement the interface.

// 1. Define callback interface
interface Callback {
    void onComplete(String result);
}

// 2. Business logic class accepting callback
class Task {
    public void execute(Callback callback) {
        String result = "Task Completed!";
        callback.onComplete(result);
    }
}

// 3. Usage with anonymous class
public class CallBackTest {
    public static void main(String[] args) {
        Task task = new Task();
        task.execute(new Callback() {
            @Override
            public void onComplete(String result) {
                System.out.println("Callback received: " + result);
            }
        });
    }
}

3.2 Via Lambda Expression (Java 8+)

For single-method interfaces (functional interfaces), lambdas simplify the syntax:

public class CallBackTest {
    public static void main(String[] args) {
        Task task = new Task();
        task.execute(result -> System.out.println("Callback received: " + result));
    }
}

3.3 Asynchronous Callback with CompletableFuture

Java's CompletableFuture enables async callbacks. The example simulates a 2-second task:

import java.util.concurrent.CompletableFuture;

interface Callback {
    void onComplete(String result);
}

class AsyncTask {
    public void executeAsync(Callback callback) {
        CompletableFuture.supplyAsync(() -> {
            try { Thread.sleep(2000); } catch (InterruptedException e) { }
            return "Task Completed!";
        }).thenAccept(callback::onComplete);
    }
}

public class CallBackTest {
    public static void main(String[] args) {
        AsyncTask task = new AsyncTask();
        task.executeAsync(result -> System.out.println("Async callback received: " + result));
        System.out.println("Main thread continues executing...");
    }
}
supplyAsync

runs the task asynchronously; thenAccept registers the callback; the main thread proceeds without waiting.

3.4 Payment Async Callback (Architecture Level)

In third-party payment integration, the merchant registers a notify URL (callback endpoint) with the payment platform. After payment, the platform POSTs the result to that URL. The Spring controller example shows: /create initiates payment, passing notifyUrl from config. /notify receives the async notification and delegates to payService.asyncNotify().

Config snippet (YAML) includes notifyUrl for WeChat Pay and Alipay.

4. Callback in Spring Framework

Spring's BeanFactory uses callbacks internally. The core method doGetBean() calls getSingleton(beanName, () -> createBean(...)). The second argument is an ObjectFactory functional interface. Inside getSingleton(), the callback is invoked via singletonFactory.getObject(), which executes createBean(). This demonstrates functional-style callback for lazy singleton creation with proper locking and lifecycle callbacks ( beforeSingletonCreation, afterSingletonCreation).

public Object getSingleton(String beanName, ObjectFactory<?> singletonFactory) {
    synchronized (this.singletonObjects) {
        Object singletonObject = this.singletonObjects.get(beanName);
        if (singletonObject == null) {
            beforeSingletonCreation(beanName);
            try {
                singletonObject = singletonFactory.getObject(); // callback invokes createBean()
                newSingleton = true;
            } finally {
                afterSingletonCreation(beanName);
            }
            if (newSingleton) addSingleton(beanName, singletonObject);
        }
        return singletonObject;
    }
}

5. Practical Business Example: Multi-Bank Data Transformation

Problem: different banks provide credit data in varying formats. Hard-coding per bank leads to duplication. Solution: extract the transformation step into a functional interface DataTransformer<T, R> with a single method R transform(T input). A generic DataProcessor accepts data and a transformer, applying it via lambda or method reference.

@FunctionalInterface
public interface DataTransformer<T, R> {
    R transform(T input);
}

public class DataProcessor<T, R> {
    public R processData(T data, DataTransformer<T, R> transformer) {
        return transformer.transform(data);
    }
}

// Usage examples
public static void main(String[] args) {
    // Example 1: String -> Integer (length)
    Integer length = DataProcessor.processData("Hello", String::length);
    System.out.println(length); // 5

    // Example 2: Person -> Student via method reference
    Person person = new Person();
    person.setName("zhang san");
    person.setAge(18);
    Student student = DataProcessor.processData(person, DataProcessor::convertToStudent);
    System.out.println(student);
}

private static Student convertToStudent(Person person) {
    Student student = new Student();
    student.setName(person.getName());
    student.setAge(person.getAge());
    return student;
}

This approach lets each bank provide its own transformer lambda, keeping the core pipeline unchanged.

6. Summary

Java callbacks, implemented via interfaces, anonymous classes, lambdas, and CompletableFuture, enable asynchronous, decoupled, and modular code. They appear in framework internals (Spring's singleton creation) and real-world architectures (payment notifications). Functional interfaces combined with lambdas provide a clean way to parameterize behavior, as shown in the multi-bank data transformation case, turning repetitive CRUD-like code into elegant, reusable pipelines.

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.

Design PatternsJavaLambdaCompletableFutureFunctional ProgrammingCallbackdata transformationSpring Framework
ITPUB
Written by

ITPUB

Official ITPUB account sharing technical insights, community news, and exciting events.

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.