Java 我应该严格避免在 Android 上使用枚举吗?

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/29183904/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-11 07:31:33  来源:igfitidea点击:

Should I strictly avoid using enums on Android?

javaandroidenums

提问by nvinayshetty

I used to define a set of related constants like Bundlekeys together in an interface like below:

我曾经Bundle在如下界面中定义了一组相关的常量,比如键:

public interface From{
    String LOGIN_SCREEN = "LoginSCreen";
    String NOTIFICATION = "Notification";
    String WIDGET = "widget";
}

This provides me a nicer way to group related constants together and used them by making a static import (not implements). I know Androidframework also uses the constants in same way like Toast.LENTH_LONG, View.GONE.

这为我提供了一种更好的方法来将相关常量组合在一起,并通过进行静态导入(而不是实现)来使用它们。我知道Android框架也以相同的方式使用常量,如Toast.LENTH_LONG, View.GONE

However, I often feel that the Java Enumsprovide much better and powerful way to represent the constant.

但是,我经常觉得Java Enums提供了更好、更强大的方式来表示常量。

But is there a performence issue in using enumson Android?

但是使用enumson是否存在性能问题Android

With a bit of research I ended up in confusion. From this question "Avoid Enums Where You Only Need Ints” removed from Android's performance tips?it's clear that Googlehas removed "Avoid enums"from its performance tips, but from it's official training docs Be aware of memory overheadsection it clearly says: "Enums often require more than twice as much memory as static constants. You should strictly avoid using enums on Android."Is this still holds good? (say in Javaversions after 1.6)

经过一些研究,我最终陷入了困惑。从这个问题 “Avoid Enums Where You Only Need Ints”中删除了Android的性能提示?很明显Google已经从它的性能提示中删除了“Avoid enums”,但是从它的官方培训文档注意内存开销部分它清楚地说:“Enums通常需要比静态常量多两倍的内存。你应该严格避免在 Android 上使用枚举。”这仍然有效吗?(Java在 1.6 之后的版本中说)

One more issue that I observed is to send enumsacross intentsusing BundleI should send them by serializing (i.e putSerializable(), that I think an expensive operation compared to primitive putString()method, eventhough enumsprovides it for free).

还有一个问题,我观察到的是发送enumsintents使用Bundle我应该序列化给他们(即putSerializable(),我认为一个昂贵的操作比较原始的putString()方法沉绵enums提供它是免费的)。

Can someone please clarify which one is the best way to represent the same in Android? Should I strictly avoid using enumson Android?

有人可以澄清哪一种是表示相同的最佳方式Android吗?我应该严格避免使用enumsonAndroid吗?

采纳答案by Kamil Jarosz

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

enum当您需要其功能时使用。不要严格避免它

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.

Java enum 更强大,但如果你不需要它的特性,使用常量,它们占用更少的空间并且它们本身可以是原始的。

When to use enum:

何时使用枚举:

  • type checking - you can accept onlylisted values, and they are not continuous (see below what I call continuoushere)
  • 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
  • 类型检查-你可以接受列出的值,而且他们是不连续的(见下面就是我所说的连续点击这里)
  • 方法重载 - 每个枚举常量都有自己的方法实现

    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);
    }
    
  • 更多数据 - 你的一个常量包含多个不能放在一个变量中的信息

  • 复杂的数据 - 您不断需要对数据进行操作的方法

When notto 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
  • 您可以接受一种类型的所有值,并且您的常量仅包含这些最常用的
  • 你可以接受连续数据

    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);
            }
    
            ...
        }
    }
    
  • 对于名称(如您的示例)
  • 对于真正不需要枚举的其他所有内容

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' sizesaligned to 8 bytes + overhead of the object
  • the enum class itself occupies some space
  • 对枚举常量的单个引用占用4 个字节
  • 每个枚举常量占用的空间是其字段大小总和对齐到 8 个字节 +对象的开销
  • 枚举类本身占用了一些空间

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.)
  • 常量没有引用,因此它是纯数据(即使它是引用,枚举实例也将是对另一个引用的引用)
  • 常量可以添加到现有的类 - 没有必要添加另一个类
  • 常量可以被内联;它带来了扩展的编译时功能(例如空检查、查找死代码等)

回答by stan0

Should I strictly avoid using enums on Android?

我应该严格避免在 Android 上使用枚举吗?

No. "Strictly" means they are so bad, they should not be used at all. Possibly a performance issues might arise in an extreme situation like many many many(thousands or millions of) operations with enums (consecutive on the ui thread). Far more common are the network I/O operations that should strictlyhappen in a background thread. The most common usage of enums is probably some kind of type check - whether an object is thisor thatwhich is so fast you won't be able to notice a difference between a single comparison of enums and a comparison of integers.

不。“严格”意味着它们太糟糕了,根本不应该使用它们。在极端情况下可能会出现性能问题,例如使用枚举(在 ui 线程上连续进行)的许多(数千或数百万)操作。更常见的是应该严格发生在后台线程中的网络 I/O 操作。枚举最常见的用法可能是某种类型的检查——一个对象是这个还是那个,它太快了,你将无法注意到枚举的单个比较和整数的比较之间的区别。

Can someone please clarify which one is the best way to represent the same in Android?

有人可以澄清哪一种是在Android中表示相同的最佳方式吗?

There is no general rule of thumb for this. Use whatever works for you and helps you get your app ready. Optimize later - after you notice there's a bottleneck that slows some aspect of your app.

