HashMap 中的 hashCode 应避免冲突
多线程使用 Vector 或 HashTable
Vector 是 ArrayList 的多线程版本, HashTable 是 HashMap 的多线程版本.
非稳定排序推荐使用 List
对于变动的集合排序
set=new TreeSet
使用 TreeSet 是希望实现自动排序, 即使修改也能自动排序, 既然它无法实现, 那就用 List 来代替, 然后使用 Collections.sort() 方法对 List 排序
- import java.util.ArrayList;
- import java.util.SortedSet;
- import java.util.TreeSet;
- public class Client69 {
- public static void main(String[] args) {
- SortedSet<Person> set = new TreeSet<Person>();
- // 身高 180CM
- set.add(new Person(180));
- // 身高 175CM
- set.add(new Person(175));
- set.first().setHeight(185);
- set=new TreeSet<Person>(new ArrayList<Person>(set));
- for (Person p : set) {
- System.out.println("身高:" + p.getHeight());
- }
- }
- static class Person implements Comparable<Person> {
- // 身高
- private int height;
- public Person(int _height) {
- height = _height;
- }
- public int getHeight() {
- return height;
- }
- public void setHeight(int height) {
- this.height = height;
- }
- // 按照身高排序
- @Override
- public int compareTo(Person o) {
- return height - o.height;
- }
- }
- }
在项目中推荐使用枚举常量代替接口常量或类常量
- enum Season {
- Spring, Summer, Autumn, Winter;
- public static Season getComfortableSeason(){
- return Spring;
- }
- }
使用构造函数协助描述枚举项
- enum Role {
- Admin("管理员", new LifeTime(), new Scope()), User("普通用户", new LifeTime(), new Scope());
- private String name;
- private LifeTime lifeTime;
- private Scope scope;
- /* setter 和 getter 方法略 */
- Role(String _name, LifeTime _lifeTime, Scope _scope) {
- name = _name;
- lifeTime = _lifeTime;
- scope = _scope;
- }
- }
- class LifeTime {
- }
- class Scope {
- }
name: 表示的是该角色的中文名称
lifeTime: 表示的是该角色的生命周期, 也就是多长时间该角色失效
scope: 表示的该角色的权限范围
小心 switch 带来的空指针异常
在 switch 的 default 代码块中增加 AssertionError 错误
使用 valueOf 前必须进行校验
枚举. valueOf(name)
没有匹配找到指定值报错:
- Exception in thread "main" java.lang.IllegalArgumentException: No enum ...
- at java.lang.Enum.valueOf(Unknown Source)
两种避免的方式:
(1), 使用 try......catch 捕捉异常
try{
枚举. valueOf(name)
- }catch(Exception e){
- e.printStackTrace();
- System.out.println("无相关枚举项");
- }
(2), 扩展枚举类
- enum Season {
- Spring, Summer, Autumn, Winter;
- // 是否包含指定的枚举项
- public static boolean isContains(String name) {
- // 所有的枚举值
- Season[] season = values();
- for (Season s : season) {
- if (s.name().equals(name)) {
- return true;
- }
- }
- return false;
- }
- }
用枚举实现工厂方法模式更简洁
枚举非静态方法实现工厂方法模式
- enum CarFactory {
- // 定义生产类能生产汽车的类型
- FordCar, BuickCar;
- // 生产汽车
- public Car create() {
- switch (this) {
- case FordCar:
- return new FordCar();
- case BuickCar:
- return new BuickCar();
- default:
- throw new AssertionError("无效参数");
- }
- }
- }
通过抽象方法生成产品
- enum CarFactory {
- // 定义生产类能生产汽车的类型
- FordCar{
- public Car create(){
- return new FordCar();
- }
- },
- BuickCar{
- public Car create(){
- return new BuickCar();
- }
- };
- // 抽象生产方法
- public abstract Car create();
- }
使用枚举类型的工厂方法模式三个优点:
避免错误调用的发生: 一般工厂方法模式中的生产方法 (也就是 createCar 方法), 可以接收三种类型的参数: 类型参数 (如我们的例子),String 参数 (生产方法中判断 String 参数是需要生产什么产品),int 参数 (根据 int 值判断需要生产什么类型的的产品), 这三种参数都是宽泛的数据类型, 很容易发生错误 (比如边界问题, null 值问题), 而且出现这类错误编译器还不会报警.
性能好, 使用简洁: 枚举类型的计算时以 int 类型的计算为基础的, 这是最基本的操作, 性能当然会快, 至于使用便捷, 注意看客户端的调用.
降低类间耦合: 不管生产方法接收的是 Class,String 还是 int 的参数, 都会成为客户端类的负担, 这些类并不是客户端需要的, 而是因为工厂方法的限制必须输入的, 例如 Class 参数, 对客户端 main 方法来说, 他需要传递一个 FordCar.class 参数才能生产一辆福特汽车, 除了在 create 方法中传递参数外, 业务类不需要改 Car 的实现类. 这严重违背了迪米特原则 (Law of Demeter 简称 LoD), 也就是最少知识原则: 一个对象应该对其它对象有最少的了解.
而枚举类型的工厂方法就没有这种问题了, 它只需要依赖工厂类.
枚举项的数量限制在 64 个以内
为了更好地使用枚举, Java 提供了两个枚举集合: EnumSet 和 EnumMap, 这两个集合使用的方法都比较简单, EnumSet 表示其元素必须是某一枚举的枚举项, EnumMap 表示 Key 值必须是某一枚举的枚举项, 由于枚举类型的实例数量固定并且有限, 相对来说 EnumSet 和 EnumMap 的效率会比其它 Set 和 Map 要高.
当枚举项数量小于等于 64 时, 创建一个 RegularEnumSet 实例对象, 大于 64 时则创建一个 JumboEnumSet 实例对象.
枚举项数量不要超过 64, 否则建议拆分.
- import java.util.EnumSet;
- public class EnumSetTest {
- // 普通枚举项, 数量等于 64
- enum Const{
- A,B,C,D,E,F,G,H,I,J,K,L,M,N,O,P,Q,R,S,T,U,V,W,X,Y,Z,
- AA,BB,CC,DD,EE,FF,GG,HH,II,JJ,KK,LL,MM,NN,OO,PP,QQ,RR,SS,TT,UU,VV,WW,XX,YY,ZZ,
- AAA,BBB,CCC,DDD,EEE,FFF,GGG,HHH,III,JJJ,KKK,LLL
- }
- // 大枚举, 数量超过 64
- enum LargeConst{
- A,B,C,D,E,F,G,H,I,J,K,L,M,N,O,P,Q,R,S,T,U,V,W,X,Y,Z,
- AA,BB,CC,DD,EE,FF,GG,HH,II,JJ,KK,LL,MM,NN,OO,PP,QQ,RR,SS,TT,UU,VV,WW,XX,YY,ZZ,
- AAAA,BBBB,CCCC,DDDD,EEEE,FFFF,GGGG,HHHH,IIII,JJJJ,KKKK,LLLL,MMMM
- }
- public static void main(String[] args) {
- EnumSet<Const> cs = EnumSet.allOf(Const.class);
- EnumSet<LargeConst> lcs = EnumSet.allOf(LargeConst.class);
- // 打印出枚举数量
- System.out.println("Const 的枚举数量:"+cs.size());
- System.out.println("LargeConst 的枚举数量:"+lcs.size());
- // 输出两个 EnumSet 的 class
- System.out.println(cs.getClass());
- System.out.println(lcs.getClass());
- }
- }
allOf 调用 noneOf
- public static <E extends Enum<E>> EnumSet<E> allOf(Class<E> elementType) {
- // 生成一个空 EnumSet
- EnumSet<E> result = noneOf(elementType);
- // 加入所有的枚举项
- result.addAll();
- return result;
- }
- public static <E extends Enum<E>> EnumSet<E> noneOf(Class<E> elementType) {
- // 获得所有的枚举项
- Enum[] universe = getUniverse(elementType);
- if (universe == null)
- throw new ClassCastException(elementType + "not an enum");
- // 枚举数量小于等于 64
- if (universe.length <= 64)
- return new RegularEnumSet<>(elementType, universe);
- else
- // 枚举数量大于 64
- return new JumboEnumSet<>(elementType, universe);
- }
注意 @Override 不同版本的区别
- interface Foo {
- public void doSomething();
- }
- class FooImpl implements Foo{
- @Override
- public void doSomething() {
- }
- }
这段代码在 Java1.6 版本上编译没问题, 虽然 doSomething 方法只是实现了接口的定义, 严格来说并不是覆写, 但 @Override 出现在这里可减少代码中出现的错误.
可如果在 Java1.5 版本上编译此段代码可能会出现错误: The method doSomeThing() of type FooImpl must override a superclass method.
Java1.5 版本的 @Override 是严格遵守覆写的定义: 子类方法与父类方法必须具有相同的方法名, 输出参数, 输出参数 (允许子类缩小), 访问权限 (允许子类扩大), 父类必须是一个类, 不能是接口, 否则不能算是覆写. 而这在 Java1.6 就开放了很多, 实现接口的方法也可以加上 @Override 注解了, 可以避免粗心大意导致方法名称与接口不一致的情况发生.
Java1.6 版本的程序移植到 1.5 版本环境中, 就需要删除实现接口方法上的 @Override 注解.
来源: http://www.bubuko.com/infodetail-2722293.html