DZone
Thanks for visiting DZone today,
Edit Profile
  • Manage Email Subscriptions
  • How to Post to DZone
  • Article Submission Guidelines
Sign Out View Profile
  • Post an Article
  • Manage My Drafts
Over 2 million developers have joined DZone.
Log In / Join
Please enter at least three characters to search
Refcards Trend Reports
Events Video Library
Refcards
Trend Reports

Events

View Events Video Library

Zones

Culture and Methodologies Agile Career Development Methodologies Team Management
Data Engineering AI/ML Big Data Data Databases IoT
Software Design and Architecture Cloud Architecture Containers Integration Microservices Performance Security
Coding Frameworks Java JavaScript Languages Tools
Testing, Deployment, and Maintenance Deployment DevOps and CI/CD Maintenance Monitoring and Observability Testing, Tools, and Frameworks
Culture and Methodologies
Agile Career Development Methodologies Team Management
Data Engineering
AI/ML Big Data Data Databases IoT
Software Design and Architecture
Cloud Architecture Containers Integration Microservices Performance Security
Coding
Frameworks Java JavaScript Languages Tools
Testing, Deployment, and Maintenance
Deployment DevOps and CI/CD Maintenance Monitoring and Observability Testing, Tools, and Frameworks

Because the DevOps movement has redefined engineering responsibilities, SREs now have to become stewards of observability strategy.

Apache Cassandra combines the benefits of major NoSQL databases to support data management needs not covered by traditional RDBMS vendors.

The software you build is only as secure as the code that powers it. Learn how malicious code creeps into your software supply chain.

Generative AI has transformed nearly every industry. How can you leverage GenAI to improve your productivity and efficiency?

Related

  • Generics in Java and Their Implementation
  • High-Performance Java Serialization to Different Formats
  • Writing DTOs With Java8, Lombok, and Java14+
  • Redefining Java Object Equality

Trending

  • How to Use AWS Aurora Database for a Retail Point of Sale (POS) Transaction System
  • Exploring Intercooler.js: Simplify AJAX With HTML Attributes
  • Security by Design: Building Full-Stack Applications With DevSecOps
  • IoT and Cybersecurity: Addressing Data Privacy and Security Challenges
  1. DZone
  2. Coding
  3. Languages
  4. Creating Immutable Classes in Java

Creating Immutable Classes in Java

An introduction to immutable classes in Java, such as a String class.

By 
Hari Kiran G user avatar
Hari Kiran G
·
Updated Apr. 14, 16 · Tutorial
Likes (29)
Comment
Save
Tweet
Share
42.6K Views

Join the DZone community and get the full member experience.

Join For Free

What is an immutable object?

Once an object is created and initialized, it cannot be modified. We can call accessor methods (e.g. getter methods), copy the objects, or pass the objects around — but no method should allow modifying the state of the object. Wrapper classes (such as Integer and Float) and String classes are well-known examples of classes that are immutable.

Let us now discuss the String class. String is immutable; once you create a String object, you cannot modify it. How about methods such as trim that remove leading and trailing whitespace characters — do such methods modify the state of the String object? No. If there are any leading or trailing whitespace characters, the trim method removes them and returns a new String object instead of modifying that String object.

Defining Immutable Classes

Keep the following aspects in mind for creating your own immutable objects:

  • Make the fields final and initialize them in the constructor. For primitive types, the field values are final, there is no possibility of changing the state after it is initialized. For reference types, you cannot change the reference.
  • For reference types that are mutable, you need to take of some more aspects to ensure immutability. Why? Even if you make the mutable reference type final it is possible that the members may refer to objects created outside the class or may be referred by others. In this case:
    • Make sure that the methods don’t change the contents inside those mutable objects.
    • Don’t share the references outside the classes — for example, as a return value from methods in that class. If the references to fields that are mutable are accessible from code outside the class, they can end up modifying the contents of the object.
    • If you must return a reference, return the deep copy of the object (so that the original contents remain intact even if the contents inside the returned object is changed).
  • Provide only accessor methods (i.e., getter methods) but don’t provide mutator methods (i.e., setter methods)
    • In case changes must be made to the contents of the object, create a new immutable object with the necessary changes and return to that reference.
  • Declare the class final. Why? If the class is inheritable, methods in its derived class can override them and modify the fields.

