第30条:用enum代替int常量

在java1.5之前,表示枚举类型的常用模式是声明一组具名的int常量,每个类型成员一个常量:

public static final int APPLE_FUJI = 0;
public static final int APPLE_PIPPIN = 1;
public static final int APPLE_GRANNY_SMITH = 2;

public static final int ORANGE_NAVEL = 0;
public static final int ORANGE_TEMPLE = 1;
public static final int ORANGE_BLOOD = 2;

缺点:

1.将apple传到想要orange的方法中,不会出现错误

2.用==操作符将apple与orange比较,不会出现错误

3.int枚举是编译时常量,被编译到客户端中,如果枚举常量关联的int发生变化,客户端必须重新编译,如果没有重新编译,程序仍可以运行,但行为就确定了,如APPLE_FUJI关联的常量不再是0,而是3。

4.将int枚举常量翻译成可打印的字符串很麻烦

5.遍历一个组中所有的int枚举常量,获得int枚举组的大小,没有可靠的方法,如想知道APPLE的常量有多少个,除了查看int枚举常量所在位置的代码外,别无他法,而且靠的是观察APPLE_前缀有多少个,不可靠

枚举类型是int枚举常量的替代解决方案:

public enum Apple {FUJI, PIPPIN, GRANNY_SMITH}
public enum Orange {NAVEL, TEMPLE, BLOOD}

枚举是功能齐全的类,通过公有的静态final域为每个枚举常量导出实例的域。因为没有可以可以访问的构造器,客户端不能创建枚举类型的实例,也不能扩展它。

枚举提供编译时的类型安全,如果一个参数的类型是Apple,就可以保证,被传入到该参数上的任何非null对象引用一定是FUJI,PIPPIN,GRANNY_SMITH三个之一。

包含同名常量的多个枚举类型可以共存,因为每个类型有自己的命名空间,增加或重新排列枚举类型的常量,无需重新编译客户端代码。

通过调用toString方法,可以将枚举转换成可打印的字符串。

枚举类型有方法和域:

public enum Planet {
    MERCURY(3.302e+23, 2.439e6),
    VENUS(4.869e+24, 6.052e6),
    EARTH(5.975e+24, 6.378e6),
    MARS(6.419e+23, 3.393e6),
    JUPITER(1.899e+27, 7.149e7),
    SATURN(5.685e+26, 6.027e7),
    URANUS(8.683e+25, 2.556e7),
    NEPTUNE(1.024e+26, 2.477e7);
    private final double mass;
    private final double radius;
    private final double surfaceGravity;

    private static final double G = 6.67300e-11;

    Planet(double mass, double radius) {
        this.mass = mass;
        this.radius = radius;
        surfaceGravity = G * mass / (radius * radius);
    }

    public double mass() {
        return mass;
    }

    public double radius() {
        return radius;
    }

    public double surfaceGravity() {
        return surfaceGravity;
    }

    public double surfaceWeight(double mass) {//F=ma
        return mass * surfaceGravity;
    }

}

根据某个物体在地球上的重量,显示该物体在所有8颗行星上的重量:

public static void main(String[] args) {
        double earthWeight = 175;
        double mass = earthWeight / Planet.EARTH.surfaceGravity();
        for(Planet p : Planet.values()) {
            System.out.printf("Weight on %s is %f%n", p, p.surfaceWeight(mass));
        }
}

如果枚举具有普遍适用性,它应该成为一个顶层类,如果只被用在一个特定的顶层类中,应该成为顶层类的一个成员类。

java.math.RoundingMode枚举表示十进制的舍入模式,用在BigDecimal类。

Planet示例展示每个常量关联不同的数据,有时候需要将本质上不同的行为与常量关联起来。

假设有一个枚举类型,表示计算器的四大基本操作:

public enum Operation {
    PLUS("+") {
        double apply(double x, double y) {return x + y;}
    },
    MINUS("-") {
        double apply(double x, double y) {return x - y;}
    },
    TIMES("*") {
        double apply(double x, double y) {return x - y;}
    },
    DIVIDE("/") {
        double apply(double x, double y) {return x - y;}
    }
    private final String symbol;
    Operation(String symbol) {
        this.symbol = symbol;
    }
    public String toString() {
        return symbol;
    }
    abstract double apply(double x, double y);
}

某些情况下,覆盖toString方法使打印算术表达式很容易:

public static void main(String[] args) {
    double x = 2.0;
    double y = 4.0;
    for(Operation op : Operation.values())
        System.out.printf("%f %s %f = %f%n", x, op, y, op.apply(x,y));
}

枚举类型有一个自动产生的valueOf(String)方法,它将常量的名字转变成常量本身。

如果覆盖toString方法,要考虑编写一个fromString方法,将字符串表示法变回相应的枚举:

private static final Map<String, Operation> stringToEnum
    = new HashMap<String, Operation>();
static {
    for(Operation op : values())
        stringToEnum.put(op.toString(), op);
}
public static Operation fromString(String symbol) {
    return stringToEnum.get(symbol);
}

枚举策略解决多个枚举常量同时共享相同的行为。

加班报酬,weekday和weekend的计算方式不一样:

enum PayrollDay {
    MONDAY(PayType.WEEKDAY),
    THESDAY(PayType.WEEKDAY),
    WEDNESDAY(PayType.WEEKDAY),
    THURSDAY(PayType.WEEKDAY),
    FRIDAY(PayType.WEEKDAY),
    SATURDAY(PayType.WEEKEND),
    SUNDAY(PayType.WEEKEND);

