ZOFTINO.COM android and web dev tutorials

Java Enums

Java enum allow you to define a data type which contains a fixed set of constant values. The variable of enum data type can be assigned only one of the valued defined in the enum declaration. Introduced in Java 5, enums make code clean and readable.

Table of Contents

Introduction to Enums

In Java versions before JDK 5, constants are defined using static final variable.

public class OfferType {
	public static final int COUPON = 1;
	public static final int CASHBACK = 2;
}

Here is how the constants are used.

public class Discount{
	private int discType = OfferType.COUPON;
	...
}

The problem with using constant this way is that they are not type safe, meaning you can assign any integer to the variable which should be assigned only defined constants, and values are not meaningful. You will have to write code to access list of constants of a particular type and to find the order of constants.

Enums solve these problems. They are type safe as enum data type is used to declare variables where ever constants are used and they can be assigned only enumeration constants defined in enum. It provides boiler plate code required to access list of constants, convert string to constant, constant to string and to get ordinal value of an enumeration constant.

Declaring Enum

Like class and interface declarations contain class and interface keywords, enums are defined using enum keyword. Here is a enum type example.

public enum  OfferType {
    COUPON, DEAL, SALE, CASHBACK
}

Enums can’t extend any class as it implicitly extends Enum class. If you try to extend it, compiler with throw error Syntax error on token "extends", implements expected.

Using Enum

Here is how enum type variable is declared and a value is assigned to it. Enum data type variable can be used like any other variable, declared as member variable and passed to method and constructors.

OfferType offerType = OfferType.CASHBACK;

Here is the complete example of how enum is used. It also show using switch case statement with enum variable and its values.

public class Offer {
	private String offer;
	private OfferType offerType;

	public String getOffer() {
		return offer;
	}
	public void setOffer(String offer) {
		this.offer = offer;
	}
	public OfferType getOfferType() {
		return offerType;
	}
	public void setOfferType(OfferType offerType) {
		this.offerType = offerType;
	}	

	public int getDiscount() {
		switch (offerType) {
		case CASHBACK:
			return 5;
		case COUPON:
			return 15;
		case DEAL:
			return 25;
		case SALE:
			return 65;
		default:
			return 0;
		}
	}
}
public class OfferTest {
	public static void main(String[] args) {
		
		Offer offer = new Offer();
		
		offer.setOffer("electronics offer");
		offer.setOfferType(OfferType.CASHBACK);
		
		int discPercent = offer.getDiscount();
		System.out.println("discount percentage "+ discPercent);
	}	
}

Output:

discount percentage 5

Special Methods

Compiler adds special methods such as values(), valueOf(), name() and ordinal() methods to enum class. Methods values() and valueOf() can be accessed using class as they are static methods. Method values() returns array of enumeration constants.

OfferType[] types = OfferType.values();

Value method is useful to loop thru all enumeration constants and do something with each enumeration constant.

for(OfferType ot : OfferType.values()) {
	System.out.println("discount percentages "+ Offer.getDiscount(ot));
}

Method valueOf() is used to convert a string value to enum data type.

OfferType cpn = OfferType.valueOf("COUPON");

To get string value of this enum constant, method name() is used.

OfferType sale = OfferType.valueOf("SALE");
System.out.println("enum string value "+ sale.name());

You can know the order of enumeration constant using ordinal() method

System.out.println("Ordinal value "+ offerType.ordinal());

Fields, Methods and Constructors in Enum

Fields, methods and constructors can be defined inside enum. Capability to define fields inside enum allows adding properties to enumeration constants. Methods provide behavior which uses external data and properties of enumeration constants.

To add fields to enumerations, first declare constants inside enum passing comma separated field values. The declaration of enumeration constants inside enum should end with semicolon if constants have field values.

For example, to our offer type enum, lets’ add discount value and type.

	SALE (250, "flat"), 
	CASHBACK (35, "percent");

Then declare field variables.

	private final int discount;   
	private final String discType;

