Learn about using constants in Java with a focus on common patterns and anti-patterns

1. Introduction

In this article, we’re going to learn about using constants in Java with a focus on common patterns and anti-patterns.

We’ll start with some basic conventions for defining constants. From there, we’ll move onto common anti-patterns before finishing with a look at common patterns.

2. Basics

A constant is a variable whose value won’t change after it’s been defined.

Let’s look at the basics for defining a constant:

private static final int OUR_CONSTANT = 1;

Some of the patterns we’ll look at will address the public or private access modifier decision. We make our constants static and final and give them an appropriate type, whether that’s a Java primitive, a class, or an enum. The name should be all capital letters with the words separated by underscores, sometimes known as screaming snake case. Finally, we provide the value itself.

3. Anti-Patterns

First, let’s start by learning what not to do. Let’s look at a couple of common anti-patterns we might encounter when working with Java constants.

3.1. Magic Numbers

Magic numbers are are numeric literals in a block of code:

if (number == 3.14159265359) {
        // ...
    }

They’re hard for other developers to understand. Additionally, if we’re using a number throughout our code, it’s difficult to deal with changing the value. We should instead define the number as a constant.

3.2. A Large Global Constants Class

When we start a project, it might feel natural to create a class named Constants or Utils with the intention of defining all the constants for the application in there. For smaller projects, this might be ok, but let’s consider a couple of reasons why this isn’t an ideal solution.

First, let’s imagine we have a hundred or more constants all in our constants class. If the class isn’t maintained, both to keep up with documentation and to occasionally refactor the constants into logical groupings, it’s going to get pretty unreadable. We could even end up with duplicate constants with slightly different names. This approach is likely to give us readability and maintainability problems in anything but the smallest projects.

In addition to the logistics of maintaining the Constants class itself, we’re also inviting other maintainability problems by encouraging too much interdependency with this one global constants class and various other parts of our application.

On a more technical side, the Java compiler places the value of the constant into referencing variables in the classes in which we use them. So, if we change one of our constants in our constants class and only recompile that class and not the referencing class, we can get inconsistent constant values.

3.3. The Constant Interface Anti-Pattern

The constant interface pattern is when we define an interface that contains all of the constants for certain functionality and then have the classes that need those functionalities to implement the interface.

Let’s define a constant interface for a calculator:

public interface CalculatorConstants {
        double PI = 3.14159265359;
        double UPPER_LIMIT = 0x1.fffffffffffffP+1023;
        enum Operation {ADD, SUBTRACT, MULTIPLY, DIVIDE};
    }

Next, we’ll implement our CalculatorConstants interface:

public class GeometryCalculator implements CalculatorConstants {    
        public double operateOnTwoNumbers(double numberOne, double numberTwo, Operation operation) {
           // Code to do an operation
        }
    }

The first argument against using a constant interface is that it goes against the purpose of an interface. We’re meant to use interfaces to create a contract for the behavior our implementing classes are going to provide. When we create an interface full of constants, we’re not defining any behavior.

Secondly, using a constant interface opens us up to run-time issues caused by field shadowing. Let’s look at how that might happen by defining an UPPER_LIMIT constant within our GeometryCalculator class:

public static final double UPPER_LIMIT = 100000000000000000000.0;

Once we define that constant in our GeometryCalculator class, we hide the value in the CalculatorConstants interface for our class. We could then get unexpected results.

Another argument against this anti-pattern is that it causes namespace pollution. Our CalculatorConstants will now be in the namespace for any of our classes that implement the interface as well as any of their subclasses.

#java #programming #developer

Constants in Java: Patterns and Anti-Patterns
2.25 GEEK