7

Today I looked at the ZipEntry class and found the following:

public class ZipEntry implements ZipConstants, Cloneable

ZipConstants does not define any methods - only constants (static final int LOCHDR = 30)

It then occurred to me that implementing the interface with constants lets you access those constants directly, as if they were defined in the class itself. For example:

public interface Constants {
    static final int CONST = 2;
}

public class implements Constants {
    int doSomething(int input) {
        return CONST * input;
    }
}

Is there another reason not to use this, apart from:

  • it is at first confusing where the constant is coming from
  • it is considered wrong to use interfaces for constants definition

I'm curious because it is definitely not a very common practice.

Bozho
  • 588,226
  • 146
  • 1,060
  • 1,140

6 Answers6

16

Another reasons not to use this:

Since Java 5, there is a "clean" language feature that achieves the same goal: static imports.

Implementing interfaces to use constants is basically a pre-Java-5 hack to simulate static imports.

Michael Borgwardt
  • 342,105
  • 78
  • 482
  • 720
  • (+1), it's not simulating it completely, because it doesn't work for static imports of methods – Bozho Jan 14 '10 at 10:47
  • Actually, there's some circular logic in this argument too. We don't inherit constant only classes because you can use static imports. But why should we use static imports given that we could inherit the interface?? Even calling it a "hack" without saying why it is considered a "hack" is like repeating the "bad style" mantra. – Stephen C Jan 14 '10 at 14:53
  • The difference is that static imports are a language feature introduced specifically to allow this, whereas the purpose of interfaces is quite different; thus, using an interface like this is a hack; I thought that went without saying. – Michael Borgwardt Jan 15 '10 at 10:43
  • To be frank. Static import is nothing but a compiler feature. Just check out the decompiled version of a static import. you could see that the reference to any variable is along with the interface. – Ravisha Nov 25 '10 at 08:02
  • @Ravisha: The entire Java language (along with every other high-level language) is "nothing but a compiler feature". – Michael Borgwardt Nov 25 '10 at 08:07
3

It is not so rare as you might think, for instance in the static analysis of Parasofts JTest both the rule that constants should be declared in a class and the rule that constants should be declared in interfaces are present, and it's up to the project to choose between them.

That said, in all my projects I disallow the practice of defining constants in interfaces. Creating a meaningfull class and being explicit about the context of a constant makes code much more readable and thus maintainable than in the case where a developer has to check that constants used in one class are actually the same as those in another class (or not.)

rsp
  • 23,135
  • 6
  • 55
  • 69
3

I think that using an interface for shared constants is an example of confusing two different concepts:

  1. Code reuse
  2. Subtyping

In my experience using subclassing, or interface implementation simply to prevent the duplication of code leads to problems. Your code becomes more fragile. For example, someone might accidental redefine the constant - especially if your class hierarchy is several classes deep.

It is often better to use composition to keep your code DRY.

Another problem with using inheritance in this way is that generally this type of inheritance forms part of the API of your class. The hierarchy of the class is visible outside of the class. This breaks encapsulation. There is no need for you to expose your use of the constants outside of the class, they are to do with how you have chosen to implement your class and are not part of its API (in your example).

This can lead to horrible backwards compatibility problems. Someone else might come along and write code like this:

public interface Constants {
   static final int CONST = 2;
}

public class MyClass implements Constants {
   int doSomething(int input) {
    return CONST * input;
   }
}

public class ThirdPartyClass {
   int doSomethingElse(int input) {
     return MyClass.CONST + input;
   }
}

Now, if you decide you no longer need to use CONST in MyClass you are stuck. Because ThirdPartyClass has create a dependency on CONST being available in MyClass.

You can end up with this. Where MyClass is not using any of the constants in the interface, but still has to implement it.

public interface Constants {
   static final int CONST = 2;
}

public class MyClass implements Constants {
   int doSomething(int input) {
    return input;
   }
}

public class ThirdPartyClass {
   int doSomethingElse(int input) {
     return MyClass.CONST + input;
   }
}

In short; never do this!

lexicalscope
  • 7,158
  • 6
  • 37
  • 57
  • I wasn't intending to do it, I was just curious why has it been done in a sun-provided API – Bozho Jan 14 '10 at 12:02
  • Inexperience maybe? I have done it in the past, before I realised the kind of problems that it can cause. Or maybe it was just decided upon as a code convention a long time ago, and now the developers at sun feel they are stuck following it? I'm guessing... – lexicalscope Jan 14 '10 at 13:00
2

... because it is considered wrong to use interfaces for constants definition

This is a bad reason not to do something. In fact, it is not a reason at all.

EDIT

Consider this.

  • The reason that XXX is bad style is YYY.
  • The reason you should do XXX is that it is bad style.

How many substantive reasons are there for not doing XXX? One or two?

If the answer is two, I can make it three, four, five and so on by adding extra tenuous chains of reasons. For example "The reason you should not do XXX is because it is a bad idea." "The reasons it is a bad idea is that it is bad style". And so on. That is plainly silly.

No the real reason for not doing XXX is YYY, and the "Bad style" reason is not a substantive reason. Rather, it is a short cut for saying don't do XXX because of YYY and ZZZ, and any other substantive reasons.

In fact, even the OP's "it is confusing" reason is incompletely stated. WHY is it confusing?

Because an interface is normally a type with classes that implement the interface are subtype. But a constant only interface is not a type in any useful sense, and classes that implement the interface are not subtypes in any useful sense. Ultimately, this is the real reason that implementing constant-only interfaces is called bad style and an "anti-pattern", and it is the main reason that the static imports were added in Java 5.

Stephen C
  • 698,415
  • 94
  • 811
  • 1,216
  • since it is a matter of code-style anyway, having a code-style reason for another code-style matter isn't so strange. – Bozho Jan 14 '10 at 10:52
0

Nope, this is also known as the "Constant Interface Antipattern". An alternative is writing a concrete class which defines the constants and then use static import.

Class Constants

package util;

public class Constants {
    public static final String CONSTANT_STRING = "abc";

    private Constants() {
        throw new AssertionError(); 
    }
}

Class Test

import static util.Constants.CONSTANT_STRING;

public class Test {
    System.out.println(CONSTANT_STRING);
}

See

Wikipedia

for further details.

helpermethod
  • 59,493
  • 71
  • 188
  • 276
0

One of the reasons for not putting your constants in your interface is is that if you expose your interface to a thirdparty they have access to your constants. This may not seem like a bad idea to start off but imagine if you want to change the value of a constant but people are still using an old interface.

When you add something to an interface it has the potential to be set in stone so only add what you want others to see and use.

Shawn Vader
  • 12,285
  • 11
  • 52
  • 61