Java-8 (The Biggest Transformation)
Source: Dev.to
Lambda Expressions (Part 1)
In Java, writing even a small piece of logic used to be lengthy because we had to create an anonymous class and override its method every single time. Java 8 solved this problem by introducing lambda expressions — a short, clean, functional‑style way to write code.
Basic Syntax
// No‑parameter lambda
() -> System.out.println("HI");
// Single‑parameter lambda
x -> x * x;
// Two‑parameter lambda
(x, y) -> x * y;
// Lambda with a block body
x -> {
int y = x + 1;
return y;
};
// No‑parameter lambda with a block body
() -> {
System.out.println("HI");
}
Before Java 8
new Thread(new Runnable() {
@Override
public void run() {
System.out.println("Running");
}
}).start();
After Java 8
new Thread(() -> System.out.println("Running")).start();
Capturing Variables
Rule: A captured variable must be effectively final.
int processedCount = 0;
orders.forEach(order -> {
processedCount++; // ❌ ERROR
});
Local variable
processedCountdefined in an enclosing scope must be final or effectively final.
Fix 1: Use AtomicInteger
AtomicInteger processedCount = new AtomicInteger(0);
orders.forEach(order -> {
processedCount.incrementAndGet(); // ✔ Works
});
System.out.println(processedCount.get());
AtomicInteger is an object; the reference is final, but its internal value can change.
Fix 2: Use an array wrapper
int[] processedCount = {0};
orders.forEach(order -> {
processedCount[0]++; // ✔ Works
});
The array reference is final, while its elements can be mutated.
Fix 3: Use Stream count
long processedCount = orders.stream().count();
Hope this helped you understand Java 8 better. In the next blog, we dive into Collections in Java 8—don’t miss it!