3分钟快速阅读-《Effective Java》(四)

2019-10-26 20:47:54 浏览数 (1)

31.用实例域代替序数

在枚举类当中添加序数,可以帮助我们对于有特定需求的枚举进行排序

代码语言:javascript复制
public enum Emsemble {
    SOLO(1),DUTE(2),TRIO(3),QUARTET(4),QUINTET(5),SEXTET(6);

    private final int numberOfMusic;
    Emsemble(int number) {
        numberOfMusic = number;
    }
    public int numberOfMusic(){
        return numberOfMusic;
    }
}

测试用例

代码语言:javascript复制
    public static void main(String[] args) {
        int i = Emsemble.DUTE.numberOfMusic();
        System.out.println(i);
    }
32.使用EnumSet代替位域

日常开发当中我们总会需要使用到位运算符来表示一个对象具有一种或者多种状态的情况,我们有时会用这样的操作:

代码语言:javascript复制
public class Text {

    public static final int STYLE_BOLD = 1 << 0 ;
    public static final int STYLE_TIACLC = 1 << 1 ;
    public static final int STYLE_UNDERLINE = 1 << 2 ;
    public static final int STYLE_SIRIKETHROUGH = 1 << 3 ;

    public void applyStyles(int style){
        //TODO
    }
}

使用枚举的操作

代码语言:javascript复制
public class Text {
    public enum Style{
        STYLE_BOLD,STYLE_TIACLC,STYLE_UNDERLINE,STYLE_SIRIKETHROUGH;
    }
    public void applyStyles(int style){
        //TODO
    }
}
33.用EnumMap代替枚举当中的数组

错误示例

代码语言:javascript复制
public enum Person {
    JMES,LILI,HEARO,LORSE,MARAY,MICK;
    private static final Person[][] HUMAN = {
            {JMES,LILI,HEARO},
            {LORSE,MARAY,MICK}
    };
}

正确示例

代码语言:javascript复制
    //使用内部嵌套类
    private enum Human{
        JMES,LILI,HEARO,LORSE,MARAY,MICK;
        private static final Map<Person,Map<Person,Human>> MAP = new EnumMap<Person, Map<Person, Human>>(Person.class);
        static {
            for (Person person : Person.values()) {
                MAP.put(person,new EnumMap<Person, Human>(Person.class));
            }
        }
    }
34.用接口模拟可伸缩的枚举

简单来说,用接口来拓展枚举的功能,代码示例如下

代码语言:javascript复制
//接口
public interface Operator {
    double apply(double x,double y);
}

//实现类
//在枚举当中每一常量都是它的一个对象,所以当这个字段需要传递什么参数时,都需要对应的构造器用于初始化这个参数,并且添加相对应的字段,用于表示和初始化
public enum Operation implements Operator{
    PLUS(" "){
        @Override
        public double apply(double x, double y) {
            return x   y;
        }
    },
    MINUE("-"){
        @Override
        public double apply(double x, double y) {
            return x > y ? x - y : y - x;
        }
    },
    TIMES("*"){
        @Override
        public double apply(double x, double y) {
            return x * y;
        }
    },
    DIVID("-"){
        @Override
        public double apply(double x, double y) {

            return (x == 0 || y == 0) ? 0 :  x / y;
        }
    };

    private final String symbol;
    Operation(String symbol){
        this.symbol = symbol;
    }

}
35.注解优先于命名模式

本条原文中举例当我们使用单元测试的时候只是使用test作为方法开头来命名,这样不够好,可以使用注解来作为方法区分的方式,个人觉得没必要.开发者根据自己情况而定

36.坚持使用@Override注解

好处就是编译器可以帮你做对应检查,省去一些不必要的麻烦

37.用标记接口定义类型

引用原文:总而言之,如果想要定义一个任何新方法都不会与之关联的类型,标记接口就是最好的选择,否则可以使用注解

38.检查参数的有效性

每个方法都有它对应的业务意义,所以当我们方法接收的参数可能存在不安全情况的时候,都要习惯性的记得对它做非空判断以及不符合当前业务逻辑的参数判断.这样可以帮助我们免除和记录很多非必要的异常

39.必要时进行保护性拷贝

简而言之,只要从客户端得到或者返回客户端的可变组件,类就必须要保护性的拷贝这些组件.要杜绝对象可能会被改变的可能性.代码示例如下

代码语言:javascript复制
public final class Period {

    private final Date start;
    private final Date end;

    //在构造器当中加入对于开始时间和结束时间的限制和约束,避免当对象被初始化完成之后,被再次恶意修改了时间
    public Period(Date start, Date end) {
        this.start = new Date(start.getTime());
        this.end = new Date(end.getTime());
        if(start.compareTo(end) > 0){
            throw new IllegalArgumentException(start   "after"   end);
        }
    }
    public Date strat(){
        return new Date(this.start.getTime());
    }
    public Date end(){
        return new Date(this.end.getTime());
    }
}
40.谨慎设计方法签名
  • 40.1 谨慎选择方法的名称,请根据不同公司的命名规则进行命名
  • 40.2 不要过于追求提供便利的方法.不管是接口或者是类,方法过多都会导致测试难度加强,不易于学习
  • 40.3 避免过长的参数列表.最多不要超过4个参数为最佳

0 人点赞