Then declare constructor with parameters and set the arguments to field variables.

	OfferType(int value, String type) {
		discount = value;
		discType = type;
	}

Then you can define methods to provide behavior. In our example, the method will calculate final order amount after discount.

	public float calculateDiscount(float orderAmt) {
		if(discType.equals("percent")) {
			return orderAmt*(100-discount)/100;
		}else {
			return orderAmt - discount;
		}
	}

Here is the offer type enum with fields and methods.

public enum  OfferType {
	COUPON (20, "percent"), 
	DEAL (100, "flat"), 
	SALE (250, "flat"), 
	CASHBACK (35, "percent");

	private final int discount;   
	private final String discType;

	OfferType(int value, String type) {
		discount = value;
		discType = type;
	}
	
	public float calculateDiscount(float orderAmt) {
		if(discType.equals("percent")) {
			return orderAmt*(100-discount)/100;
		}else {
			return orderAmt - discount;
		}
	}
}

Here is how it is used to calculate final order amount

		float orderAmount = 2349;
		OfferType offerType = OfferType.COUPON;
		
		float orderAmtAfterDis = offerType.calculateDiscount(orderAmount);
		System.out.println("order amount after discount "+ orderAmtAfterDis);

Enum with Abstact Methods

By defining methods you can provide behavior for the enum. To provide different behavior for each enumeration constant, you can define abstract method and implement it at enumeration constant level.

public enum  OfferType {
	COUPON (20, "percent"){
		public String describeOffer() {
			return "Coupons, enter coupon on checkout page";
		}
	}, 
	DEAL (100, "flat"){
		public String describeOffer() {
			return "Deals, displayed with product listing";
		}
	}, 
	SALE (250, "flat"){
		public String describeOffer() {
			return "sale, extra discount offer";
		}
	}, 
	CASHBACK (35, "percent"){
		public String describeOffer() {
			return "cashback, applied at checkout without coupon ";
		}
	};

	private final int discount;   
	private final String discType;

	OfferType(int value, String type) {
		discount = value;
		discType = type;
	}
	
	public abstract String describeOffer();
}

Here is how it is used.

		for(OfferType ot : OfferType.values()) {
			System.out.println("about "+ot.name()+" "+ ot.describeOffer());
		}

EnumSet

EnumSet can be used with enums and it can contain only enum values that too all element of the set should be from one enum. Enumset is efficient and can be used for conditional operations such as contains and contains all. To simply put, EnumSet is similar to HashSet but it is efficient and can be used with Enums.

public enum CommunicationChannel {
	EMAIL, SMS, PHONE, CHAT, WHATSUP, FACEBOOK, TWITTER
}
String userSlectedOptionOne = "EMAIL";
CommunicationChannel cc = CommunicationChannel.valueOf(userSlectedOptionOne);


EnumSet<CommunicationChannel> personalCommu = EnumSet.of( 
		CommunicationChannel.EMAIL,
		CommunicationChannel.PHONE,
		CommunicationChannel.CHAT);

if(personalCommu.contains(cc)) {
	System.out.println("user chose personal communication option");
}else {
	System.out.println("user chose auto communication option");
}

EnumMap

EnumMap is similar to HashMap but it is efficient and can be used with enums. All the keys should be from one enum type. EnumMap maintains the same order for keys as the order in which enumeration constants are defined in the enum.

EnumMap<OfferType, Double> offerOrderAmtMap = new EnumMap<OfferType, Double>(OfferType.class);

offerOrderAmtMap.put(OfferType.COUPON, 200.00);
offerOrderAmtMap.put(OfferType.DEAL, 500.00);
offerOrderAmtMap.put(OfferType.SALE, 999.99);
offerOrderAmtMap.put(OfferType.CASHBACK, 1555.30);

double totalOrderAmt = 899.99;


for(OfferType ot : offerOrderAmtMap.keySet()) {
	if(totalOrderAmt < offerOrderAmtMap.get(ot)){
		System.out.println("applicable offer is "+ot.name());
		break;
	}
}