Reactive Programming is a programming paradigm focused on asynchronous data streams and the propagation of change. It’s all about reacting to data as it comes in — like events, user interactions, or data updates — and building systems that respond to these changes automatically and efficiently.
🔹 Core Concepts:
- Observables / Streams: Sequences of data/events over time.
- Observers / Subscribers: React to new data or changes.
- Operators: Transform, combine, filter, or debounce data streams.
- Backpressure: Handle data flow control when consumers are slower than producers.
✅ Example Use Cases:
- UI updates based on user input (e.g., search-as-you-type).
- Real-time systems (chat apps, financial tickers).
- Event-driven microservices.
🛠 Common Libraries:
- RxJava (Java)
- Reactor (Spring ecosystem)
- RxJS (JavaScript)
- Combine (Swift)
🔃 What is Procedural Programming?
Procedural Programming is a programming paradigm based on a sequence of steps or procedures (functions). It focuses on how to achieve a task through a linear series of commands and logic blocks.
🔹 Core Concepts:
- Functions (procedures) and structured flow (if, loops, etc.)
- Top-down approach: execute code step by step.
- Mutation of variables and explicit state management.
✅ Example Use Cases:
- Scripting tasks
- Batch processing
- System-level programming (e.g., C-based applications)
🛠 Common Languages:
- C
- Pascal
- Early Java without reactive extensions
🔍 Key Differences at a Glance:
| Aspect | Reactive Programming | Procedural Programming |
|---|---|---|
| Focus | Asynchronous data flow and event reaction | Step-by-step task execution |
| Data Flow | Push-based, streams of data | Pull-based, function calls and returns |
| Control Flow | Event-driven, declarative | Linear, imperative |
| Concurrency | Built-in (e.g., RxJava handles async by default) | Manual (e.g., threads, futures) |
| State Handling | Immutable, state flows through streams | Often mutable, state changes explicitly |
| Examples | Auto-complete search, real-time updates | Calculator logic, file processing scripts |
🧠 Analogy:
- Procedural is like a recipe: do step 1, then step 2, and so on.
- Reactive is like a chef cooking while listening to multiple timers and ingredients arriving — constantly adapting based on inputs.
Example
🧪 Scenario:
You have a list of integers. You want to:
- Filter even numbers.
- Double them.
- Print each result.
🔧 Procedural Style (Plain Java)
import java.util.Arrays;
import java.util.List;
public class ProceduralExample {
public static void main(String[] args) {
List<Integer> numbers = Arrays.asList(1, 2, 3, 4, 5, 6);
for (Integer number : numbers) {
if (number % 2 == 0) {
int doubled = number * 2;
System.out.println(doubled);
}
}
}
}
✅ Characteristics:
- Step-by-step logic.
- Loops and conditions used explicitly.
- Synchronous processing.
⚡️ Reactive Style (RxJava)
import io.reactivex.rxjava3.core.Observable;
public class ReactiveExample {
public static void main(String[] args) {
Observable<Integer> numbers = Observable.just(1, 2, 3, 4, 5, 6);
numbers
.filter(n -> n % 2 == 0)
.map(n -> n * 2)
.subscribe(System.out::println);
}
}
✅ Characteristics:
- Stream of data using
Observable. - Declarative chaining of operations:
filter, thenmap, thensubscribe. - Asynchronous and reactive by nature (though this example runs synchronously for simplicity).
- You don’t control the loop — RxJava handles data flow.
🧠 Extra Thoughts:
- In real-world RxJava, you often deal with data from a database, network, or UI events, and not just static lists.
- RxJava makes it easy to handle errors, retry, debounce, throttle, and combine streams — which is much harder with plain Java.
🧪 1. Debounced Search Input (like “search-as-you-type”)
Imagine a user types in a search box, and we want to:
- Wait until the user pauses (e.g. 300ms).
- Only then trigger a search request.
- Cancel previous search if new input comes in.
import io.reactivex.rxjava3.core.Observable;
import io.reactivex.rxjava3.schedulers.Schedulers;
import java.util.concurrent.TimeUnit;
public class DebouncedSearch {
public static void main(String[] args) throws InterruptedException {
Observable<String> userTyping = Observable
.just("S", "St", "Sta", "Stan", "Stanl", "Stanley")
.concatMap(s -> Observable.just(s).delay(100, TimeUnit.MILLISECONDS));
userTyping
.debounce(300, TimeUnit.MILLISECONDS)
.observeOn(Schedulers.io())
.subscribe(searchTerm -> System.out.println("Searching for: " + searchTerm));
Thread.sleep(2000); // keep main thread alive
}
}
✅ Result:
Only "Stanley" is printed after the user finishes typing.