Define Constants in Interface or Class

Define Constants in Interface or Class

In Java syntactically it is possible and allowed to define constants in both Interface and Class. In old days putting constants in Interface was common practice because by default defined constants are marked public static final and constants can be used in implementation class without interface name prefix. But defining constants in the Interface has few disadvantages.

To explain it I will use following interface which defines one constant API_VERSION and one method.

public interface ConstantInterface {
    String API_VERSION = "1.0";
    
    void sampleMethod();
}

Disadvantages of defining Constants in Interface

  1. Interface is supposed to define type and behavior. Constants values are kind of implementation detail and by defining constants in Interface we are exposing implementation which is not good.
  2. Namespace pollution is evident side effect. Constants defined in Interface are also accessible using name of implementing class and sub-classes. Imagine how confusing it would be to see one constant defined in interface and accessed using multiple class/sub-class names in the codebase.

See following class implementing the interface.

public class ImplClass implements ConstantInterface {
    
    @Override
    public void sampleMethod() {
            // Some code
    }
}

Now I access API_VERSION constant using both interface as well as  implementing class.

System.out.println("InterfaceConstant.API_VERSION = " + ConstantInterface.API_VERSION);
System.out.println("ImplClass.API_VERSION = " + ImplClass.API_VERSION);

/*
--- Output ---
InterfaceConstant.API_VERSION = 1.0
ImplClass.API_VERSION = 1.0
*/
  1. Even if we decide to designate an interface to be used only for defining constants, syntactically it’s not possible to restrict classes from not implementing an interface.
  2. It is usual to define local constants or variables in a class if coincidently class variable/constant name matches exactly same as constant defined in implemented interface, the class local variable/constant will override interface constant. Magically constant turns into variable and it can be changed as many times as we want. And of course, value of constant referred without prefix and with Interface Name prefix is different.

See following class implementing the interface.

public class ImplClass implements ConstantInterface {
    String API_VERSION = "1.1";
    
    @Override
    public void sampleMethod() {
        System.out.println("InterfaceConstant.API_VERSION = " + ConstantInterface.API_VERSION);
        System.out.println("API_VERSION = " + API_VERSION);
        
        API_VERSION = "1.2";
        System.out.println("API_VERSION = " + API_VERSION);
    }
}

/*
--- Output ---

InterfaceConstant.API_VERSION = 1.0
API_VERSION = 1.1
API_VERSION = 1.2
*/
  1. In Interface is used to define external API, it will be packaged in client jar which will expose the constant to external client applications. It will create unnecessary dependency in client and changing constant value or removing it will break or impact all clients.

By now we got enough reasons to not define constants in Interface. Lets how above concerns are addressed by defining constants in a Class.

Advantages of defining Constants in Class

  1. Class is supposed to provide implementation so semantically it is correct to define constant in a class, irrespective of local or global constant.
  2. We can designate a class to define only constants for whole application. Good practice is to define all constants public static final. We must mark the class final so no one can extend it. We must also make the constructor private because there is no need to create instance of this constants class. All defined constants can we accessed statically using ClassName. This point alone addresses disadvantage #2, 3 and 4 of constants in interface.

See following class designed to define constants. Note that the class is marked final and has private constructor.

public final class ConstantClass {
    private ConstantClass() {}
    
    public static final String API_VERSION = "1.0";
}
  1. In client API jar we usually don’t package implementation classes, our constants are not exposed to client applications.
  2. We can create inner classes to logically group and organize constants.
  3. We can define static block in the class to put some logic to assign values to constants.
public final class ConstantClass {
    private ConstantClass() {}

    public static final String API_VERSION;

    static {
        API_VERSION = "1.0";
    }
}

So defining constants in Class is best approach.

Always use Interface to define only contract and Class to define implementation state (variable and constant) and behavior (method implementation).

Please share it and help others if you found this article helpful. Feedback, questions and comments are always welcome.

Further Reading

1 Comment

Comments

%d bloggers like this: