3

I heard now a day that We should use Enums instead of Constants . Is it possible in all cases ? Whether enums are replacement of Constants ?

In Below Example I have Constants defined in Constants file and ConstantsTest uses them

public final class Constants {

private Constants(){

}
public static final String ACCOUNT="Account";
public static final String EVENT_ITEM ="EventItem";
public static final int MULTIPLIER_ONE = 1;
public static final int MULTIPLIER_NEGATIVE_ONE = -1;
public static final String BALANCE_AFTER_MODIFICATION = "BalanceAfterModification";
public static final String COMMA = ",";
public static final String DOTPSV =".psv";
public static final String NEW_LINE = "\n";
}


 // Test Class
import java.io.File;
import java.io.FileWriter;
import java.io.IOException;
import java.util.HashMap;
import java.util.Map;

public class ConstantsTest {
private static File rootDir = new File(".");    
public static void main(String[] args) throws IOException {

    Map<String,Integer> accountBalance = new HashMap<String, Integer>();
    accountBalance.put("123",55000);
    accountBalance.put("223",15000);
    writeToFile(Constants.ACCOUNT, accountBalance, true, 2000);
    // do operation 

 }

/**
 * 
 * @param fileType
 * @param inputData
 * @param add if true add balance  else substract the balance 
 * @return
 * @throws IOException
 */
 private static File writeToFile(String fileType , Map<String,Integer>accountBalance ,boolean add, int amount) throws IOException{
     File file = null; 
     FileWriter fw = null;
     try{
         if(Constants.ACCOUNT.equals(fileType)){
             file = new File(rootDir,Constants.ACCOUNT+Constants.DOTPSV);//creating a fileName using constants
             fw = new FileWriter(file);
             fw.write(Constants.ACCOUNT+Constants.COMMA+Constants.BALANCE_AFTER_MODIFICATION);//Writing Header in file using constant values
             updateBalance(accountBalance, add, amount);
             for(String key:accountBalance.keySet()){
                 fw.write(Constants.NEW_LINE);
                 fw.write(key+Constants.COMMA+accountBalance.get(key));
             }
         }
         else if(Constants.EVENT_ITEM.equals(fileType))
         {
             // write to EventItem.psv
         }
     } finally{
         if (null!=fw){
             fw.close();
         }
     }

     System.out.println("File created successfully");
     return file;

 }

private static void updateBalance(Map<String, Integer> accountBalance,
        boolean add, int amount) {
    for(String key:accountBalance.keySet()){
         int currentBal = accountBalance.get(key);
         if(add){
             accountBalance.put(key,currentBal+amount*Constants.MULTIPLIER_ONE); // do lot of calculations
         }else{
             accountBalance.put(key,currentBal+amount*Constants.MULTIPLIER_NEGATIVE_ONE);// do a lot of calculations
         }
     }
}

}

Please suggest in my sample example enums would be better or my current approach of using constants is good enough ?

