您的位置:首页 > 编程语言 > Java开发

编写高质量代码:改善Java程序的151个建议-学习笔记(5-8章)

2017-05-13 20:26 721 查看

枚举和注解

83.推荐使用枚举定义常亮

public enum SeaSon {
Sping, Summer, Autumn, Winner;

public static SeaSon getCommonSeason() {
return Sping;
}

}

for (SeaSon s : SeaSon.values()) {
Log.i("clp", "s values =" + s);
}

Log.i("clp", "common =" + SeaSon.getCommonSeason());


04-19 10:26:24.608 14196-14196/com.example.demo I/clp: s values =Sping

04-19 10:26:24.608 14196-14196/com.example.demo I/clp: s values =Summer

04-19 10:26:24.608 14196-14196/com.example.demo I/clp: s values =Autumn

04-19 10:26:24.608 14196-14196/com.example.demo I/clp: s values =Winner

04-19 10:26:24.608 14196-14196/com.example.demo I/clp: common =Sping

84.使用构造函数协助描述枚举项

public enum SeaSon {
Sping("春"), Summer("夏"), Autumn("秋"), Winner("冬");

private String desc;

SeaSon(String desc) {
this.desc = desc;
}

public String getDesc() {
return desc;
}

public static SeaSon getCommonSeason() {
return Sping;
}

}


for (SeaSon s : SeaSon.values()) {
Log.i("clp", "s values =" + s.getDesc());
}

Log.i("clp", "common =" + SeaSon.getCommonSeason());


构造函数还可以比这个更复杂,传递对象等。

85.小心switch带来的空值异常

public void doSwSeaSon(SeaSon seaSon) {
switch (seaSon) {
case Sping:
Log.i("clp", "Sping");
break;
default:
Log.i("clp", "其他类型");
break;
}
}


doSwSeaSon(null);


java.lang.NullPointerException: Attempt to invoke virtual method ‘int com.cp.demo.java.SeaSon.ordinal()’ on a null object reference

case的其实是:SeaSon.Sping.ordinal(),所以要做对象的空值判断。

86.在switch的default代码块中增加AssertionError错误

因为枚举类型和case没有强制关系,如果后续增加了一个,没有case,就会导致switch漏掉这个枚举项。

87.枚举使用valueOf前必须进行校验

否则会抛出异常

List<String> mList = Arrays.asList("Sping", "sss");
for (int i = 0; i < mList.size(); i++) {
SeaSon sea = SeaSon.valueOf(mList.get(i));
if (sea == null) {
Log.i("clp", "没有此枚举值");
} else {
Log.i("clp", "有值");
}
}


java.lang.IllegalArgumentException: sss is not a constant in com.cp.demo.java.SeaSon

两种方案:

1.捕获异常

List<String> mList = Arrays.asList("Sping", "sss");
for (int i = 0; i < mList.size(); i++) {
try {
SeaSon sea = SeaSon.valueOf(mList.get(i));
Log.i("clp", "有值");
} catch (IllegalArgumentException e) {
Log.i("clp", "没有此枚举值");
}
}


04-19 11:35:20.148 13538-13538/com.example.demo I/clp: 有值

04-19 11:35:20.148 13538-13538/com.example.demo I/clp: 没有此枚举值

2.拓展枚举类

public static boolean contains(String name) {
for (SeaSon sen : values()) {
if (sen.name().equals(name)) {
return true;
}
}
return false;
}


List<String> mList = Arrays.asList("Sping", "sss");
for (int i = 0; i < mList.size(); i++) {
boolean sea = SeaSon.contains(mList.get(i));
if (sea) {
Log.i("clp", "有值");
} else {
Log.i("clp", "没有此枚举值");
}
}


88.用枚举实现工厂方法模式更简洁

1.非静态方法实现。

public interface Car {
public void drive();
}

public class FortCar implements Car {

@Override
public void drive() {
Log.i("clp", "fort drive");
}
}

public class BuickCar implements Car {

@Override
public void drive() {
Log.i("clp", "buick drive");
}
}

public enum CarFactory {
FortCar, BuickCar;

public Car create() {
switch (this) {
case FortCar:
return new FortCar();
case BuickCar:
return new BuickCar();
default:
Log.i("clp", "无效参数");
}
return null;
}

}


04-19 11:55:34.988 1940-1940/com.example.demo I/clp: fort drive

2.通过抽象方法生成

public enum CarFactory {
FortCar {
@Override
public Car create() {
return new FortCar();
}
}, BuickCar {
@Override
public Car create() {
return new BuickCar();
}
};

public abstract Car create();

}


89.枚举项的数量限制的64个以内

long e = -1L >>> -65;//value=1
long e = -1L >>> -1;//value=1
long e = -1L >>> 63;//value=1
long e = -1L >>> 1;//9223372036854775807

long e = -1L >>> 62;//value=3

int e = -1 >>> 31;//value=1
int e = -1 >>> 1;//2147483647


小于等于64和大于64处理的机制是不一样的。

Enum[] universe = getUniverse(elementType);
if (universe == null)
throw new ClassCastException(elementType + " not an enum");

if (universe.length <= 64)
return new RegularEnumSet<>(elementType, universe);
else
return new JumboEnumSet<>(elementType, universe);

RegularEnumSet:
void addAll() {
if (universe.length != 0)
elements = -1L >>> -universe.length;
}

JumboEnumSet:
void addAll() {
for (int i = 0; i < elements.length; i++)
elements[i] = -1;
elements[elements.length - 1] >>>= -universe.length;
size = universe.length;
}


所以内部是以64位拆分进行分组。

90.小心注解继承

91.枚举和注解结合使用威力很大

92.注意@Overrig不同版本的区别

如果是Java1.6版本的程序移植到1.5版本环境中,就需要删除实现接口方法上的@Override注解

泛型和反射

93.Java的泛型是类型擦除的

java的编译期和运行期解读:

http://www.360doc.com/content/14/0218/23/9440338_353675002.shtml

编译期:源码->class文件的过程

运行期:在JVM中运行的过程

public void initList(List<Integer> mList) {

}

public void initList(List<String> mList) {

}


按照上面这种方式写,报错。

initList(List)’ clashes with ‘initList(List)’; both methods have same erasure

List<String> mList = new ArrayList<String>();
List<Integer> mIList = new ArrayList<Integer>();
Log.i("clp", "is equals=" + (mList.getClass() == mIList.getClass()));


04-25 15:49:13.356 2760-2760/old.pkg.com.myapplicati I/clp: is equals=true

他们擦除后的类型都是List

Java泛型-类型擦除:

http://blog.csdn.net/caihaijiang/article/details/6403349

94.不能初始化泛型参数和数组

T t = new T();//报错
T[] mTArray = new T[];//报错
List<T> mList = new ArrayList<T>();//报错


以上3个写法,在AS上面都报错,需要在运行期指定T类型。

95.强制声明泛型的实际类型

“`

List mList = CldCalMiniUtil.asList();//正确

List mList = CldCalMiniUtil.asList();//正确

List mList2 = CldCalMiniUtil.asList(1, 2.2);//报错

List mList2 = CldCalMiniUtil.asList(1, 2.2);//正确–这里使用了强制声明
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: