Should I Strictly Avoid Using Enums on Android

Should I strictly avoid using enums on Android?

Use enum when you need its features. Don't avoid it strictly.

Java enum is more powerful, but if you don't need its features, use constants, they occupy less space and they can be primitive itself.

When to use enum:

  • type checking - you can accept only listed values, and they are not continuous (see below what I call continuous here)
  • method overloading - every enum constant has its own implementation of a method

    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);
    }
  • more data - your one constant contains more than one information that cannot be put in one variable

  • complicated data - your constant need methods to operate on the data

When not to use enum:

  • you can accept all values of one type, and your constants contain only these most used
  • you can accept continuous data

    public class Month{
    public static final int JANUARY = 1;
    public static final int FEBRUARY = 2;
    public static final int MARCH = 3;
    ...

    public static String getName(final int month){
    if(month <= 0 || month > 12){
    throw new IllegalArgumentException("Invalid month number: " + month);
    }

    ...
    }
    }
  • for names (like in your example)
  • for everything else that really doesn't need an enum

Enums occupy more space

  • a single reference to an enum constant occupies 4 bytes
  • every enum constant occupies space that is a sum of its fields' sizes aligned to 8 bytes + overhead of the object
  • the enum class itself occupies some space

Constants occupy less space

  • a constant doesn't have a reference so it's a pure data (even if it's a reference, then enum instance would be a reference to another reference)
  • constants may be added to an existing class - it's not necessary to add another class
  • constants may be inlined; it brings extended compile-time features (such as null checking, finding dead code etc.)

Why was Avoid Enums Where You Only Need Ints removed from Android's performance tips?

The 2011 answer from Elliot Hugues said that the original reason to avoid enum was for performance reason... as in "processing performance". As this reason was not backed by fact, it was removed from the official documentation.

It has been added later on because enums add a lot more data in memory than using integer.

Why doesn't Android use more enums?

This answer is out of date as of March 2011.

Enums can be used on Froyo and up - according to this answer (Why was “Avoid Enums Where You Only Need Ints” removed from Android's performance tips?) from a member of the Android VM team (and his blog).


Previous Answer:

The official Android team recommendation is to avoid enums whenever you can avoid it:

Enums are very convenient, but
unfortunately can be painful when size
and speed matter. For example, this:

public enum Shrubbery { GROUND, CRAWLING, HANGING }

adds 740 bytes to
your .dex file compared to the
equivalent class with three public
static final ints. On first use, the
class initializer invokes the
method on objects representing each of
the enumerated values. Each object
gets its own static field, and the
full set is stored in an array (a
static field called "$VALUES"). That's
a lot of code and data, just for three
integers. Additionally, this:

Shrubbery shrub = Shrubbery.GROUND;

causes a static field lookup. If
"GROUND" were a static final int, the
compiler would treat it as a known
constant and inline it.

Source: Avoid Enums Where You Only Need Ints

Working with Enums in android

Where on earth did you find this syntax? Java Enums are very simple, you just specify the values.

public enum Gender {
MALE,
FEMALE
}

If you want them to be more complex, you can add values to them like this.

public enum Gender {
MALE("Male", 0),
FEMALE("Female", 1);

private String stringValue;
private int intValue;
private Gender(String toString, int value) {
stringValue = toString;
intValue = value;
}

@Override
public String toString() {
return stringValue;
}
}

Then to use the enum, you would do something like this:

Gender me = Gender.MALE

enum vs android @Intdef - which one is better optimized

@Intdef is clearly more efficient, it carries zero weight over just having static final ints, it's all compile time instructions. enums are classes and as mentioned in your link have a foot print. @Intdef gets you the most basic functionality of enums namely value validation and none of the other features of enums such as automatic String conversions.

Much of the android docs is stale, this could very well be one of them. Back in the early days of android every bit counted but now devices are much more capable. Personally I would choose between those two options depending on what's called for by design and not get too caught up with being efficient. Also the syntax for some of these more advanced annotations doesn't make for clean easy to read code, so not a fan there. However if the situation calls for good old static ints the @Intdef will buy you some protection at the expense of visual clutter.

Enum vs. Static Constants, memory footprint

Enums are an ongoing infinite debate in the Android world.

You can hear a good talk from Romain Guy and Chet Haase about it here: http://www.parleys.com/play/5298f999e4b039ad2298c9e3/chapter57/about

According to this video how big is an object in Dalvik can be calculated as:

overhead of Object + overhead of dlmalloc + data + align
  • The overhead of an Object is exactly 8 bytes.
  • The overhead of dlmalloc can be 4 - 8 bytes (most of the times is 8
    bytes)
  • The size of the data depends on the data (of course)
  • Finally everything must be 8-byte aligned (for example, if you have 12 bytes
    for an Object this will take 16 bytes)

Remember to keep in mind that every value of an enum is actually an instance of an Enum class.

Another important point to keep in mind is the dex file size.
For example, the following enum will take around 1,112 bytes

public static enum Things {
THING_1,
THING_2;
};

Or you can have two static int which will take 128 bytes.

public static int THING_1 = 1;
public static int THING_2 = 2;

You have 10x improvement in the dex file size.

There is also a big different in on how much compiled dalvik code is generated.
For Enum there is a lot of stuff the compiler does for you. There is a static class initialization the first time the class is loaded at runtime. It adds overtime at start-up.

On the other hand enum bring also a lot of pros: readability, usability, type safe code.
I would worry about enum only in particular extreme cases.

Especially when we consider that using ProGuard can optimize Enums converting them to normal int constants.

Kotlin enum class in Android performance

It would appear so, yes.

I created this in Kotlin:

enum class Thingies {
Red,
Green,
Blue
}

And decompiled it with javap -v, and here is the header:

public final class Thingies extends java.lang.Enum<Thingies>
minor version: 0
major version: 52
flags: ACC_PUBLIC, ACC_FINAL, ACC_SUPER, ACC_ENUM

Bottom line: they are identical, so you probably have to treat them the same way.



Related Topics



Leave a reply



Submit