    private final PayType p;
    PayrollDay(PayType p) {
        this.p = p;
    }
    double pay(double hoursWorked, double payRate) {
        return payType.pay(hoursWorked, payRate);
    }

    private enum PayType {
        WEEKDAY {
            double overtimePay(double hours, double payRate) {
                return hours <= HOURS_PER_SHIFT ? 0 :
                    (hours - HOURS_PER_SHIFT) * payRate * 2;
            }
        },
        WEEKEND {
            double overtimePay(double hours, double payRate) {
                return hours * payRate / 2;
            }
        };
        private final static int HOURS_PER_SHIFT = 8;
        abstract double overtimePay(double hours, double Rate);
        double pay(double hoursWorked, double payRate) {
            double basePay = hoursWorked * payRate;
            return basePay + overtimePay(hoursWorked, payRate);
        }
    }
}

每当需要一组固定常量的时候,就应该使用枚举。

时间: 2024-10-06 12:30:36

第30条:用enum代替int常量的相关文章

【代码优化】使用enum代替int常量

经常带代码中看见这样的代码: public static final int APP_START=1; public static final int APP_PAUSE=0; public static final int APP_STOP =2; public static final int PLAY_START=1; public static final int PLAY_PAUSE=0; public static final int PLAY_STOP =2; 这种方法叫作int枚

Item 30 用enum代替int常量类型枚举,string常量类型枚举

1.用枚举类型替代int枚举类型和string枚举类型 public class Show { // Int枚举类型 // public static final int APPLE_FUJI = 0; // public static final int APPLE_PIPPIN = 1; // public static final int APPLE_GRANNY_SMITH = 2; public enum Apple { FUJI, PIPPIN, GRANNY_SMITH } pub

用枚举enum替代int常量

枚举的好处: 1. 类型安全性 2.使用方便性 public class EnumDemo { enum Color{ RED(3),BLUE(5),BLACK(8),YELLOW(13),GREEN(28); private int colorValue; private Color(int rv){ this.colorValue=rv; } private int getColorValue(){ return colorValue; } private int value(){ retu

第六章:枚举和注解。ITEM30:用enum代替int常量。&amp;ITEM32:用EnumSet代替位域。&amp;ITEM33:用EnumMap代替序数索引。

1 package com.twoslow.cha6; 2 3 import java.util.HashMap; 4 import java.util.Map; 5 6 public enum Operation { 7 8 PLUS("+") { 9 @Override 10 double apply(double x, double y) { 11 return x + y; 12 } 13 },MINUS("-") { 14 @Override 15 dou

大师传承-java代码编写的30条建议

成为一个优秀的Java程序员,有着良好的代码编写习惯是必不可少的.下面就让我们来看看代码编写的30条建议吧. (1) 类名首字母应该大写.字段.方法以及对象(句柄)的首字母应小写.对于所有标识符,其中包含的所有单词都应紧靠在一起,而且大写中间单词的首字母.例如: ThisIsAClassName thisIsMethodOrFieldName 若在定义中出现了常数初始化字符,则大写static final基本类型标识符中的所有字母.这样便可标志出它们属于编译期的常数. Java包(Package

HTML 代码编写的30条技巧

本文总结了30条HTML代码编写指南,只要在编写HTML代码的过程中牢记它们,灵活运用,你一定会写出一手漂亮的代码,早日迈入专业开发者的行列. 1. 一定要闭合HTML标签 在以往的页面源代码里,经常看到这样的语句: <li>Some text here. <li>Some new text here. <li>You get the idea. 也许过去我们可以容忍这样的非闭合HTML标签,但在今天的标准来看,这是非常不可取的,是必须百分百避免的.一定要注意闭合你的H

全是干货!UI设计的30条黄金准则!

http://www.wex5.com/portfolio-items/js-1/ 全是干货!UI设计的30条黄金准则! 总的来说,好的UI界面有几个特征:简洁.便利.目标明确.人性化.字面上看这几点貌似很简单,但是考虑到我们的营销目标.考虑到内容复杂度,要确确实实达到这个目标却非常困难.下面列出的这些经验,一直以来在WeX5应用开发者社群中反复被验证,简单实用.极具操作性,WeX5开发工具强烈推荐给所有应用开发者及爱好者! 注:内容转化率是指用户浏览页面的时候能被用户吸收的内容比率. 1. 尝

shopnc框架数据库查询限制30条记录

   shopnc框架数据库查询方法:Model()->table("表名")->select();假如你的表中数据大于30条,你查到的 结果中会只显示30条,解决方法是:查询语句中假如limit方法,即Model()->table("表名")-> limit(false)->select();

好Java代码的30条建议

成为一个优秀的Java程序员,有着良好的代码编写习惯是必不可少的.以下是代码编写的30条建议,希望对大家有帮助. (1) 类名首字母应该大写.字段.方法以及对象(句柄)的首字母应小写.对于所有标识符,其中包含的所有单词都应紧靠在一起,而且大写中间单词的首字母.例如: 若在定义中出现了常数初始化字符,则大写static final基本类型标识符中的所有字母.这样便可标志出它们属于编译期的常数. Java包(Package)属于一种特殊情况:它们全都是小写字母,即便中间的单词亦是如此.对于域名扩展名