Lesson 32
Including Magic Numbers and Enums

We use enums to define a set of predefined, related constants. Some common examples include the months of the year and days of the week. In this shorter lesson, we'll look at how to create and use enums. Enums are a construct that allows us to define a group of related constants.

MAGIC NUMBERS

A magic number is a value that is hard-coded into your code but does not have a clear meaning. For example, suppose we had an order-entry system. As each order is processed, it could have a status of Quoted, Purchased, Shipped, or Delivered.

In languages that do not provide enums, a developer will often simply assign a numeric code to each status, so you could end up looking at code such as what is shown in Listing 32.1.

LISTING 32.1

Coding without an Enum

public void shipOrder(Order order) {
    if(order.getStatus() == 2) { // purchased
        // ship it
 
        // move to shipped status
        o.setStatus(3);
    }
}

With the comments, the code is clearer, but without the comments, a developer unfamiliar with the order status codes would not know what 2 and 3 mean. This listing might work now, but what happens if a change is needed? Software tends to change over time, so what would we do when we need to add steps in the middle?

For example, what would happen if we needed to add a Gift Wrap stage in between Purchased and Shipped? In that case, the order of steps could end up being 1, 2, 5, 3, 4. The larger the workflow becomes and the more insertions and deletions are made, then the more unwieldy hard-coding numbers actually becomes.

This is where enums become useful.

ENUMS

As mentioned, enums are a construct that allows us to define a group of related constants. In other words, we can define a controlled vocabulary for the constants we are interested in. For example, we can use an enum to define the order status options in the previous example, define the days of the week, or even identify the different shifts at a factory.

You have already seen that constants are far better than hard-coded magic numbers in your code. Enums take constants a step further in that they are all grouped together and are type safe. It is also easier to see which enum values are valid and which are not.

There are many sophisticated things that can be done with enums; many of them are not available in other languages, but these features are beyond the scope of this lesson and beyond your needs at this stage of your development career. We will concentrate on using enums as better constants.

Creating Enums for Fixed Constants

Defining a Java enum is similar to defining a class or interface. For example, we could define an enum to be used as a set of fixed constants for the basic math operators: addition, subtraction, multiplication, and division. This enum could then be used in a simple math program.

Creating an enum for use as a set of constants is straightforward. Simply list each item in the enum vocabulary in a comma-separated list in the body of the enum like this:

public enum MathOperator {
    ADD, SUBTRACT, MULTIPLY, DIVIDE
}

Using Enums

One of the advantages of using enums over regular constants is that an enum is a proper type. This means we can use a particular enum type in the formal parameter list of a method and in switch statements.

To illustrate this, we will create a class that performs simple math operations on two integers. This class has one method—calculate()—that has three parameters:

  • The operation to perform
  • Operand 1
  • Operand 2

We then assign each of the enum values to a specific operation using a switch statement, as shown in Listing 32.2.

LISTING 32.2

Using a Switch and Enum Together

public class IntMath {
 
    public int calculate(MathOperator operator, int operand1, int operand2) {
 
        switch(operator) {
            case ADD:
                return operand1 + operand2;
            case SUBTRACT:
                return operand1 - operand2;
            case MULTIPLY:
                return operand1 * operand2;
            case DIVIDE:
                return operand1 / operand2;
            default:
                throw new UnsupportedOperationException();
        }
    }
}

Here are some things to note about this code:

  • The first formal parameter of this method is of type MathOperator, which is the enum type that we just created. This guarantees that the only values allowed as operators are ADD, SUBTRACT, MULTIPLY, and DIVIDE.
  • When using an enum in a switch statement, the values in the case statements must be unqualified—in other words, ADD versus MathOperator.ADD.
  • The return statements in each case negate the need for break statements.
  • We have chosen to throw an UnsupportedOperationException if we don't recognize the operator.

Listing 32.3 presents an application class that uses the MathOperator enum along with the IntMath class.

LISTING 32.3

Using the IntMath Class

public class App {
 
  public static void main(String[] args) {
    
     IntMath num1 = new IntMath();
     int result;
     
     result = num1.calculate(MathOperator.ADD, 10, 5);
     System.out.println("Add: " + result);
     
     result = num1.calculate(MathOperator.SUBTRACT, 10, 5);
     System.out.println("Subtract: " + result);
     
     result = num1.calculate(MathOperator.MULTIPLY, 10, 5);
     System.out.println("Multiply: " + result);
     
     System.out.println("Divide: " + num1.calculate(MathOperator.DIVIDE, 10, 5));
  }
}

In this listing, you can see that an IntMath() object is created called num1. It is then used to do calculations. The type of calculation will be based on the MathOperator enum that was created. You can see that using MathOperator.ADD results in the ADD case in Listing 32.2 being called. Using MathOperator.SUBTRACT results in the corresponding SUBTRACT case being used. The end result is that the use of the enum makes it clear what the listing is trying to accomplish. When the program is executed, the results should look like the following:

Add: 15
Subtract: 5
Multiply: 50
Divide: 2

Getting Values from an Enum

Many times, we might use an enum that has been defined in a different file. As such, we might not be aware of the values it contains. In Java, when an enum is created by the compiler, a method called values() is added to the enum. This method allows you to access the values that the enum contains.

