No30 用enum代替int常量

一:综述

int枚举模式,示范:

// The int enum pattern - severely deficient!
public static final int APPLE_FUJI             =  0;
public static final int APPLE_PIPPIN           =  1;
public static final int APPLE_GRANNY_SMITH     =  2;

还有一种是这种模式的变体,使用String常量代替int常量,称为String枚举模式。缺点:

  • int枚举是编译时常量,如果它发生了变化,客户端需要重新编译;
  • 将int枚举常量翻译成可打印的字符串,并没有很便利的方法,你所见到的就是一个数字(比如调试,跟踪值等);
  • String枚举中的硬编码常量如果包含有书写错误,那么这样的错误在编译时不会被检测到,运行时会出错。

JDK1.5发行版本开始,提出了另一种可以替代的解决方案,可以避免int和String枚举模式的缺点,并提供许多额外的好处。示范:

public enum Apple {FUJI, PIPPIN, GARNNY_SMITH}

  • 枚举提供了编译时的类型安全。如果声明一个参数的类型为Apple,就可以保证,被传到该参数上的任何非null的对象引用一定属于三个有效的Apple值之一。
  • 常量值没有被编译到客户端代码中;
  • 允许添加任意的方法和域,并实现任意的接口。

二:有关枚举的一个好例子:

// Enum type with data and behavior - Pages 149-150
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;           // In kilogramsprivate final double radius;         // In metersprivate final double surfaceGravity; // In m / s^2// Universal gravitational constant in m^3 / kg s^2private static final double G = 6.67300E-11;// ConstructorPlanet(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) {return mass * surfaceGravity;  // F = ma
    }
}

// Takes earth-weight and prints table of weights on all planets - Page 150
public class WeightTable {public static void main(String[] args) {if(args.length == 0) {args = new String[]{"100"};}double earthWeight = Double.parseDouble(args[0]);double mass = earthWeight / Planet.EARTH.surfaceGravity();for (Planet p : Planet.values())System.out.printf("Weight on %s is %f%n",p, p.surfaceWeight(mass));Planet p = Planet.MERCURY;System.out.printf("dd Weight on %s is %f%n",p, p.surfaceWeight(mass));}
}

三:复杂一些的例子,比较如下两段代码:

代码一:

// Enum type that switches on its own value – questionable
public enum Operation {PLUS, MINUS, TIMES, DIVIDE;// Do the arithmetic op represented by this constantdouble apply(double x, double y) {switch(this) {case PLUS:  return x + y;case MINUS: return x - y;case TIMES: return x * y;case DIVIDE:return x / y;}throw new AssertionError("Unknown op:" + this);}
}

上述代码可行,但是不太好看。如果没有throw语句,它就不能进行编译。另外,如果添加了新的枚举常量,却忘记给switch添加相应的条件,枚举仍然可以编译,但当你试图运用新的运算时,就会运行失败。

代码二:

// Enum type with constant-specific class bodies and data - Page 153
import java.util.*;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; }@Override public String toString() { return symbol; }abstract double apply(double x, double y);// Implementing a fromString method on an enum type - Page 154private static final Map<String, Operation> stringToEnum= new HashMap<String, Operation>();static { // Initialize map from constant name to enum constantfor (Operation op : values())stringToEnum.put(op.toString(), op);}// Returns Operation for string, or null if string is invalidpublic static Operation fromString(String symbol) {return stringToEnum.get(symbol);}// Test program to perform all operations on given operandspublic static void main(String[] args) {double x = Double.parseDouble(args[0]);double y = Double.parseDouble(args[1]);for (Operation op : Operation.values())System.out.printf("%f %s %f = %f%n",x, op, y, op.apply(x, y));}
}

输出:

2.000000 + 4.000000 = 6.000000

2.000000 - 4.000000 = -2.000000

2.000000 * 4.000000 = 8.000000

2.000000 / 4.000000 = 0.500000

注:枚举类型中的抽象方法必须被它所有常量中的具体方法覆盖。

No32 用EnumSet代替位域

如果一个枚举类型的元素主要用在集合中,一般就使用int枚举模式,将2的不同倍数赋予每个常量:

// Bit field enumeration constants – OBSOLETE!
import java.util.*;public class Text {public static final int STYLE_BOLD          = 1 << 0;       //1public static final int STYLE_ITATIC         = 1 << 1;       //2public static final int STYLE_UNDERLINE     = 1 << 2;       //4public static final int STYLE_STRIKETHROUGH = 1 << 3;       //8//Parameter is bitwise OR of zero or more STYLE_ constantspublic void applyStyles(int styles){// 根据styles值进行拆分,判断是哪些参数...
    };// Sample usepublic static void main(String[] args) {Text text = new Text();text.applyStyles(STYLE_BOLD|STYLE_ITATIC);}
}

下面是一个范例改成枚举代替位域后的代码,它更加简洁、更加清楚、也更加安全。

// EnumSet - a modern replacement for bit fields - Page 160
import java.util.*;public class Text {public enum Style { BOLD, ITALIC, UNDERLINE, STRIKETHROUGH }// Any Set could be passed in, but EnumSet is clearly bestpublic void applyStyles(Set<Style> styles) {// Body goes here
    }// Sample usepublic static void main(String[] args) {Text text = new Text();text.applyStyles(EnumSet.of(Style.BOLD, Style.ITALIC));}
}

No36 坚持使用Override注解

如果你能判断出下面的代码输出结果是260,而不是26,那么你的水平应该足够高。即使这样,也不应该忽略Override注解。

