Java Builder Pattern Simple example

🧱 Builder Design Pattern in Java — Step-by-Step with Example

The Builder Pattern is a creational design pattern that provides a flexible solution for constructing complex objects step by step.
It’s especially useful when a class has many fields, and not all of them are required (some are optional).

Instead of passing dozens of constructor arguments (and remembering their order),
the Builder Pattern allows clean, readable object creation like this πŸ‘‡

Customer customer = new Customer.CustomerBuilder("Vinod", "Kumaran") .setCity("Bangalore") .setAddress("Electronic City") .build();

🎯 Why Builder Pattern?

Imagine you have a class with:

  • Mandatory fields (must always be provided)

  • Optional fields (can be skipped or defaulted to null)

If you use normal constructors, you might end up with “constructor telescoping”, like:

new Customer("Vinod", "Kumaran", null, "Bangalore", null);

This is hard to read, hard to maintain, and error-prone.

The Builder Pattern fixes this problem by providing:
✅ Better readability
✅ Clear separation of mandatory & optional fields
✅ Immutable objects
✅ Easy object construction


⚙️ Example Use Case

We’ll create a Customer class where:

  • firstName and lastName are mandatory

  • address, city, and zipCode are optional


🧩 Step 1: Create the Customer Class

package com.vinod.patterns; /** * Builder pattern example demonstrating how to create objects * with mandatory and optional parameters. */ public class Customer { // Mandatory fields private final String firstName; private final String lastName; // Optional fields private final String address; private final String city; private final String zipCode; // Private constructor to enforce the use of Builder private Customer(CustomerBuilder builder) { this.firstName = builder.firstName; this.lastName = builder.lastName; this.address = builder.address; this.city = builder.city; this.zipCode = builder.zipCode; } // Getters public String getFirstName() { return firstName; } public String getLastName() { return lastName; } public String getAddress() { return address; } public String getCity() { return city; } public String getZipCode() { return zipCode; } @Override public String toString() { return "Customer [firstName=" + firstName + ", lastName=" + lastName + ", address=" + address + ", city=" + city + ", zipCode=" + zipCode + "]"; } /** * Static nested Builder class * Provides fluent methods to set optional parameters. */ public static class CustomerBuilder { // Required fields private final String firstName; private final String lastName; // Optional fields (initialized to null by default) private String address; private String city; private String zipCode; // Constructor with mandatory parameters public CustomerBuilder(String firstName, String lastName) { this.firstName = firstName; this.lastName = lastName; } // Setter methods for optional fields public CustomerBuilder setAddress(String address) { this.address = address; return this; } public CustomerBuilder setCity(String city) { this.city = city; return this; } public CustomerBuilder setZipCode(String zipCode) { this.zipCode = zipCode; return this; } // Build method to return final Customer object public Customer build() { return new Customer(this); } } }

πŸ§ͺ Step 2: Test the Builder Pattern

package com.vinod.patterns; public class TestBuilderPattern { public static void main(String[] args) { // Case 1: Create Customer with only mandatory fields Customer customer1 = new Customer.CustomerBuilder("Vinod", "Kumaran") .build(); System.out.println(customer1); // Case 2: Create Customer with some optional fields Customer customer2 = new Customer.CustomerBuilder("Vinod", "Kumaran") .setAddress("Electronic City") .setCity("Bangalore") .build(); System.out.println(customer2); } }

🧾 Output

Customer [firstName=Vinod, lastName=Kumaran, address=null, city=null, zipCode=null] Customer [firstName=Vinod, lastName=Kumaran, address=Electronic City, city=Bangalore, zipCode=null]

🧠 How It Works — Step by Step

StepActionExplanation
1️⃣Create a CustomerBuilderPass only mandatory fields to its constructor.
2️⃣Chain setter methodsUse fluent syntax to set optional fields.
3️⃣Call build()Constructs a Customer by passing builder data to the private constructor.
4️⃣Customer object is immutableBecause all fields are final and no setters exist in Customer.

🧭 When to Use the Builder Pattern

ScenarioWhy Builder Helps
Many parameters (some optional)Avoids telescoping constructors
Object should be immutableBuilder handles initialization only once
Want readable, step-by-step object creationMethod chaining improves clarity
Need validation or defaultsAdd checks inside build()

⚡ Advantages

  • ✅ Clean and readable object creation

  • ✅ Avoids null handling for optional parameters

  • ✅ Supports immutability

  • ✅ Easy to extend without breaking existing code

  • ✅ Works perfectly in Java 8 and above


πŸ” Summary

ConceptDescription
Pattern TypeCreational
Main IdeaSeparate object construction from representation
UsageWhen a class has multiple optional fields
ResultCleaner, safer, and more maintainable code

πŸ’¬ Real-World Analogy

Think of a pizza order πŸ• —
You must choose the base (mandatory), but toppings like cheese, olives, or mushrooms are optional.
The Builder Pattern lets you create the exact “pizza” you want, without forcing you to specify every topping each time.




Java EE WebSocket Simple example

WebSocket is a protocol which allows for communication between the client and the server/endpoint using a single TCP connection. The advantage WebSocket has over HTTP is that the protocol is full-duplex (allows for simultaneous two-way communcation).

Here is one simple example to create a WebSocket endpoint and communicate it from a client.

Softwares Used

Java 1.7, Apache Tomcat, Eclipse

1. Create a Maven project with webapp archetype.

image

2.Create a WebSocket end point.

package com.pretech.test.websockets;
 
import java.io.IOException;
 
import javax.websocket.OnClose;
import javax.websocket.OnMessage;
import javax.websocket.OnOpen;
import javax.websocket.Session;
import javax.websocket.server.ServerEndpoint;
 
@ServerEndpoint("/websocket")
public class WebSocketTest {
 
    @OnMessage
    public void onMessage(String message, Session session) throws IOException,
            InterruptedException {
        System.out.println("User input: " + message);
        session.getBasicRemote().sendText("Hello world Mr. " + message);
        // Sending message to client each 1 second
        for (int i = 0; i <= 25; i++) {
            session.getBasicRemote().sendText(i + " Message from server");
            Thread.sleep(1000);
 
        }
    }
 
    @OnOpen
    public void onOpen() {
        System.out.println("Client connected");
    }
 
    @OnClose
    public void onClose() {
        System.out.println("Connection closed");
    }
}

@ServerEndpoint annotation is used at type level and defines the current class as a websocket server endpoint. The value used in this annotation represents the URL where the endpoint will be listening for client connections

3. Create an html page

<!DOCTYPE html>
<html>
<head>
<title>Pretech blog testing web sockets</title>
</head>
<body>
    <div>
        <input type="text" id="userinput" /> <br> <input type="submit"
           value="Send Message to Server" onclick="start()" />
    </div>
    <div id="messages"></div>
    <script type="text/javascript">
        var webSocket = new WebSocket(
                'ws://localhost:8080/pretech-websocket-example-1.0-SNAPSHOT/websocket');

        webSocket.onerror = function(event) {
            onError(event)
        };

        webSocket.onopen = function(event) {
            onOpen(event)
        };

        webSocket.onmessage = function(event) {
            onMessage(event)
        };

        function onMessage(event) {
            document.getElementById('messages').innerHTML += '<br />'
                    + event.data;
        }

        function onOpen(event) {
            document.getElementById('messages').innerHTML = 'Now Connection established';
        }

        function onError(event) {
            alert(event.data);
        }

        function start() {
            var text = document.getElementById("userinput").value;

            webSocket.send(text);
            return false;
        }
    </script>
</body>
</html>

4. Build and deploy the war

Build the maven project and deploy the war in to tomcat server. Once the server is started hit the blow url.

http://localhost:8080/pretech-websocket-example-1.0-SNAPSHOT/hello.html

We will see the connection established message in the screen, now enter your name and submit the request.

image

image

 

5. Download this example

 

Download WebSoket Example

 

Ref: Netbeans

Java Enum constructor example

Example

package com.vinod.test;

public class EnumConstructor {

    public static void main(String[] args) {
        // Getting year values
        System.out.println("Year " + Days.YEAR.getValue() + "   days");

        // Getting all values
        for (Days day : Days.values()) {
            System.out.println(day.getValue());

        }
    }

}
enum Days {
    YEAR(365), MONTH(30), WEEK(7);
    private int value;
    private Days(int value) {
        this.value = value;
    }
    public int getValue() {
        return value;
    }
}

Output

Year 365   days
365
30
7

Java ListIterator Example

The ListIterator interface is a special kind of iterator designed to iterate over lists. It provides functionality to iterates a list in both direction. Here is one example to iterate a list in reverse order using ListIterator.

Example

package mycollectiontest;

import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;

public class ListIterator {

public static void main(String[] args) {
List<String> list = new ArrayList<String>();
list.add("One");
list.add("Two");
list.add("Three");
list.add("Four");
list.add("Five");
// Iterator allows only one direction
Iterator<String> it = list.iterator();
while (it.hasNext()) {
System.out.println(it.next());

}
// ListIterator allows traversing both direction
java.util.ListIterator<String> listIterator = list.listIterator(list.size());
while (listIterator.hasPrevious()) {
System.out.println(listIterator.previous());
}
}

}

Output

One
Two
Three
Four
Five
Five
Four
Three
Two
One

Java custom serialization example

Java Custom Serialization — Complete Guide With Example 

(Updated with transient vs non-transient fields explanation)

Serialization is a core concept in Java and plays a major role in distributed systems, microservices, caching, and message passing.
This blog explains:

  • What serialization is

  • Why serialization is needed

  • What transient & non-transient mean

  • How custom serialization works

  • Real-world use cases

  • Complete code example


1. What Is Serialization in Java?

Serialization is the process of converting an object into a byte stream so it can be:

✔ Stored in a file
✔ Sent over a network
✔ Stored in cache
✔ Persisted temporarily
✔ Shared between JVM instances

Java provides built-in serialization with:

implements Serializable

2. Why Serialization Is Needed (Real Use Cases)

Serialization is crucial in many systems:

✔ Distributed Systems

Send objects between services (legacy RMI, microservices, RPC frameworks).

✔ Caching

Store Java objects in Redis, Hazelcast, Ignite.

✔ Message Passing

Kafka, ActiveMQ, RabbitMQ often serialize objects.

✔ File/Session Storage

Store state so it can be restored later.


3. What Are Transient and Non-Transient Fields?

Serialization by default saves every non-transient field of a class.

But sometimes we do NOT want all fields to be serialized.

πŸ“ Transient Field

A transient field is NOT serialized even if the class implements Serializable.

Example:

transient String password;

Java intentionally skips this during serialization.

πŸ“ Non-Transient Field

Normal variables (without transient) are serialized.

Example:

String name; // serialized int age; // serialized

4. Why Java Introduced transient?

(Why do we need it?)

✔ 1. Security

You don’t want to serialize sensitive data:

  • passwords

  • tokens

  • API keys

  • cryptographic secrets

✔ 2. Derived (non-essential) fields

Some fields can be computed again at runtime.

transient int cachedHashCode;

✔ 3. Large fields not needed in serialization

Example: temporary buffers

✔ 4. Prevent unwanted state transfer

Ex: open network connections, thread objects, file streams

These objects cannot be serialized, so marking them transient avoids errors.

✔ 5. Reduce payload

Skipping unnecessary fields reduces storage & network cost.


5. How transient Works Internally?

When serializing:

  • JVM examines all fields

  • If a field is transient → it is skipped

  • If not transient → JVM serializes it

On deserialization:

  • Transient fields are restored as default values:

    • 0 for numbers

    • false for boolean

    • null for all objects


6. Custom Serialization (writeObject & readObject)

Sometimes we need even more control, beyond transient.

Example use case:

Do not serialize Employee object IF address is empty.

For such rules, Java lets you override serialization using:

private void writeObject(ObjectOutputStream out) private void readObject(ObjectInputStream in)

7. Full Example: Custom Serialization in Java

🟦 Employee class

class Employee implements Serializable { private static final long serialVersionUID = 5845255930677343859L; private String name; private String address; public Employee(String name, String address) { this.name = name; this.address = address; } private void writeObject(ObjectOutputStream o) throws IOException { if (address == null || address.length() == 0) { throw new IllegalArgumentException(); } o.writeObject(name); o.writeObject(address); } private void readObject(ObjectInputStream o) throws IOException, ClassNotFoundException { name = (String) o.readObject(); address = (String) o.readObject(); } @Override public String toString() { return "Employee [name=" + name + ", address=" + address + "]"; } }

🟧 Main Class

public class CustomSerializaionExample { public static void main(String[] args) { Employee emp = new Employee("Vinod", ""); try { FileOutputStream fos = new FileOutputStream("employee.ser"); ObjectOutputStream oos = new ObjectOutputStream(fos); oos.writeObject(emp); // calls custom writeObject() oos.close(); FileInputStream fis = new FileInputStream("employee.ser"); ObjectInputStream ois = new ObjectInputStream(fis); Employee deemp = (Employee) ois.readObject(); ois.close(); System.out.println(deemp); } catch (Exception e) { e.printStackTrace(); } } }

8. Expected Output

Exception in thread "main" java.lang.IllegalArgumentException at Employee.writeObject(...)

This shows that your custom validation logic executed.

Since address is empty, the object is blocked from serialization.


9. Where Transient + Custom Serialization Are Useful

ScenarioUse CaseFeature
Sensitive fieldsPassword, token, keytransient
Skip invalid objectsMissing mandatory datawriteObject()
Reduce sizeRemove large bufferstransient
Derived fieldsRecalculate instead of storingtransient
Full control over serializationBusiness validationwriteObject/readObject

Often you combine both transient and custom serialization.


10. Summary

✔ Serialization converts an object to bytes

✔ Needed for networking, caching, persistence

transient prevents sensitive/unwanted fields from being serialized

✔ Custom writeObject() allows full control over what & how to serialize

✔ Your example shows validation-based serialization control

✔ Very useful in secure, distributed, or performance-critical systems


What is Robustness?

Robustness is the ability of software systems to react appropriately to abnormal conditions.

Ref: Object Oriented software Construction by Bertrand Meyer

12 classic String-based Java interview questions with simple explanations and code.

  1️⃣ Check if a String is a Palindrome Problem Given a string, check if it reads the same forward and backward. Example: "madam...

Featured Posts