In Listing 32.4, we illustrate a simple use of the values() method using an enhanced for loop to show all the entries in an enum of months.

LISTING 32.4

The Month Enum

public class Test {
    enum Month { JANUARY, FEBRUARY, MARCH,
                 APRIL, MAY, JUNE, 
                 JULY, AUGUST, SEPTEMBER, 
                 OCTOBER, NOVEMBER, DECEMBER }
 
    public static void main(String[] args) {
        for (Month m : Month.values())
            System.out.println(m);
    }
}

In the listing, an enhanced loop cycles through the values in the Month enum and prints each entry.

JANUARY
FEBRUARY
MARCH
APRIL
MAY
JUNE
JULY
AUGUST
SEPTEMBER
OCTOBER
NOVEMBER
DECEMBER

ENUM MEMBERS

The Month enum in Listing 32.4 presents a common but basic usage of enums using constant values. Enums, however, can do a lot more by including additional members, specifically fields and methods. Members of an enum are implicitly declared as public static members that cannot be changed. In Listing 32.5, the Month enum is expanded to provide more functionality.

When we review Listing 32.5, we can see that the enum looks a lot like other classes with a few key differences. First, it is declared with the enum keyword. This sets the type as an enum instead of a standard class. Second, the members of the enum, both fields and methods, are all declared by default as public final. This means that once defined, they cannot be changed.

In the listing, we didn't just define the value for the enum items, such as JANUARY; we also included defining values for each. In this case, we included two additional numbers. The first is the order in which the month appears in the year, and the second is the number of days the month contains. We included these in parentheses after each month's entry. To maintain the value for the enum, we declared two private variables to hold the values as well as declared a constructor to assign the values.

private int order;
private int days;
 
Month(int order, int days) {
    this.order = order;
    this.days = days;
}

As you can see, we store the values as order and days. With the constructor, we assign the initializing value into the private variables of our existing enum. To access these values, we have created member functions that can be used. We can do more than just access these values from within our enum, which is illustrated by the monthToSeason() method that determines the season and returns it.

Listing 32.6 is a short listing that uses the updated Month enum and its methods.

LISTING 32.6

Using the Month Enum

package com.tsg.moreenumfun;
 
public class MoreEnumFun {
 
    public static void main(String[] args) {
 
        Month month;
        month = Month.JANUARY;
        
        System.out.println("Month: " + month.numberOfDays());
        System.out.println("====");
 
        for (Month i : Month.values()) {
            System.out.println("Month: " + i + " - " + i.monthToNumber()
                    + " - " + i.numberOfDays() + " - " + i.monthToSeason());
        }
    }
}

In this listing, a variable called month is defined as a Month enum. This value is then assigned a value from the enum, in this case Month.January. Following the assignment, a simple call to System.out.println displays the number of days within the month we assigned—in this case, 31 days.

In addition to showing how a month can be declared, assigned, and displayed, the listing also uses an enhanced for loop to show how you can cycle through the enum and see not only the entries but also the values associated to each entry. When Listing 32.6 is executed, the following is displayed:

Month: 31
====
Month: JANUARY - 1 - 31 - Winter
Month: FEBRUARY - 2 - 28 - Winter
Month: MARCH - 3 - 31 - Winter
Month: APRIL - 4 - 30 - Spring
Month: MAY - 5 - 31 - Spring
Month: JUNE - 6 - 30 - Spring
Month: JULY - 7 - 31 - Summer
Month: AUGUST - 8 - 31 - Summer
Month: SEPTEMBER - 9 - 30 - Summer
Month: OCTOBER - 10 - 31 - Fall
Month: NOVEMBER - 11 - 30 - Fall
Month: DECEMBER - 12 - 31 - Fall

Of course, the point of an enum is to be able to access these values as constants within your listings, more so than simply printing the values out.

SUMMARY

That's all there is to it. We introduce this topic here because, as we begin to use other libraries, we see enums more and more, and we want you to understand how they work.

The important takeaways from this lesson are the following:

  • Enums are used as a way to group related constants.
  • Enums are first-class types and can be used as formal parameters to methods and in switch statements.
  • Items in an enum should be in all caps since they are constants.
  • Enums are used widely, and you will start to see them in other APIs and frameworks as we program larger applications.

EXERCISES

The following exercises will help you practice what you are learning about enums in this lesson. These are to do on your own.

  • Exercise 1: How Many Days until Friday?
  • Exercise 2: Playing Cards

Exercise 1: How Many Days until Friday?

In this exercise, create an enum for every day of the week. Then, create an App class that asks the user to enter a day of the week and then use a switch statement and your enum to print out how many days there are until Friday.

Exercise 2: Playing Cards

Create two enums: one that contains the four suits in a card deck (CLUBS, DIAMONDS, HEARTS, and SPADES) and a second one that contains the names of the ranks of cards such as ACE, TWO, THREE, etc.

Use your newly created enums in a listing that should randomly select a card by selecting a random suit and a rank and then display the card to the console. Here's an example:

ACE CLUBS

Once you've completed printing a card, modify your listing to select and print five cards randomly. Your output could look something like the following:

Drawing a hand of cards: 
THREE DIAMONDS
KING CLUBS
SIX CLUBS
FOUR HEARTS
NINE HEARTS
..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
3.145.166.7