The accepted answer is quite good, but I wanted to add my judgment to this because I think it's a bit different from that of others.
You should use a named constant in three situations:
- When the value behind the constant has some cost to it, that you can avoid by comparing constants instead
- When the value behind the constant is ambiguous in meaning, and giving it a meaningful name would help with comprehension
- When the value behind the constant is used in multiple places, and you would logically want all of them to change at the same time.
For case #1, an example would be the use of something like new Integer(4967)
. The Integer
class has static constants for a bunch of values, but probably not 4967. If you make it a constant, you save slightly on memory, significantly on boxing/unboxing costs, and you can use ==
to compare identity instead of having to use .equals()
for a correct comparison. This makes your code shorter, easier to read, and more efficient.
For case #2, the accepted answer's example of months is good, if slightly weak. Most people know the order of the months off by heart and wouldn't be confused to read code that says month == 6
; but perhaps people who use a different native calendar, or children perhaps, might not know it as well. Reading month == FEBRUARY
is going to be equally easy for most people. It also protects you from accidentally writing month == 14
(though I might argue that in this case, an enumerated type would be even better, making an invalid month assignment a compile-time error instead).
In general I would use a named constant for anything where the name itself carries additional meaning beyond the number. Months, TCP ports, special values (PI
or Integer.MAX_VALUE
), and so on.
Case #3 is architectural, and it's as much about program correctness as readability. There is some nuance here as well. The idea is to understand the logical connection between values, and use constants to connect up things that logically go together. The nuance is that you want to do this only when there is a logical connection between the values--not just because they happen to have the same value.
For example (a little contrived, but I think it works okay), say you're writing an internet service that hosts in both TCP and UDP. You could set both protocols to use the same port number (say 6666) by default; but they are going to be contacted by separate services on the client. There is no reason they have to be the same; someone might have to change them to get around firewall restrictions.
So in this case, I would use two constants, TCP_PORT = 6666
and UDP_PORT = 6666
. I wouldn't put the value directly in the code, unless it was only going to be used exactly once, and the code was simple enough that anyone would be able to find and configure it (an example might be builder-like code that looks more like a DSL than an actual program). But I also wouldn't fold the two constants together into a single PORT
constant, because the two values just happen to be the same: they aren't bound to one another. Folding them together would just require someone to unfold them at some point down the road, which would require changes throughout the module.
TLDR: Use constants when they make your code more maintainable, more readable, and/or faster (roughly in that order). Don't use them if they make your code less readable or less maintainable. In many cases I'd accept a small reduction in performance, if it made the code significantly more readable.