Category Archives: Java

Understanding LinkedHashMap in Java

Let’s dive into a fascinating corner of Java’s Collections Framework: the LinkedHashMap. You might already be familiar with HashMap for its speedy key-value pair storage and LinkedHashSet for maintaining insertion order in a set. Well, LinkedHashMap is the best of both worlds, offering the familiar map interface with the added benefit of predictable iteration order.

Let’s break down what makes LinkedHashMap so special and when you should consider using it.

What is LinkedHashMap?

In simple terms, LinkedHashMap is a hash table and a linked list implementation of the Map interface. It inherits all the goodness from HashMap (fast lookups, insertions, and deletions) but adds an internal doubly-linked list that runs through all of its entries. This linked list defines the iteration order, which can either be:

  1. Insertion Order: The default behavior, where elements are iterated in the order they were first inserted into the map.
  2. Access Order: Elements are iterated in the order they were last accessed (read or written). This is particularly useful for implementing LRU (Least Recently Used) caches.

Like HashMapLinkedHashMap allows one null key and multiple null values.

Interface Hierarchy

LinkedHashMap implements the following interfaces and extends the following class:

  • java.io.Serializable
  • java.util.Map
  • java.lang.Cloneable

And it extends java.util.HashMap.

Continue reading Understanding LinkedHashMap in Java

The Strategy Pattern: How to Write Code That Can Change Its Mind

As developers, we often face a familiar problem. We start with a simple feature, but soon, the requirements expand. “Can we also add this option? And what about this other way of doing it?” Before we know it, our clean, simple method has turned into a tangled mess of if-else statements or a monstrous switch block.

This is not just ugly; it’s fragile. Every new option requires modifying a central piece of logic, increasing the risk of breaking something. This violates a core principle of good software design: the Open/Closed Principle (open for extension, but closed for modification).

So, how do we build components that are flexible enough to accommodate different behaviors without a complete rewrite? Enter the Strategy Design Pattern.

What is the Strategy Pattern?

The Strategy Pattern is a behavioral design pattern that allows you to define a family of algorithms, put each of them into a separate class, and make their objects interchangeable.

Think of it like this: You have a job to be done (e.g., “calculate shipping cost”), but there are multiple ways, or strategies, to do it (e.g., “FedEx calculation,” “UPS calculation,” “Free Shipping calculation”). Instead of hard-coding the logic for all these methods inside your main Order class, you delegate the responsibility of “how” to calculate the cost to a separate strategy object. The Order class only knows that it has a “shipping calculator” and how to use it; it doesn’t care about the specifics of the calculation itself.

This lets you switch the calculation algorithm at runtime, all without touching the Order class.

Continue reading The Strategy Pattern: How to Write Code That Can Change Its Mind

Taming Complex Object Behavior with the State Design Pattern

As developers, we often encounter objects whose behavior needs to change based on their internal state. The classic, and often messy, way to handle this is with a sprawling set of if/else or switch statements. This approach quickly becomes a maintenance nightmare as we add more states and behaviors. The code gets bloated, hard to read, and fragile.

Imagine a Document object that can be in a “Draft,” “InReview,” “Approved,” or “Published” state. An action like publish() should only work if the document is “Approved.” Handling all these rules in a single method leads to a tangled mess of conditional logic. This is exactly the problem the State Design Pattern elegantly solves.

The State pattern is a behavioral design pattern that allows an object to alter its behavior when its internal state changes. The object appears to change its class.

Let’s break it down.

What is the State Pattern? The Core Idea

The core idea is to encapsulate state-specific logic into separate classes. Instead of the main object (our “Context”) handling all the logic, it delegates the responsibility to a “State” object that represents its current condition.

When the context’s state needs to change, it simply swaps its current state object for a new one representing the new state. The context itself remains blissfully unaware of the specific logic within each state.

Continue reading Taming Complex Object Behavior with the State Design Pattern

Mastering the Undo: A Deep Dive into the Memento Design Pattern

Have you ever wondered how text editors, design software, or even version control systems like Git flawlessly implement the “undo” or “revert” feature? You make a change, then another, and then realize you need to go back to a previous version. This powerful capability is often powered by a clever behavioral design pattern: the Memento pattern.

Let’s break down this pattern, understand its moving parts, and build a practical Java example to see it in action.