Let us now review the String class to understand how these aspects are taken care of in its implementation:

  • All its fields are made private. The String constructors initialize the fields.

  • There are methods such as trim, concat, and substring that need to change the contents of the String object. To ensure immutability, such methods return new String objects with modified contents.
  • The String class is final, so you cannot extend it and override its methods.

Here is a circle class that is immutable. For brevity, this example shows only the relevant methods for illustrating how to define an immutable class:

//ImmutableCircle.java

// Point is a mutable class
class Point {

    private int xPos, yPos;

    public Point(int x, int y) {
       xPos = x;
       yPos = y;
    }

    public String toString() {
        return "x = " + xPos + ", y = " + yPos;
    }

    int getX() { return xPos; }
    int getY() { return yPos; }
}

// ImmutableCircle is an immutable class – the state of its objects
// cannot be modified once the object is created
public final class ImmutableCircle {

private final Point center;
private final int radius;

public ImmutableCircle(int x, int y, int r) {
center = new Point(x, y);
radius = r;
}

public String toString() {
return "center: " + center + " and radius = " + radius;
}

public int getRadius() {
return radius;
}

public Point getCenter() {
// return a copy of the object to avoid
// the value of center changed from code outside the class
return new Point(center.getX(), center.getY());
}

public static void main(String []s) {
System.out.println(new ImmutableCircle(10, 10, 20));
}
// other members are elided ...
}

This program prints:

center: x = 10, y = 10 and radius = 20

Note the following aspects in the definition of the ImmutableCircle class:

  • The class is declared final to prevent inheritance and overriding of its methods.
  • The class has only final data members and they are private.
  • Because center is a mutable field, the getter method getCenter() returns a copy of the Point object.

Immutable objects also have certain drawbacks. To ensure immutability, methods in immutable classes may end-up creating numerous copies of the objects. For instance, every time getCenter() is called on the ImmutableCircle class, this method creates a copy of the Point object and returns it. For this reason, we may need to define a mutable version of the class as well, for example, a mutable Circle class.

The String class is useful in most scenarios, if we call methods such as trim, concat, or substring in a loop, these methods are likely to create numerous (temporary) String objects. Fortunately, Java provides StringBuffer and StringBuilder classes that are mutable. They provide functionality similar to String,  but you can mutate the contents within the objects. Hence, depending on the context, we can choose to use String class or one of StringBuffer or StringBuilder classes.

Source code presented in this article can be downloaded here.

Object (computer science) Data Types Strings Java (programming language)

Published at DZone with permission of Hari Kiran G. See the original article here.

Opinions expressed by DZone contributors are their own.

Related

  • Generics in Java and Their Implementation
  • High-Performance Java Serialization to Different Formats
  • Writing DTOs With Java8, Lombok, and Java14+
  • Redefining Java Object Equality

Partner Resources

×

Comments
Oops! Something Went Wrong

The likes didn't load as expected. Please refresh the page and try again.

ABOUT US

  • About DZone
  • Support and feedback
  • Community research
  • Sitemap

ADVERTISE

  • Advertise with DZone

CONTRIBUTE ON DZONE

  • Article Submission Guidelines
  • Become a Contributor
  • Core Program
  • Visit the Writers' Zone

LEGAL

  • Terms of Service
  • Privacy Policy

CONTACT US

  • 3343 Perimeter Hill Drive
  • Suite 100
  • Nashville, TN 37211
  • support@dzone.com

Let's be friends:

Likes
There are no likes...yet! 👀
Be the first to like this post!
It looks like you're not logged in.
Sign in to see who liked this post!