flatMap in Depth The Collectors API covers perhaps 90% of real-world aggregation needs, but the moment you need something beyond grouping, partitioning, or joining, the custom Collector is there. Understanding flatMap and the full Collectors toolkit — including when to write your own — separates competent Java 8 developers from those who still reach for a for loop whenever a problem gets slightly unusual. flatMap is the most powerful transformation in the Streams API.
Continue reading »Java 8 Tutorial
16 posts in this section
Collections and Map Enhancements: forEach, merge, compute, replaceAll
Overview Java 8 didn’t just add Streams — it also enhanced the existing Iterable, Collection, List, and Map interfaces with default methods that cover the most common imperative patterns. Understanding these methods lets you write cleaner code even without streams. The three methods worth memorising immediately are computeIfAbsent (the most useful new Map method), merge (for accumulation patterns), and removeIf (eliminating the iterator-based removal pattern). Together they eliminate the most common sources of verbose boilerplate in collection-heavy code.
Continue reading »CompletableFuture: Async Pipelines and Non-Blocking Composition
The Problem with Future<T> Fetching a product page on an e-commerce site requires at least three data sources: product details, live pricing, and inventory availability. Done sequentially, a 200 ms call to each service adds up to 600 ms. Done in parallel with a properly composed CompletableFuture pipeline, the wall-clock time drops to roughly the slowest of the three — around 200 ms. This article shows exactly how to build that pipeline and everything else you need to write robust async code in Java 8.
Continue reading »Date and Time API (JSR-310): LocalDate, ZonedDateTime, Duration, Period
Why java.util.Date Had to Go If you have ever tracked down a bug caused by a SimpleDateFormat shared across threads, or spent an afternoon understanding why a Calendar.get(Calendar.MONTH) returns 0 for January, you will appreciate why JSR-310 was one of the most eagerly anticipated Java 8 features. The new java.time API is not a patch on the old API — it is a complete redesign that makes an entire class of date and time bugs impossible by construction.
Continue reading »Default and Static Interface Methods: Backwards-Compatible API Evolution
The Problem: Evolving Interfaces Without Breaking Implementations Default methods solved a problem that had blocked the Java Collections team from improving the core APIs for years: how do you add methods to an interface without breaking every existing implementation? The answer Java 8 gave — concrete implementations on the interface itself — has wider implications than just Collection.stream(). It is the mechanism behind the fluent Comparator API, the Predicate composition methods, and the design pattern of composable interface contracts.
Continue reading »Functional Interfaces: Predicate, Function, Supplier, Consumer, and More
What Is a Functional Interface? Functional interfaces are the type system bridge that makes lambda expressions work in Java 8. Without them, the compiler would have no way to know what type to assign to a lambda. Once you understand how the 43 built-in interfaces in java.util.function are organised — and when to write your own — you will find that the same patterns (compose, chain, validate, transform) appear everywhere in a Java 8 codebase.
Continue reading »Java 8 Best Practices and Patterns for Production Code
Introduction Java 8 introduced a fundamentally different programming model. The features — lambdas, streams, Optional, CompletableFuture — interact with each other in ways that produce clean, readable code when used correctly and confusing, brittle code when used incorrectly. This article consolidates the most important production-ready guidance from across the series into a single reference, along with the migration checklist for moving a Java 7 codebase to Java 8. Streams Best Practices Do: Use streams for transformations and aggregations // Good: filter → transform → collect List<String> premiumNames = customers.
Continue reading »Java 8 Overview: The Release That Changed Everything
Before We Start — Feel the Difference You’re about to learn Java 8. Before diving into history and theory, let’s just feel what changed. Here’s the same task written in Java 7 and Java 8: Task: Find all names that start with “A”, uppercase them, sort them, and collect into a list. // Java 7 — 10 lines, two passes, one temporary variable, zero joy List<String> result = new ArrayList<>(); for (String name : names) { if (name.
Continue reading »JVM Improvements: Metaspace, PermGen Removal, and Performance
PermGen Removal: The End of a Classic Error OutOfMemoryError: PermGen space was the Java error that launched a thousand Stack Overflow questions. Application servers would run fine for hours and then fall over during a hot redeploy. The fix — adding more -XX:MaxPermSize — was a band-aid. Java 8 removed the underlying problem entirely. Before Java 8, the JVM heap was divided into several regions. One of them — Permanent Generation (PermGen) — held class metadata, interned strings, and bytecode.
Continue reading »Lambda Expressions (JEP 126): Syntax, Closures, and Target Typing
The Problem Lambdas Solve Every Java 7 developer has written the same five lines of boilerplate to sort a list or run a background task. Lambda expressions eliminate that ceremony entirely — and once you understand target typing, closures, and composition, you will find yourself reaching for them in every layer of a codebase: validation pipelines, event systems, retry logic, and beyond. Before Java 8, passing behaviour as a value required an anonymous inner class:
Continue reading »