对此没有一般的经验法则。使用适合您的任何东西并帮助您准备好您的应用程序。稍后优化 - 在您注意到有一个瓶颈会减慢您的应用程序的某些方面。

回答by android developer

If the enums simply have values, you should try to use IntDef/StringDef , as shown here:

如果枚举只有值,您应该尝试使用 IntDef/StringDef ,如下所示:

https://developer.android.com/studio/write/annotations.html#enum-annotations

https://developer.android.com/studio/write/annotations.html#enum-annotations

Example: instead of :

示例:而不是:

enum NavigationMode {NAVIGATION_MODE_STANDARD, NAVIGATION_MODE_LIST, NAVIGATION_MODE_TABS} 

you use:

你用:

@IntDef({NAVIGATION_MODE_STANDARD, NAVIGATION_MODE_LIST, NAVIGATION_MODE_TABS})
@Retention(RetentionPolicy.SOURCE)
public @interface NavigationMode {}

public static final int NAVIGATION_MODE_STANDARD = 0;
public static final int NAVIGATION_MODE_LIST = 1;
public static final int NAVIGATION_MODE_TABS = 2;

and in the function that has it as a parameter/returned value , use:

并在将其作为参数/返回值的函数中,使用:

@NavigationMode
public abstract int getNavigationMode();

public abstract void setNavigationMode(@NavigationMode int mode);

In case the enum is complex, use an enum. It's not that bad.

如果枚举很复杂,请使用枚举。它没有那么坏。

To compare enums vs constant values, you should read here:

要比较枚举与常量值,您应该在这里阅读:

http://hsc.com/Blog/Best-Practices-For-Memory-Optimization-on-Android-1

http://hsc.com/Blog/Best-Practices-For-Memory-Optimization-on-Android-1

Their example is of an enum with 2 values. It takes 1112 bytes in dex file compared to 128 bytes when constant integers are used . Makes sense, as enums are real classes, as opposed to how it works on C/C++ .

他们的例子是一个有 2 个值的枚举。与使用常量整数时的 128 字节相比,它在 dex 文件中需要 1112 字节。有道理,因为枚举是真正的类,而不是它在 C/C++ 上的工作方式。

回答by Grisgram

I like to add, that you can not use @Annotations when you declare a List<> or Map<> where either key or value is of one of your annotation interfaces. You get the error "Annotations are not allowed here".

我想补充一点,当您声明 List<> 或 Map<> 时,您不能使用 @Annotations,其中键或值属于您的注释接口之一。您收到错误“此处不允许使用注释”。

enum Values { One, Two, Three }
Map<String, Values> myMap;    // This works

// ... but ...
public static final int ONE = 1;
public static final int TWO = 2;
public static final int THREE = 3;

@Retention(RetentionPolicy.SOURCE)
@IntDef({ONE, TWO, THREE})
public @interface Values {}

Map<String, @Values Integer> myMap;    // *** ERROR ***

So when you need to pack it into a list/map, use enum, as they can be added, but @annotated int/string groups can not.

因此,当您需要将其打包到列表/映射中时,请使用 enum,因为它们可以添加,但 @annotated int/string 组不能。

回答by Gaket

In addition to previous answers, I would add that if you are using Proguard (and you should definitely do it to reduce size and obfuscate your code), then your Enumswill be automatically converted to @IntDefwherever it is possible:

除了之前的答案之外,我还要补充一点,如果您正在使用 Proguard(并且您绝对应该这样做以减小大小并混淆您的代码),那么您Enums将自动转换为@IntDef任何可能的位置:

https://www.guardsquare.com/en/proguard/manual/optimizations

https://www.guardsquare.com/en/proguard/manual/optimizations

class/unboxing/enum

Simplifies enum types to integer constants, whenever possible.

类/拆箱/枚举

尽可能将枚举类型简化为整数常量。

Therefore, if you have some discrete values and some method should allow to take only this values and not others of the same type, then I would use Enum, because Proguard will make this manual work of optimizing code for me.

因此,如果您有一些离散值并且某些方法应该只允许采用这些值而不是其他相同类型的值,那么我会使用Enum,因为 Proguard 将为我进行优化代码的手动工作。

And here isa good post about using enums from Jake Wharton, take a look at it.

这里是如何使用枚举从Hyman沃顿好的帖子,看看它。

As a library developer, I recognize these small optimizations that should be done as we want to have as little impact on the consuming app's size, memory, and performance as possible. But it's important to realize that [...] putting an enum in your public API vs. integer values where appropriate is perfectly fine. Knowing the difference to make informed decisions is what's important

作为库开发人员,我认为应该进行这些小的优化,因为我们希望对消费应用程序的大小、内存和性能产生尽可能小的影响。但重要的是要意识到 [...] 在你的公共 API 中放置一个枚举而不是整数值是完全没问题的。了解差异以做出明智的决定是重要的

回答by Kai Wang

Two facts.

两个事实。

1, Enum is one of the most powerful feature in JAVA.

1、枚举是JAVA中最强大的特性之一。

2, Android phone usually has a LOT of memory.

2、Android手机通常有很多内存。

So my answer is NO. I will use Enum in Android.

所以我的答案是否定的。我将在 Android 中使用 Enum。

回答by Ali

With Android P, google has no restriction/objection in using enums

使用 Android P,谷歌在使用枚举方面没有限制/反对

The documentation has changed where before it was recommended to be cautious but it doesn't mention it now. https://developer.android.com/reference/java/lang/Enum

文档已经更改了之前建议谨慎的地方,但现在没有提及。 https://developer.android.com/reference/java/lang/Enum