Shirishkumar Bari
  • 2,692
  • 1
  • 28
  • 36
  • 2
    Seems like a duplicate of [JAVA Constants: Enums VS Classes VS Interfaces](http://stackoverflow.com/questions/6144227/java-constants-enums-vs-classes-vs-interfaces), with additional duplicate candidate of [enums for constants in java - is this good style?](http://stackoverflow.com/questions/367104/enums-for-constants-in-java-is-this-good-style) – Oleg Estekhin Jul 02 '14 at 06:39
  • From a design perspective, your code gives a totally different meaning when compared against Enums. – TheLostMind Jul 02 '14 at 06:42
  • @ Scary I have shown this code to let viewer know I have used constants for different purpose at different steps . Also I have used Interface for defining constants .. so they are by default public static final – Shirishkumar Bari Jul 02 '14 at 06:45
  • 1
    [Don't use an interface just for constants](https://stackoverflow.com/questions/320588/interfaces-with-static-fields-in-java-for-sharing-constants) – awksp Jul 02 '14 at 06:47
  • Sorry, I did not notice you were using an interface – Scary Wombat Jul 02 '14 at 06:49
  • 1
    @TheLostMind Right. Edited. I didn't look at the code when I wrote that, so I wasn't in a position to judge design, but a quick look just makes me confused... – awksp Jul 02 '14 at 06:50
  • Hi All, I have changed the Constant defination as class Instead of interface .. i will be using it in the same fashion from now On ...... Focus of my question is about preferring Enums over constants as when there uses can be different as given in above example Code – Shirishkumar Bari Jul 02 '14 at 07:07

6 Answers6

4

In your particular case the using enums is classic solution.

First, let's re-write your Constants as an enum:

public enum Constants {
    ACCOUNT,
    EVENT_ITEM,
    ;

}

public enum Operation {
   MULTIPLIER_ONE {
        public int action(int value) {
            return value;
        }
   },
   MULTIPLIER_NEGATIVE_ONE {
        public int action(int value) {
            return value * (-1);
        }
   },
   ;
   private Operation(int coef) {
        this.coef = coef;
   }

   public abstract int action(int value);
}

Now instead of writing:

if(Constants.ACCOUNT.equals(fileType)){
} else if(....)

you can either use switch/case or even better define: define method (let's call it action() into the enum and call it from your code. See example in Operation enum above. In this case you code becomes trivial: no more if/else or switch statements. Everything is simple. Validation is done at compile time: you defined abstract method in enum you cannot add yet another element to enum without implementing this method for it. This does not happen when using if/else structures maintenance of which is a programmer's responsibility.

I know only one limitation of enums: using string contstants in annotations. There are a lot of annotations with string attributes. For example XmlElement(name="foo"). Even if you define enum

enum FooBar {
    foo, bar
}

you cannot use it in annotations:

@XmlElement(name=FooBar.foo) // is wrong because String type is required
@XmlElement(name=FooBar.foo.name()) // is wrong because annotations do not support method invocation 

In all other cases I prefer enum.

AlexR
  • 114,158
  • 16
  • 130
  • 208
2

You should use enums this code

enum Constants {
  ACCOUNT,
  EVENT_ITEM ,
  COMMA ,
  DOTPSV ,
  BALANCE_AFTER_MODIFICATION ;

@Override
public String toString() {
  switch(this) {
    case ACCOUNT: return "Account";
    case EVENT_ITEM : return "EventItem";
    case COMMA : return ",";
    case DOTPSV : return ".psv";
    case BALANCE_AFTER_MODIFICATION : return "BalanceAfterModification";
    default: throw new IllegalArgumentException();
   }
 }
}
1

Only we can use Enums for the constant values which are in the single group. Let us suppose: Weeks, Months, Colours, Gender, Process states

It is not the good idea to use single enum for storing all constants. Instead we can use one enum for each group of constants.

Let us suppose you have maintaining some colour codes then better to have Colour enum instead of saving as constants.

Prasanna
  • 303
  • 2
  • 16
Srinivas
  • 52
  • 6
0

An Enum doesn't define a contract for the class using it, an interface does. A class which uses an Enum isn't of the type an Enum. A class which implements an Interface is effectively of the same type as the interface (the Interface is the parent.. and the reference could be changed). Considering these design issues. Tell me, is your approach correct?

TheLostMind
  • 35,966
  • 12
  • 68
  • 104
  • my class doesnt implement the Interface. I have used interface to define the constants .... so they are by default public static final ... I dont have to write it for every constants – Shirishkumar Bari Jul 02 '14 at 06:50
  • @Shree - Strictly speaking.. An `Interface` defines an unbreakable contract implicitly. You might not be using it. But you are still providing the capability for it (which is against OOP concepts). – TheLostMind Jul 02 '14 at 06:55
  • 1
    @Shree you are letting laziness dictate your design? – Scary Wombat Jul 02 '14 at 06:56
  • well I have gone through URL which gave me good insight as why interface is bad practice for using it to write just constants ..... That I agree with you ... I will follow it in future ... but the main question is about using enums as replacement to constants. – Shirishkumar Bari Jul 02 '14 at 06:58
0

Constants will be better for the example provided. Interface variables are public static final by default.

public static final String ACCOUNT="Account";

See Why are interface variables static and final by default?

Community
  • 1
  • 1
vinayknl
  • 1,242
  • 8
  • 18
0

You got enum wrong, it's not like you should create an enum instead of constant: an enum is a group of constants that are related, for example:

enum Days {
    SUNDAY, MONDAY, TUESDAY, ...
}

From the docs:

An enum type is a special data type that enables for a variable to be a set of predefined constants.

Nir Alfasi
  • 53,191
  • 11
  • 86
  • 129