// Can you spot the bug? - Page 176
import java.util.*;public class Bigram {private final char first;private final char second;public Bigram(char first, char second) {this.first  = first;this.second = second;}public boolean equals(Bigram b) {return b.first == first && b.second == second;}public int hashCode() {return 31 * first + second;}public static void main(String[] args) {Set<Bigram> s = new HashSet<Bigram>();for (int i = 0; i < 10; i++)for (char ch = 'a'; ch <= 'z'; ch++)s.add(new Bigram(ch, ch));System.out.println(s.size());}
}

在上面的代码中的方法equals之前增加@Override注解,则编译出错!因为equals需要的是Object参数,而不是Bigram参数。这样,你应该能够明白@Override的作用了吧。

转载于:https://www.cnblogs.com/nayitian/p/3245516.html

《Effective Java》读书笔记五(枚举和注解)相关推荐

  1. Effective Java读书笔记五:异常

    第57条:只针对异常的情况才使用异常 异常是为了在异常情况下使用而设计的,不要将它们用于普通的控制流,也不要编写迫使它们这么做的API. 下面部分来自:异常 如果finally块中出现了异常没有捕获或 ...

  2. Effective Java读书笔记(二)

    Effective Java 读书笔记 (二) 创建和销毁对象 遇到多个构造器参数时要考虑使用构建器 创建和销毁对象 何时以及如何创建对象? 何时以及如何避免创建对象? 如何确保它们能够适时地销毁? ...

  3. Effective Java 读书笔记(七):通用程序设计

    Effective Java 读书笔记七通用程序设计 将局部变量的作用域最小化 for-each 循环优于传统的 for 循环 了解和使用类库 如果需要精确的答案请避免使用 float 和 doubl ...

  4. Effective Java读书笔记二:枚举和注解

    第30条:用enum代替int常量 当需要一组固定常量的时候,应该使用enum代替int常量,除了对于手机登资源有限的设备应该酌情考虑enum的性能弱势之外. 第31条:用实例域代替序数 枚举的ord ...

  5. Effective Java读书笔记完结啦

    Effective Java是一本经典的书, 很实用的Java进阶读物, 提供了各个方面的best practices. 最近终于做完了Effective Java的读书笔记, 发布出来与大家共享. ...

  6. Effective Java 读书笔记(一)

    前言: 开个新的坑位,<effective java>的读书笔记,之后有时间会陆陆续续的更新,读这本书真的感触满多,item01和item02就已经在公司的项目代码中看到过了.今天这篇主要 ...

  7. Effective Java读书笔记七:泛型(部分章节需要重读)

    第23条:请不要在新代码中使用原生态类型 从java1.5发行版本开始,Java就提供了一种安全的替代方法,称作无限制的通配符类型,如果要使用范型,但是确定或者不关心实际的参数类型,就可以用一个问号代 ...

  8. Effective Java读书笔记六:方法

    第38条:检查参数的有效性 绝大多数方法和构造器对于传递给它们的参数值都会有些限制.比如,索引值必须大于等于0,且不能超过其最大值,对象不能为null等.这样就可以在导致错误的源头将错误捕获,从而避免 ...

  9. Effective Java读书笔记四:通用程序设计

    第45条:将局部变量的作用域最小化 在第一次使用变量时的地方声明: 几乎每个局部变量的声明都应该包含一个初始表达式: 如果在终止循环之后不需要循环变量的内容,for循环优于while循环.(for循环 ...

  10. Effective Java读书笔记三:创建和销毁对象

    第1条:考虑用静态工厂方法代替构造器 对于类而言,为了让客服端获得它的一个实例最常用的的一个方法就是提供一个公有的构造器.还有一种方法,类可以提供一个公有的静态工厂方法(static factory ...

最新文章

  1. 用JavaScript fetch API取数据遇到CORS policy问题
  2. Android学习拾遗
  3. Python编程教程:面向对象之高级特性!
  4. (129)System Verilog限制建仓方法
  5. @RestControllerAdvice 异常分析
  6. python可以下载百度文库_不用下载券也能下载百度文库资料,Python帮你轻松搞定...
  7. EXCEL【数据处理之数据清洗——缺失数据处理】
  8. 2021年11月软件设计师真题解析
  9. 英语流利说19秋招笔试总结
  10. 计算机歌曲数我的一个道姑朋友,同人歌|我的一个道姑朋友
  11. http://www.jdon.com/
  12. 《OpenGL ES 3.x游戏开发(下卷)》一2.4 展翅飞翔的雄鹰
  13. 家乡旅游风景区介绍——茂名风景区网页设计HTML+CSS+JavaScript
  14. 网页设计颜色及平面设计的常用16进制+RGB色值表参考大全
  15. 谷歌浏览器使用记住密码功能 导致input 输入框样式改变的解决办法
  16. dsf5.0没登录显示登录弹框
  17. Android系统SystemUI启动过程
  18. android动态壁纸是什么格式的,为什么动态壁纸为APK格式? -
  19. 港交所OMD-C对接笔记
  20. sql查询数据库中所有表名

热门文章

  1. 花落谁家---再见熊节
  2. Emlog程序CYP音乐主题模板源码
  3. android xlog崩溃日志,Android第三方log库:xlog使用记录
  4. 服务器操找不见系统,服务器提示找不到操作系统
  5. matlab输出的图怎么设置网格背景图片,4.11Python数据处理篇之Matplotlib系列(十一)---图例,网格,背景的设置...
  6. Office 365 API平台概览
  7. 六大类二叉树面试题汇总解答
  8. UML交互图(时序图、顺序图、序列图是一样的、协作图)
  9. Transact -SQL 语句
  10. 计算机视觉新手入门学习