Defining Java Constants
Yeah, I understand. What's the big deal in defining constants in Java. But hold on, and spare me a few minutes. Read on. As a standard practice constants must be defined for values
which do not change in the application. The use of string literals and numbers scattered across the code is
discouraged. It is always a good practice to define constants for all of those
values which is used at multiple places. Let’s first check the rules.
Final and Static
What
makes a literal or a numeric value “constant”? Java provides for a keyword
“final”. Anything that is final cannot be changed once its value is set (in the context of a field). Thus any constant should be accompanied by the keyword “final”. The keyword “static”
however is not mandatory to define a constant. A constant is something which is
expected to be used outside the scope of the class, in most probability, would
remain the same throughout the application. If that is the case, then the
constant should be defined as “public” and “static”.
public static final int MAX_COUNT = 5;
|
If the constant will be used within the scope of a class
(private field), then you must be aware how often that class potentially will
be initalized. If the initialization is not that commonplace then a better
approach would be to avoid marking it “static”
and only “final” should suffice. The object would be garbage collected when
the usage is over and will not put load on memory when it is not used.
A cache is also a constant entity. Such objects should be
defined as a singleton. Usually such classes will also be immutable – i.e. the
values should be set via a constructor or a builder and should never change
during the lifetime of the object. Choose between “eager” and “lazy”
initialization of such objects according to the project need.
Enums
Before java 1.5, there was no way to group constants. For
example if we have types of phone to be represented as constants we would
probably have done it this way.
public static String FIXEDLINE = "Fixed Line";
public static String MOBILE = "Mobile";
public static String FAX =
"Fax";
|
This has two major problems:
- These are a part of a “group” called “Phone Type” but there is no way to classify them as such
- These are of type “String”, which means any method declared which takes in a parameter of “Phone Type” must handle the condition when the phone type is not one of the above three values. (as shown below)
public static int getPhoneTypeCode(String phoneType){
if (FIXEDLINE.equals(phoneType))
return 1;
else if (MOBILE.equals(phoneType))
return 2;
else if (FAX.equals(phoneType))
return 3;
else
throw new IllegalArgumentException("The phoneType is invalid.");
}
|
The good part is that we can use enums to declare constants.
(Other details and usage of enums are discussed in the enum section of the
book). The constants can be grouped under the enum “PhoneType” which has the
elements FIXEDLINE, MOBILE and FAX declared under it. Better still, since each
element of the enum itself behaves like a singleton class, they can hold
methods, and individual values (such as description & code) within it.
public enum PhoneType {
FIXEDLINE ("Fixed Line", 1),
MOBILE ("Mobile", 2),
FAX ("Fax", 3);
// description for phone type
private String desc;
private int code;
private PhoneType(String desc, int code){
this.desc = desc;
this.code = code;
}
public String desc() { return this.desc; }
public int code() { return this.code; }
}
|
The ‘code’, for example will be a part of the declaration of
each phoneType and can be directly accessed by the method call.
int code
= PhoneType.FIXEDLINE.code();
|
Combining Constants
Another way to declare constants for a group of values is in
the form of integers and combining them to hold multiple constant values. We
can use the logical OR operation to
then check and operate upon these constants. Let us talk about this in a little
detail. Say, you have Coffee object,
which has multiple add-ons such as: MILK,
SUGAR, CREAM & CHOCOLATE
and you can have none, or a combination of one or more of the add-Ons on the
coffee. How would you define your constants so that you can use multiple
add-Ons with coffee? One way is to define each add-On as a string and have a
list assigned to the coffee object, which holds these constants. So if there
are many add-Ons then the list would have more than one element. The problem
with this approach is that we would have to iterate the entire list every time
we want to find which add-Ons were used in the coffee.
We will leverage the bitwise operation provided by the Java
language. The java bitwise operators and bit-shift operators are performed on
the Java integral types. They manipulate the bit digits instead of the whole
numbers. Before we start defining the constant, let us review a quick example.
Have a look at the method below. The construct – “i1 & i2” actually
does a bitwise or comparison.
private static int And(int i1, int i2){
return i1 & i2;
}
|
If we pass in the integers 20 and 37, we would get back the
number 4.
public static void main(String... args) {
int n1 = 20; // 0001 0100
int n2 = 37; // 0010 0101
// the operation would be
// 0001 0100
// AND
// 0010 0101
// ----------
// 0000 0100 // 4
in decimal
// ----------
System.out.println(And(n1, n2));
}
|
The above main method would print 4 in decimal value.
Similarly if we replace the AND ( &
) with OR ( | ) operator, the
result would be 53 in decimal.
Returning to the main topic, we can define the group of
constants (or add-Ons) in this way to leverage this feature of the java
programming language. Let us review the add-Ons of the coffee object, which are:
MILK, SUGAR, CREAM and CHOCOLATE. We can define them as
constants as a multiple of 2 (or a binary multiplication of 10). If we use this
declaration we can blend any combination and segregate anyone using the bitwise
operators.
public static final int MILK = 1; // binary 0001
public static final int SUGAR = 2; // binary 0010
public static final int CREAM = 4; // binary 0100
public static final int CHOCOLATE = 8; // binary 1000
|
Say you want a coffee
with
- SUGAR and CREAM then the value would be SUGAR + CREAM = 2 + 4 = 6 (or 0110)
- MILK, CREAM and CHOCOLATE -> MILK + CREAM + CHOCOLATE = 1 + 4 + 8 = 13 (or 1101)
Just in case you remembered the Unix command - ‘chmod’, then yes, we are doing the same
thing. You just need to add the numbers to come up with a combination. So the
coffee with sugar and cream would be represented by 6, and coffee with milk,
cream and chocolate would have the number 13. Using a simple bitwise AND operator you can find out if the
coffee contains MILK, CREAM, SUGAR or CHOCOLATE. Consider this, if there is any
one item doing a bitwise AND operation on that would give a result other than
0.
If we need to check if the combination has MILK, all that we need to do is do a
bitwise AND operation between the
combination and MILK. If the
resultant number is not 0 (zero), then the combination contains MILK. If we check the same combination
with SUGAR, we would get back 0
(zero), and so we can conclude that the combination does not have SUGAR. To close it lets have a look at
the Java code.
/**
* This is the method which will evaluate the
if the combination
* has the addOn
*
* @param addOn - the
addOn which is being checked
* @param addOns - the
addOns which the Coffee has
* @return true if addOn is a part of the coffee,
* false if it is
not a part of the addOn
*/
public static boolean hasAddOn(int addOn, int addOns){
return (addOn & addOns) != 0;
}
public static boolean hasMilk(int addOns){
return hasAddOn(MILK, addOns);
}
public static boolean hasSugar(int addOns){
return hasAddOn(SUGAR, addOns);
}
public static boolean hasCream(int addOns){
return hasAddOn(CREAM, addOns);
}
public static boolean hasChocolate(int addOns){
return hasAddOn(CHOCOLATE, addOns);
}
|
If the constants are declared this way, we can combine
multiple features in a single value, sparing a lot of object creation, which in
turn saves both time and space. Note that the individual values should double
for each ‘constant’ declaration; else the system does not work. We can also
leverage the ‘enums’ here and combine both the styles to come up with a better
suited declaration.
When declaring a constant, programmers should think thoroughly about its. A constant when declared, especially when within an API is very
difficult to change, so do spare a moment of thought when declaring them.
Comments
Post a Comment