Practical application of Enum


I've always been concerned with the question of the Enum class: what advantages do they have over ordinary static final primitives?

And, if possible, share your experience in which the use of Enum would really be justified.

Author: Артём Ионаш, 2016-08-24

4 answers

enum it has a number of advantages when used in comparison with static final int. And it is worth using it if you need these advantages.

The main difference is that using enum you can check the data type.

For example:

public class SomeClass {
    public static int RED = 1;
    public static int BLUE = 2;
    public static int YELLOW = 3;
    public static int GREEN = 3; // Совпадающие значения

    private int color;

    public void setColor(int color) {
        this.color = color;
    }   
}

In this case, you can pass any value to the class int.

new SomeClass().setColor(999);

Hence, the main problems of using static final int are:

  • The need to check the input data.
  • No no protection against creating a static final int variable with a duplicate value.

Another advantage of enum is the ability to overload methods.

public enum UnitConverter{
    METERS{
        @Override
        public double toMiles(final double meters){
            return meters * 0.00062137D;
        }

        @Override
        public double toMeters(final double meters){
            return meters;
        }
    },
    MILES{
        @Override
        public double toMiles(final double miles){
            return miles;
        }

        @Override
        public double toMeters(final double miles){
            return miles / 0.00062137D;
        }
    };

    public abstract double toMiles(double unit);
    public abstract double toMeters(double unit);
}

Disadvantages of using it enum

  • The operators do not apply to them>, =, enum should not be used in a list of consecutive data.
  • enum also requires more memory to store than a regular constant.

IntDef and StringDef in Android

Google does not recommend use enum in Android apps because it requires more memory. Instead, for Android, you can use IntDef and StringDef which allow you to limit the value space for ordinary constants. Hence, you get the main advantage of enum without losing in memory usage. This practice is commonly used in standard Android classes:

/** @hide */
@IntDef({VISIBLE, INVISIBLE, GONE})
@Retention(RetentionPolicy.SOURCE)
public @interface Visibility {}

/**
 * This view is visible.
 * Use with {@link #setVisibility} and <a href="#attr_android:visibility">{@code
 * android:visibility}.
 */
public static final int VISIBLE = 0x00000000;

/**
 * This view is invisible, but it still takes up space for layout purposes.
 * Use with {@link #setVisibility} and <a href="#attr_android:visibility">{@code
 * android:visibility}.
 */
public static final int INVISIBLE = 0x00000004;

/**
 * This view is invisible, and it doesn't take any space for layout
 * purposes. Use with {@link #setVisibility} and <a href="#attr_android:visibility">{@code
 * android:visibility}.
 */
public static final int GONE = 0x00000008;  

In the receiving state the method uses a special annotation:

public void setVisibility(@Visibility int visibility) {
    setFlags(visibility, VISIBILITY_MASK);
    if (mBackground != null) mBackground.setVisible(visibility == VISIBLE, false);
} 

In this case, you will not be able to use another constant for this method:

view.setVisibility(456);//Error: Must be one of: View.VISIBLE, View.INVISIBLE, View.GONE
 26
Author: Volen, 2016-08-24 22:53:24

Transfers (Enum) it is convenient to use it to represent a set of mutually exclusive states.

Example Enumerations message codes:

enum MessageCode
{
    // Установка однозначного соответствия 
    // между элементом перечисления и целочисленным значением.
    UNKNOWN(0),

    TOAST(1),
    MESSAGE(2);

    private final int id;

    MessageCode(int code)
    {
        id = code;
    }

    // Метод получения целочисленного значения,
    // соответствующего выбранному элементу Перечисления (Enum)
    public int getId()
    {
        return id;
    }

    // Метод получения элемента Перечисления (Enum),
    // соответствующего переданному целочисленному значению
    public static MessageCode fromId(int code)
    {
        MessageCode[] list = MessageCode.values();

        if (code >= 0 && code < list.length)
            return list[code];
        else
            return MessageCode.UNKNOWN;
    }
}

Example of message analysis:

private Messenger chatUIThreadMessenger = new Messenger(new Handler()
{
    @Override
    public void handleMessage(Message msg)
    {
        String str;
        switch (MessageCode.fromId(msg.what))
        {
        // Доступ к выводу Toast'ов для Thread'ов прослушивающих Socket'ы
        case TOAST:
            str = (String) msg.obj;
            Toast.makeText(getBaseContext(), str, Toast.LENGTH_LONG).show();
            break;
        // Вывод сообщений в лог чата
        case MESSAGE:
            str = (String) msg.obj;
            messages.add(str);
            messagesAdapter.notifyDataSetChanged();
            final ListView listView = (ListView) findViewById(R.id.listViewChat);
            listView.smoothScrollToPosition(messagesAdapter.getCount() - 1);
            break;
        // Исключительная ситуация
        case UNKNOWN:
            Toast.makeText(getBaseContext(),
                "Messenger: неопределённый тип сообщения!", Toast.LENGTH_LONG).show();
            break;
        default:
            super.handleMessage(msg);
        }
    }
});
 12
Author: Артём Ионаш, 2016-08-24 18:20:23

Using enum instead of constants is useful, for example, when you want to limit the possible set of values of the k-l argument of a method. If you use a k-l constant (int or String, for example), and the method that should accept it will have the appropriate argument type, then nothing will prevent you from passing something there besides constants. If you use enum, you will not be able to pass anything other than enum.

 9
Author: ЮрийСПб, 2016-08-24 17:26:21

Enum you can use it as an implementation of the pattern Singleton.

Advantages:

  1. Serialization out of the box
  2. Out-of-the-box thread safety
  3. Ability to use EnumSet, EnumMap, etc.
  4. Switch support

Disadvantages

  1. Not lazy initialization

According to Joshua Bloch’and this is the best way to implement the template

public enum Singleton {
    INSTANCE;
}
 2
Author: Denis Vabishchevich, 2018-01-09 11:19:42