文章目录
![在这里插入图片描述](https://img-blog.csdnimg.cn/edb51b6e04c24825af29bfe6614c6ce6.png#pic_center)
编写高质量代码: 改善Java程序的151个建议
前言
我是 Rocky编程日记, 喜欢 后端源码 及 中间件架构, 该篇文章是我学习 编写高质量代码: 改善Java程序的151个建议的笔记记录 。希望我写的笔记能够给你提供帮助。同时若笔记中存在不对的地方,那一定是当时的理解还不够, 希望你能够及时指出嗷~
第六章 枚举和注解
建议83:推荐使用枚举定义常量
- 在项目开发中,推荐使用枚举常量替代接口常量和类常量)(常量分为:类常量、接口常量、枚举常量;
- 枚举常量优点:
- 1、枚举常量更简单;
- 2、枚举常量属于稳态性(不允许发生越界);
- 3、枚举具有内置方法,values方法可以获取到所有枚举值;
- 4、枚举可以自定义方法
建议84:使用构造函数协助描述枚举项
-
每个枚举项都是该枚举的一个实例。可以通过添加属性,然后通过构造函数给枚举项添加更多描述信息。
enum Season { Spring("春"), Summer("夏"), Autumn("秋"), Winter("冬"); private String desc; Season(String _desc) { desc = _desc; } public String getDesc() { return desc; } }
建议85:小心switch带来的空值异常
-
使用枚举值作为switch(枚举类);语句的条件值时,需要对枚举类进行判断是否为null值。
因为Java中的switch语句只能判断byte、short、char、int类型,JDK7可以判断String类型,使用switch语句判断枚举类型时,会根据枚举的排序值匹配。
如果传入的只是null的话,获取排序值需要调用如season.ordinal()方法时会抛出NullPointerException异常
public class Suggest85 { public static void main(String[] args) { doSports(null); } public static void doSports(Season season) { switch (season) { case Spring: System.out.println("spring"); break; case Summer: System.out.println("summer"); break; case Autumn: System.out.println("autumn"); break; case Winter: System.out.println("winter"); break; default: System.out.println("error"); break; } } }
建议86:在switch的default代码块中增加AssertionError错误
- switch语句在使用枚举类作为判断条件时,避免出现增加了一个枚举项,而switch语句没做任何修改,编译不会出现问题,但是在运行期会发生非预期的错误。
- 为避免这种情况出现,建议在default后直接抛出一个AssertionError错误。
- 含义是:不要跑到这里来,一跑到这里来马上就会报错。
建议87:使用valueOf前必须进行校验
-
Enum.valueOf()方法会把一个String类型的名称转变为枚举项,也就是在枚举项中查找出字面值与该参数相等的枚举项。valueOf方法先通过反射从枚举类的常量声明中查找,若找到就直接返回,若找不到就抛出IllegalArgumentException异常。
public class Suggest87 { public static void main(String[] args) { List<String> params = Arrays.asList("Spring", "summer"); for (String name : params) { Season season = Season.valueOf(name); if (season != null) { System.out.println(season); } else { System.out.println("无相关枚举项"); } } } }
解决:
- 使用 try … catch 捕捉异常
- 扩展枚举类
建议88:用枚举实现工厂方法模式更简洁
-
工厂方法模式是“创建对象的接口,让子类决定实例化哪一个类,并使一个类的实例化延迟到其子类”。枚举实现工厂方法模式有两种方法:
-
枚举非静态方法实现工厂方法模式;
-
通过抽象方法生成产品;
优点:避免错误调用的发生;性能好,使用便捷;减低类间耦合性
-
建议89:枚举项的数量控制在64个以内
- Java提供了两个枚举集合:EnumSet、EnumMap;EnumSet要求其元素必须是某一枚举的枚举项,EnumMap表示Key值必须是某一枚举的枚举项。由于枚举类型的实例数量固定并且有限,相对来说EnumSet和EnumMap的效率会比其他Set和Map要高。
- Java处理EnumSet过程:当枚举项小于等于64时,创建一个RegularEnumSet实例对象,大于64时创一个JumboEnumSet实例对象。
- RegularEnumSet是把每个枚举项编码映射到一个long类型数字得每一位上,而JumboEnumSet则会先按照64个一组进行拆分,然后每个组再映射到一个long类型的数字得每一位上
建议90:小心注解继承
-
不常用的元注解(Meta-Annotation):@Inherited,它表示一个注解是否可以自动被继承。
@Retention(RetentionPolicy.RUNTIME) @Target(ElementType.TYPE) @Inherited @interface Desc { enum Color { White, Grayish, Yellow; } Color c() default Color.White; } @Desc(c = Desc.Color.White) abstract class Bird { public abstract Desc.Color getColor(); } class Sparrow extends Bird { private Desc.Color color; public Sparrow() { color = Desc.Color.Grayish; } public Sparrow(Desc.Color _color) { color = _color; } @Override public Desc.Color getColor() { return color; } } public enum BirdNest { Sparrow; public Bird reproduce() { Desc bd = Sparrow.class.getAnnotation(Desc.class); return bd == null ? new Sparrow() : new Sparrow(bd.c()); } public static void main(String[] args) { Bird bird = BirdNest.Sparrow.reproduce(); Desc.Color color = bird.getColor(); System.out.println("color: " + color); } }
建议91:枚举和注解结合使用威力更大
- 注解和接口写法类似,都采用了关键字interface,而且都不能有实现代码,常量定义默认都是public static final类型的等,他们的主要不同点:注解要在interface前加上@字符,而且不能继承,不能实现
建议92:注意@Override不同版本的区别
- @Override注解用于方法的覆写上,它在编译期有效,也就是Java编译器在编译时会根据该注解检查方法是否真的是覆写,如果不是就报错,拒绝编译。
- Java1.5版本中@Override是严格遵守覆写的定义:子类方法与父类方法必须具有相同的方法名、输入参数、输出参数(允许子类缩小)、访问权限(允许子类扩大),父类必须是一个类,不是是接口,否则不能算是覆写。
- 而在Java1.6就开放了很多,实现接口的方法也可以加上@Override注解了。如果是Java1.6版本移植到Java1.5版本中时,需要删除接口实现方法上的@Override注解