Explain Codes LogoExplain Codes Logo

What is the best way to implement constants in Java?

java
best-practices
object-oriented-principles
constants
Anton ShumikhinbyAnton Shumikhin·Sep 13, 2024
TLDR
public final class AppConstants { public static final int MAX_USERS = 100; }

The public static final declaration in a final class is the standard way to instantiate constants in Java. Using UPPER_CASE naming for these constants visually communicates their immovable nature. This approach is appropriate for constants that are either primitive or immutable types.

Maintaining immutability for mutable objects

When dealing with objects capable of being modified, extra precaution must be taken to safeguard the immutability of our constants.

public final class AppConfig { public static final List<String> DEFAULT_SETTINGS = Collections.unmodifiableList( Arrays.asList("setting1", "setting2", "setting3") // Our sneaky attempt at being immutable ); }

In the above example, DEFAULT_SETTINGS is an unmodifiable list to prevent potential code alteration that can change its state.

Context matters: Grouping and scope

Throwing all constants in a single class, hoping for the best, isn't ideal. Rather group related constants in their specific contexts, improving code maintainability and cohesion.

public class Geometry { public static final double PI = 3.14159; // Even circles have constants! // More geometry-specific constants... } public class SystemConfig { public static final String OS_NAME = "prop.os.name"; // Sssh OS, you're a constant now // More system configuration constants... }

This practice aligns with object-oriented principles and minimizes unnecessary dependencies.

If you have a set of related constants, the enum declaration is your new best friend from Java 5 onwards.

public enum StatusColors { RED, GREEN, YELLOW; // Traffic light approved }

Enums add type-safety, enhance readability and are well-suited for usage in switch statements.

Documenting constants

Explaining intent and usage of a constant in a brief comment makes the API easier to understand and use.

/** * The maximum height of a building, sadly no room for Godzilla. */ public static final int MAX_BUILDING_HEIGHT = 300;

Mutable constant objects, handle with care

If a mutable object is used as a constant, encapsulation is key. Disable or restrict access to mutating methods, and no setters allowed.

Constants without a home, use utility class

For constants that are the odd ones out, a utility class serves as a good remedy. Remember, the constructors should be private to retain non-instantiability.

public final class UtilityConstants { private UtilityConstants() {} // Behind the screams of a non-instantiable class public static final String APPLICATION_VERSION = "1.0.0"; }

Interfaces are not constant carriers

Using interfaces for constants adds the risk of creating tight entanglements and unwanted inheritance. The preference leans heavily towards classes for defining constants.

Visibility of constants: protected/public

Consider your constants' visibility: Declare them as protected when they are used within a package or by inheriting classes. Public constants can be accessed throughout the application.

public class BaseEntity { protected static final int DEFAULT_PAGE_SIZE = 20; // An accommodating way for pagination! }

Refactor for better arrangement

Over the course of application evolution, constants can get scattered across the code. Refactor and relocate constants as needed for improved readability and maintainability.

Defining the proper type

Always choose the right data type to accurately and efficiently represent constant values.