In most IDEs, you can simply mouseover the variable if you want to know. In addition, really, if you're working in an instance method, you should really know all the variables involved. If you have too many, or their names clash, then you need to refactor.
It's really quite redundant.
I don't agree with either of the two proposals.
Constants should be in their pertinent classes, not in an all-constant class in either of the two forms proposed.
There shouldn't be constants-only classes/interfaces.
A class CreditCard
(not an internal class) should exist. This class/interface has methods relative to credits cards as well as the constants UI_EXPIRY_MONTH
and UI_ACCOUNT_ID
.
There should exist a class/interface BankAccount
(not an internal class). This class/interface has methods relative to bank accounts as well as constant UI_ACCOUNT_ID
.
For example in the Java API every class/interface has its constants. They are not in a Constants class/interface with hundreds of constants, either grouped into inner classes or not.
For example, these constants pertinent to result sets are in the interface ResultSet
:
static int CLOSE_CURSORS_AT_COMMIT
static int CONCUR_READ_ONLY
static int CONCUR_UPDATABLE
static int FETCH_FORWARD
static int FETCH_REVERSE
static int FETCH_UNKNOWN
static int HOLD_CURSORS_OVER_COMMIT
static int TYPE_FORWARD_ONLY
static int TYPE_SCROLL_INSENSITIVE
static int TYPE_SCROLL_SENSITIVE
This interface has method signatures relative to result sets, and implementing classes implement that behavior. They are not mere constant-holders.
These constants pertinent to UI actions are in the interface javax.swing.Action
:
static String ACCELERATOR_KEY
static String ACTION_COMMAND_KEY
static String DEFAULT
static String LONG_DESCRIPTION
static String MNEMONIC_KEY
static String NAME
static String SHORT_DESCRIPTION
static String SMALL_ICON
Implementing classes have behavior relative to UI actions, they are not mere constant holders.
I know at least one "constants" interface (SwingConstants
) with no methods but it doesn't have hundreds of constants, just a few, and they are all related to directions and positions of UI elements:
static int BOTTOM
static int CENTER
static int EAST
static int HORIZONTAL
static int LEADING
static int LEFT
static int NEXT
static int NORTH
static int NORTH_EAST
static int NORTH_WEST
static int PREVIOUS
static int RIGHT
static int SOUTH
static int SOUTH_EAST
static int SOUTH_WEST
static int TOP
static int TRAILING
static int VERTICAL
static int WEST
I think constants only classes are not good OO design.
Best Answer
There are two options that one has for dealing with specific, frequently occurring immutable objects. You can either instantiate them each time, or you can use a constant that is probably stuck in a
final static
in some class.BigInteger
for example hasZERO
,ONE
, andTEN
.However, this is an attempt to avoid instantation of new objects. Say you're adding the sum of some BigIntegers. You've got the choice of:
vs
vs
The first code is simpler to understand and less error prone.
The second creates another object when its not needed - do this several times and you've got several
BigInteger.valueOf(0)
objects that need to get collected at some point.The third is error prone - if the array is empty, sum comes out with a
null
.However this should be remembered that this is trying to avoid instatiation of objects. Using it for things such as comparisons doesn't help.
This is some dangerous code. Sure, ZERO_INT is an
Integer
and it will get unboxed back to a 0. But if the myArray ever becomes something that returns an Integer? It may break depending on how ZERO_INT was defined (Integer ZERO_INT = 0
is less likely to,Integer ZERO_INT = new Integer(0)
is more likely to). And things you get back from ORMs and the like are rarely boxed.At a former employer, I had
BigDecimal KM_IN_MI = BigDecimal.valueOf("1.60934");
defined because it was a value that kept getting used and removed code that would create it a few dozen times otherwise. That's a good constant - and its not one that would get auto boxed for you. Its also one that needs to stay consistent through multiple calculations.Defining
Integer.valueOf(0)
fails at this test because it is one that would get auto boxed for you, is more likely to be buggy (the==
works sometimes), and is already a constant0
.The empty string is... kind of useless, other than its name.
""
is easier to type and probably more convenient. That said, some tools will yell at you for having a string constant used multiple times as string constants - set up your static analysis to put""
into its exception list.This is because Java does String interning.
They take strings out of college and put them to work.At compile time, all the string literals are put into a specific pool of strings that are pre-defined. This can save memory and speed things up - and make things referentially equal ("foo" == "foo"
is true, while"foo" == new String("foo")
is false, but"foo" == (new String("foo")).intern()
is true -- got all that?).Defining some strings as constants means that you are not violating DRY. But for
""
, this is probably overkill, unnecessary and, frankly, a pain.For
final static
primitives (byte
,short
,int
,float
,double
,char
,long
,boolean
), these are translated to literals at compile time (String
also has this behavior though it is complicated with the interning pool). They do have uses, as can seen in the code for java.util.Calendar. However, extreme caution must be taken with this.If your code looks like:
when it gets compiled, class B effectively becomes:
There is no reference to
A.FOO
in the code. This is mentioned in Understanding Class Members:As these numbers get compiled into any class that uses them (rather than referencing the constant), it means if the value changes for some reason everything that uses it must be recompiled. Failing to do that means that you think you are using a given value from the new .jar but you are still using the old one.
There are a couple of ways to make sure you don't have this problem of mismatched constants.
The easiest (and hardest to enforce) is to say "once something is a
public final static int answer = 42
it never changes." If you need a newanswer
, you make a new constant. If you need to change this value some day, too bad.One is to make sure that the values don't get out of the package as a
public final static
and instead make it package level. This means that it isn't likely to be used in another .jar and changing it means recompiling the current .jar.Another approach is to make the constant accessed via a getter. The getter doesn't get inlined at compile time, but can get inlined at JIT time. This means that you don't have to worry about if the constant in the other class changes because you are accessing it via a getter at runtime rather than compile time inlining.
As this is a bit complex and has been the source of at least one bug that I've fought (and oh, what an epic fight it was - it works on my machine, doesn't work in the dev environment, works on test, but not on production (but differently than how it didn't work in dev); because different versions of a .jar were present on each one and the final static int was different) -- one should be wary of these values if they have at all a chance to change with future versions. There is also some more esoteric breaking of case statements where two of them could have the same value. There are some idioms to avoid this mentioned at the end of section 13.4.9 of the JLS though it has the caveat of "We note, but do not recommend..."
I should point out that
final static {primitive}
is not a pool at all in the language of patterns. It is a way of invoking a compiler optimization for DRY at the cost of closer coupling between the classes and the possibility of errors if that coupling doesn't mean all the classes are recompiled at the same time when the 'constant' changes.Constant pools of objects are there for performance issues. Look at the IntegerCache in the Integer class (its a Flyweight Pattern). Or the proper use of String interning.
But that speed performance gain is unlikely of any use if the code that is written is harder to understand and more likely to have a bug introduced in it.
When dealing with non-mathematical constants and primitive types, make sure that these values are constant to avoid some rather hard to track down bugs (see this explanation of one such 'bug').
Write what is understandable. Unless demonstrated otherwise, programmer time is more valuable than cpu time.