As a Java developer, you’re likely familiar with utility classes, which provide a collection of static methods for performing common tasks.
However, traditional implementation of these classes can be verbose and lead to boilerplate code.
That’s where Lombok’s @UtilityClass annotation comes in – an experimental feature that simplifies the creation of utility classes.
In this tutorial, you’ll learn how to use @UtilityClass annotation to write more concise and maintainable code.

What is a Utility Class?

A utility class is a class that provides a set of static methods that can be used throughout your application. You often create utility classes to group related functionality together, making it easier to reuse code and avoid duplication.

Utility classes typically have certain characteristics that distinguish them from other types of classes.
For instance, they usually don’t have any state, meaning they don’t have instance variables.
They also often don’t allow instantiation, as they are meant to be used solely through their static methods.
They often have names like StringUtils, MathUtils or DateUtils, indicating their purpose.

Here’s an example of a traditional utility class that generates random numbers

public class RandomUtils { 
  // private constructor to prevent instantiation 
  private RandomUtils() {} 

  public static int getRandomNumber(int min, int max) { 
    return (int) (Math.random() * ((max - min) + 1)) + min; 
  } 

  public static double getRandomDouble(double min, double max) { 
    return (Math.random() * ((max - min))) + min; 
  } 
}

This class can be used throughout your application without creating instances of it.

Problems with Traditional Utility Class Implementation

One of the main issues you face when creating a traditional utility class is the amount of boilerplate code required.
You need to declare a private constructor to prevent instantiation, make all fields and methods static, and ensure that the class is final to prevent subclassing.

Another problem with traditional utility classes is that they can be misused if not implemented correctly.
For instance, if you forget to make the constructor private, the class can be instantiated, which defeats the purpose of a utility class.

Lombok @UtilityClass Annotation

When you annotate a class with @UtilityClass, Lombok will:

  • Generate a private constructor, preventing instantiation of the class.
    This ensures that your utility class remains stateless and cannot be misused by creating instances.
  • Make all methods and fields in the class static, allowing them to be called without creating an instance.
    In addition, if there are any inner classes, they are also marked as static.

Let’s take a look at an example.
Suppose you want to create a utility class to generate random numbers.
We saw how to do that without @UtilityClass above. With this annotation applied, you can simplify this code to

@UtilityClass 
public class RandomUtils { 
  public static int generateRandomNumber(int min, int max) { 
    return (int) (Math.random() * (max - min + 1) + min); 
  } 
}

As you can see, the @UtilityClass annotation takes care of generating the private constructor, making your code more concise and easier to maintain.

Benefits of @UtilityClass

One of the most significant advantages of @UtilityClass is the reduction of boilerplate code.
By automatically generating a private constructor and static methods, you can focus on writing the actual utility methods without worrying about the plumbing.
This leads to increased productivity, as you can create utility classes quickly and easily.

With @UtilityClass, your utility classes become more concise and easier to understand, making it simpler for others (and yourself) to understand the codebase.
Additionally, the annotation helps enforce good coding practices, ensuring that your utility classes remain stateless and thread-safe.

Another important advantage of @UtilityClass is enhanced security.
By generating a private constructor, you ensure that instances of your utility class cannot be created externally, which prevents misuse or unintended behavior.

Conclusion

In this article, we took a look at @UtilityClass annotation in Lombok and how to simplify utility classes with this annotation.