What is the Memento Pattern?

The Memento pattern’s primary goal is to capture and externalize an object’s internal state so that it can be restored later, all without violating the object’s encapsulation.

In simpler terms, it’s like creating a save point for an object. You can take a snapshot of the object’s state at a particular moment, store it somewhere safe, and then use that snapshot to turn back the clock and restore the object to exactly how it was when you saved it. The most crucial part is that the object’s internal workings remain a black box to the outside world.

Continue reading Mastering the Undo: A Deep Dive into the Memento Design Pattern

Using Regular Expressions with Java 8 Predicates for Clean Code

Java 8 introduced some powerful functional interfaces, and one of the most versatile is Predicate. A Predicate represents a boolean-valued function of one argument. While it’s commonly used for simple checks, combining it with regular expressions opens up a world of possibilities for more complex data validation and filtering, all within a concise and readable lambda expression.

In this post, we’ll explore how to leverage Java’s Pattern.compile() method to create efficient and reusable regex-based predicates. This approach is particularly useful when you need to perform the same regex validation multiple times, avoiding recompilation overhead for each check.

The Problem with Repeated Regex Matching

Let’s say you have a list of strings, and you want to filter them based on whether they match a specific regular expression. A naive approach might look something like this:

Continue reading Using Regular Expressions with Java 8 Predicates for Clean Code

Mastering the Proxy Design Pattern: A Practical Guide

In the world of software engineering, design patterns are reusable solutions to commonly occurring problems. They’re not finished code, but rather a blueprint or a template for how to solve a problem. Today, we’re diving deep into one of the most useful structural patterns: the Proxy Design Pattern.

Let’s start with an analogy. Think about your credit card. When you want to buy something, you don’t give the merchant direct access to your bank account. Instead, you give them your credit card. The card acts as a proxy to your funds. It provides a layer of security, can handle currency conversions, and logs your transactions—all without exposing the inner workings or full access to your bank account. The merchant interacts with the card, and the card interacts with the bank. You get the benefit (the purchase) without the risk (exposing your account).

The Proxy Design Pattern works in exactly the same way.

The Gang of Four defines the Proxy Pattern as: “Provide a surrogate or placeholder for another object to control access to it.”

In simpler terms, a proxy is an object that represents another object. The client interacts with the proxy, believing it’s the real object. The proxy then manages access to the real object, adding a layer of control, security, or functionality.

Core Components of the Proxy Pattern

The pattern has four main players:

  • Subject Interface: This is an interface that both the real object and the proxy object implement. It defines the common methods, ensuring the proxy can be used anywhere the real object can.
  • Real Subject: This is the actual object that does the real work. It’s the object that the proxy represents and protects.
  • Proxy: This object has a reference to the Real Subject. It implements the same Subject Interface and controls access to the Real Subject. It can add pre-processing or post-processing logic before or after delegating the call to the real object.
  • Client: This is the object that wants to use the Real Subject’s functionality. The client interacts only with the Proxy, completely unaware that it isn’t the Real Subject.
Continue reading Mastering the Proxy Design Pattern: A Practical Guide

Lombok @Builder: The Definitive Guide to Clean and Fluent Object Creation

As Java applications grow, creating and initializing objects can become a cumbersome task. We’ve all seen them: constructors with a long list of parameters, some of which are optional, leading to multiple overloaded constructors or the error-prone “telescoping constructor” anti-pattern. The traditional solution is the Builder design pattern, which provides a readable, fluent API for object creation. However, writing a Builder by hand for every DTO or entity is tedious and adds significant boilerplate code to your project.

This is where Project Lombok’s @Builder annotation comes to the rescue. It automatically generates the complete, robust Builder pattern implementation for your class at compile time, leaving your source code clean, concise, and focused on its primary responsibility.

In this guide, we’ll dive deep into @Builder, from basic setup to its most powerful and advanced features.

1. Why Do We Need a Builder?

Let’s consider a simple Employee class. Without a builder, you might initialize it like this:


// Telescoping constructors - hard to read, easy to make mistakes
Employee emp1 = new Employee(1L, "Ankur", "Kumar", "DEV", "ACTIVE");
Employee emp2 = new Employee(2L, "John", "Doe", "QA"); // What is the default status?

Continue reading Lombok @Builder: The Definitive Guide to Clean and Fluent Object Creation