views:

404

answers:

8

If I have a collection of static constants that I want to declare centrally so that they can be shared among various projects should they be put in a class or interface (Java).

In the past I have seen them mostly put in a class but I started thinking that since the class will not and should not be instantiated maybe they would be better in an interface, but then again the interface should not be implemented by any classes. e.g.

public class ErrorCodes {
    public static final String ERROR_1 = "-1";
    public static final String ERROR_2 = "-2";
}

or

public interface ErrorCodes {
    public static final String ERROR_1 = "-1";
    public static final String ERROR_2 = "-2";
}
+17  A: 

If they have strong connections, then I'd put them in an enum:

public enum Error {
  ERROR_1("-1", "foo went wrong"),
  ERROR_2("-2", "bar went wrong");

  private final String id;
  private final String message;

  Error(String id, String message) {
    this.id=id;
    this.message=message;
  }

  public String getId() {
    return id;
  }

  public String getMessage() {
    return message;
  }
}

The advantage is that you can have type safety in your code and that you can easily add id-based lookup (either by building a HashMap<String,Error> in the constructor or by simply looping over values()).

Joachim Sauer
An enum is actually an even better way of doing this. I guess I didn't read his question carefully enough to grasp his intentions...
Tomas Lycken
I found this to be the best solution, as you can keep the numbers and strings together and load the strings from from a properties file. Everything in one place.
Thomas Jones-Low
+2  A: 

You should do it in a class.

An Interface is a description of available methods, properties etc that class users can access - by implementing an interface, you guarantee that the members declared in the interface are available to the user.

A class, on the other hand, is a description of an object or (if you're not too hard on the OO principles...) a placeholder for static members. I personally find it very useful in some projects to store away a bunch of constants in a Settings class, so I don't have to look around in the entire project for the definitions. I think this approach is what you're after, too.

Tomas Lycken
+2  A: 

The use of static import should be considered here (for importing constants defined in a class), or type-safe Enum.

From Interface for constants

Placing constants in an interface was a popular technique in the early days of Java, but now many consider it a distasteful use of interfaces, since interfaces should deal with the services provided by an object, not its data.
As well, the constants used by a class are typically an implementation detail, but placing them in an interface promotes them to the public API of the class.

VonC
+1  A: 

You should put them on the class with a private constructor.

public class ErrorCodes {
    private ErrorCodes() {} // prevents instantiation
    public static final String ERROR_1 = "-1";
    public static final String ERROR_2 = "-2";

}

Or better yet, use a typesafe enum.

Wayne Young
+1  A: 

This has been discussed before:

The reason why you don't want the constants in an interface is that it entices client classes to "implement" that interface (in order to access the constants without prefixing them with the interface name). You shouldn't, though - the interface isn't actually an interface to the object's capabilities, but a compile-time convenience ingrained in the class' external type.

There was a time when the "constant interface" was very convenient, but it has always been "wrong" and not even laziness is an excuse to use it now that we have import static statements.

Edit: Although I must agree that for the scenario presented in your question, enums are more appropriate.

gustafc
+3  A: 

Some people consider constant-interface an anti-pattern (http://en.wikipedia.org/wiki/Constant%5Finterface) .

Superfilin
To my mind, the anti-pattern is *implementing* an interface in order to gain access to the named constants.
Stephen C
A: 

I personally feel that the constants should be defined in a class for the same reasons as described here above. Especially because some developers use these constants by implementing the interface in the class that wants to use them. When that interface contains a lot of constants you do not want to look at the javadoc of that specific class anymore because it is littered with descriptions of constants that are probably not even used by that class.

A: 

I recommend a combination of static imports and interfaces for constants.

If a Java interface has constant field declarations, bear in mind that these are implicitly public, static and final (see the Java Language Specification, Section 9.3.) You can therefore always omit these modifiers, leaving only the type, and your constant interface would look like this:

public interface Constants {
    int AGE = 0x23;
    String NAME = "Andrew";
    boolean IGNORE = true;
}

This should, of course, only ever be used as follows:

import static Constants.*;

public Whatever {
    public String method() {
        return String.format("%s is %d%c", NAME, AGE, IGNORE ? '?' : '!');
    }
}

I have no issues using this style in my production code, and feel it leads to a very neat, compact constants collection, and can cope with various types of constant, which an enum couldn't, as well as being able to be extended if requred, unlike an enum.

Another possibility, which not everyone will approve of, is to nest interfaces (or even enum types) in your parent interface, allowing you to group your constants. This :

interface MoreConstants {
    int MAGIC = 0xCAFEBABE;
    interface PROPERTIES {
        String NAME = "name";
    }
    enum ERRORS {
        ON_FIRE, ASLEEP, BROKEN, UNSURE;
    }
}

and access them like this, assuming a static import of the MoreConstants interface:

if (!PROPERTIES.NAME.equals(value)) {
    return ERRORS.UNSURE;
}

Of course, these interfaces should never be implemented, which I would consider bad practice. The only way to ensure this, however, is strict code reviews...

grkvlt
An issue you don't touch is that some constants will be copied at compile time into the generated bytecode instead of being referenced, leaving you with an ABI that you can't change without breaking stuff.
Trevor Harrison
Is this not also an issue with the 'class for constants' solution, due to direct field access?
grkvlt
Yep, I think the same thing happens for both class and interface, but I could be wrong. +1 to the enum answers
Trevor Harrison
Point taken, emum is preferable in some cases. This technique is best used in a project or projects which is *not* exporting it as part of a binary API. Minor point - I see too many people writing 'public static final' before fields in interfaces, as though it makes a difference - learn what the default modifiers are and use it to write more compact code.
grkvlt