《Effective Java》读书笔记五(枚举和注解)
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 kilograms
private final double radius; // In meters
private final double surfaceGravity; // In m / s^2 // Universal gravitational constant in m^3 / kg s^2
private static final double G = 6.67300E-11; // Constructor
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) {
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 constant
double 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 154
private static final Map<String, Operation> stringToEnum
= new HashMap<String, Operation>();
static { // Initialize map from constant name to enum constant
for (Operation op : values())
stringToEnum.put(op.toString(), op);
}
// Returns Operation for string, or null if string is invalid
public static Operation fromString(String symbol) {
return stringToEnum.get(symbol);
} // Test program to perform all operations on given operands
public 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; //
public static final int STYLE_ITATIC = 1 << 1; //
public static final int STYLE_UNDERLINE = 1 << 2; //
public static final int STYLE_STRIKETHROUGH = 1 << 3; //8 //Parameter is bitwise OR of zero or more STYLE_ constants
public void applyStyles(int styles){
// 根据styles值进行拆分,判断是哪些参数...
}; // Sample use
public 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 best
public void applyStyles(Set<Style> styles) {
// Body goes here
} // Sample use
public 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的作用了吧。
《Effective Java》读书笔记五(枚举和注解)的更多相关文章
- Effective Java 读书笔记之五 枚举和注解
Java1.5中引入了两个新的应用类型家族,新的类为枚举类型,新的接口为注解类型. 一.用enum代替int常量 1.枚举值由一组固定的常量组成合法值的类型. 二.用实例域代替序数 1.不要根据枚举的 ...
- Effective java读书笔记
2015年进步很小,看的书也不是很多,感觉自己都要废了,2016是沉淀的一年,在这一年中要不断学习.看书,努力提升自己 计在16年要看12本书,主要涉及java基础.Spring研究.java并发.J ...
- [Effective Java]第六章 枚举和注解
声明:原创作品,转载时请注明文章来自SAP师太技术博客( 博/客/园www.cnblogs.com):www.cnblogs.com/jiangzhengjun,并以超链接形式标明文章原始出处,否则将 ...
- Effective Java读书笔记完结啦
Effective Java是一本经典的书, 很实用的Java进阶读物, 提供了各个方面的best practices. 最近终于做完了Effective Java的读书笔记, 发布出来与大家共享. ...
- Effective Java 读书笔记(一):使用静态工厂方法代替构造器
这是Effective Java第2章提出的第一条建议: 考虑用静态工厂方法代替构造器 此处的静态工厂方法并不是设计模式,主要指static修饰的静态方法,关于static的说明可以参考之前的博文&l ...
- [Effective Java 读书笔记] 第6章 枚举和注解
第三十条 用enum代替int 总得来说,使用enum有几点好处 1.编译时的类型安全, 2.可以保证就是自己定义的值,不会有月结风险, 3.每个枚举类型有自己的命名空间 4.枚举可以添加任意的方法和 ...
- 《Effective Java》读书笔记 - 6.枚举和注解
Chapter 6 Enums and Annotations Item 30: Use enums instead of int constants Enum类型无非也是个普通的class,所以你可 ...
- Effective Java 读书笔记(五):Lambda和Stream
1 Lamdba优于匿名内部类 (1)DEMO1 匿名内部类:过时 Collections.sort(words, new Comparator<String>() { public in ...
- Effective Java 读书笔记之七 通用程序设计
一.将局部变量的作用域最小化 1.在第一次使用变量的地方声明 2.几乎每个变量的声明都应该包含一个初始化表达式:try-catch语句是一个例外 3.使方法小而集中是一个好的策略 二.for-each ...
- Effective Java 读书笔记之一 创建和销毁对象
一.考虑用静态工厂方法代替构造器 这里的静态工厂方法是指类中使用public static 修饰的方法,和设计模式的工厂方法模式没有任何关系.相对于使用共有的构造器来创建对象,静态工厂方法有几大优势: ...
随机推荐
- [Algorithm] Serialize and Deserialize Binary Tree
Given the root to a binary tree, implement serialize(root), which serializes the tree into a string, ...
- oracle client字符集设置 乱码问题
程序员经常要连接数据库 下面 就说一下 oracle数据库 客户端与服务器端 字符集一致性的问题 这可以解决中文乱码,其他字符乱码问题 主要是指在sqlplus中,其他类似toad/pls ...
- shiro实现基于机构加username的验证以及rememberMe
一.Shiro的一些经验与rememberMe实现原理 Shiro的登录(Authorization)和验权(Authentication).默认都是依据usernameUserName来做验证和授权 ...
- C#(wpf)迷你词典
本周利用空余时间做的一个单词查询软件(C#(Wpf)-WebService),目前只支持中英文查词,同义词.例句.发音. 未激活状态 WebService:http://fy.webxml.com.c ...
- Struts2(二)action的三种方式
一.普通java类 package com.pb.web.action; /* * 创建普通的java类 */ public class HelloAction1 { public String ex ...
- HTTP Content-type整理
文件扩展名 Content-Type(Mime-Type) 文件扩展名 Content-Type(Mime-Type) .*( 二进制流.不知道下载文件类型) application/octet-st ...
- 解决Unable to load component class org.sonar.scanner.report.ActiveRulesPublisher/Unable to load component interface org.sonar.api.batch.rule.ActiveRules: NullPointerException
解决办法 Delete the directory data/es in your SonarQube installation. Restart SonarQube.
- 解决"libc.so.6: version `GLIBC_2.14' not found",系统的glibc版本太低 {强行安装!!}
原创,转载请注明出处,谢谢!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! 首先查看系统glibc支持的版本: strings /lib64/libc.so.6 |grep G ...
- MVC5 的MicrosoftOwinSecurity扩展插件——微信,QQ登录第三方源码
https://github.com/jxnkwlp/Microsoft.Owin.Security.QQ-WebChat
- poj 4014 Dice 贪心
//poj 4014 //sep9 #include <iostream> #include <algorithm> using namespace std; int n; s ...