EffectiveJava 学习总结(三)

来源:互联网 发布:网络原创女歌手 编辑:程序博客网 时间:2024/06/05 07:20

四、泛型(完全不懂)

五、枚举和注解

1、用enum代替int常量

  • 这个经常用,一般好像都是这么用的了,这里注意有个values()方法挺有意思
    // 物品在各个星球上的重量和质量算法    public enum Planet {        MERCURY(3.302e+23, 2.439e6), VENUS(4.869e+24, 6.052e6), EARTH(5.975e+24,            6.378e6);        private final double mass; // 质量        private final double radius; // 半径        private final double surfaceGravity; // 表面重力           private static final double G = 6.67300E-11; // 万有引力常数        // 构造方法        Planet(double mass, double radius) {            this.mass = mass;            this.radius = radius;            surfaceGravity = G * mass / (radius * radius);        }        public double surfaceGravity() {            return surfaceGravity;        }        // 表面质量        public double surfaceWeight(double mass) {            return mass * surfaceGravity; // F = ma        }    }    public static void main(String[] args) {        // 通过1kg地球重量得到质量        double earthWeight = 1.0d;        // 这个时候就已经初始化了所有的emun对象        double mass = earthWeight / Planet.EARTH.surfaceGravity();        // values() 循环取出emun对象        for (Planet p : Planet.values())            System.out.printf("Weight on %s is %f%n", p, p.surfaceWeight(mass));    }
2、用实例域代替序数
  • 枚举是有顺序的,但是维护起来是噩梦
  • 所以现在都是SOLO(1), SUET(2);这样了
3、用EnumSet代替位域
    public class Text {        public enum Style {            BOLD, ITALIC, UNDERLINE, STRIKETHROUGH        }        public void applyStyles(Set<Style> styles) {            System.out.println(styles);        }        public static void main(String[] args) {            // EnumSet是Set的实现,很方便的选择需要的枚举组成Set集合            new Text().applyStyles(EnumSet.of(Style.BOLD, Style.ITALIC));        }    }
4、用EnumMap代替序数索引
  • 使用enumMap来索引数据,最好不用序数来索引数组
  • 代码没有理解,明天再看
5、用接口模拟可伸缩的枚举
6、注解优先于命名模式
  • 以前的类似与JUnit,名字要以Test开头,现在都用注解了
7、坚持使用Override注解
  • 如果在想要的每个方法声明中使用Override注解来覆盖超类声明,编译器就可以替你防止大量的错误
8、用标记接口定义类型
  • 就比如Serializable,接口没有任何方法
  • 例如@Target这样的标记注解,它可以被使用到任何的地方,但是标记接口的优势就是可以更加精确地进行进行锁定
  • 总结:如果想定义一个任何新方法都不会与之关联的类型,使用标记接口;如果未来会添加更多的信息,或者使用的不止是类和接口,则使用标记注解。
  • 最后一句,如果想要定义类型,一定要使用接口。

六、方法

1、检查参数的有效性
  • 例如Collections.sort(List)会隐式的判断里面所有的参数可以进行排序,开销非常巨大
  • 总而言之,限制要写到文档里、方法体开头,并通过显式的检查来实施这些限制。
2、必要时进行保护性拷贝
3、谨慎设计方法签名
  • 谨慎的选择方法的名称
  • 不要过于追求提供便利的方法,对于接口来说方法太多维护、编写困难,对于类和接口所支持的每个动作,都提供一个功能齐全的方法。
  • 避免过长的参数列表。目标是4个以内
    • 分解方法,不过会造成方法过多
    • 创建辅助类,这种类多为静态成员类,用来保存参数分组
    • 使用Build模式,第二章第二条
  • 对于参数类型,要优先使用接口而不是类,eg:参数是Map,就可以传递HashMap,TreeMap……
  • 对于boolean参数要优先使用两个元素的枚举类型。
4、慎用重载
  • eg:相同参数列表的构造方法,最少要保证行为的一致
5、慎用可变参数
  • eg:int… args,是方便的方式,但是过度滥用会产生混乱的结果
6、返回零长度的数组或者集合,而不是null
  • 好处就是所有的地方就不用再判断 != null 了,而且返回null并没有任何理由
7、为所有导出的API元素编写文档注释
  • 注释是一门学问

七、通用程序设计

1、将局部变量的作用域最小化
  • eg: for (int i = 0, n = MAX(); i < n; i++),这样i和n是同一个作用域,减少迭代
  • 其他方法:使方法小而集中,或者分开2个方法每个方法各自执行一个操作
2、for-each循环优先于传统的for循环
  • 编写简单
  • 双重循环之类的没有变量妨碍,代码简单易读
  • 注意例外:1、遍历删除选定的参数;2、遍历取代元素值;3、平行迭代多个集合
3、了解和使用类库
  • 很多方法不用自己实现了,类库都有,例如random方法就有Random.nextInt(int),不用new Random().自己的方法了
4、如果需要精确的答案,请避免使用float和double
  • f和d是为了恶口虚假us那和工程计算而设计的,不是完全的精确结果
  • 使用BigDecimal,优点是精确,缺点是麻烦和慢
  • 使用int(9位)和long(18位)代替,优点是性能好,缺点是有位数限制
5、基本类型优先于装箱基本类型
  • spring等参数绑定默认是Integer,可以防止空指针异常
  • 如果是经常使用和变化的变量,肯定还是用int
6、如果其他类型更合适,则尽量避免使用字符串
  • 字符串缺点:慢、不灵活、容易出错
7、当心字符串连接的性能
  • StringBuild
8、通过接口引用对象
  • 更加灵活
9、接口优先于反射机制
  • 反射缺点
    • 丧失了编译时类型检查的好处
    • 代码笨拙和冗长
    • 性能损失
  • 反射使用
    • 使用编译时无法获取的类
  • 解决:实例化的时候使用反射,访问对象的时候使用已知的接口或者超类
10、谨慎的使用本地方法
  • 我估计是不会使用JNI调用C或者C++的……
11、谨慎的进行优化
  • 就是不优化
12、遵守普遍接收的命名惯例

八、并发

1、多个线程访问可变数据,必须要同步
  • synchronized
  • 只需要交互通信,不需要互斥则可以使用volatile修饰符,但是需要一些技巧
2、避免过度使用同步
  • 防止死锁和数据破坏,同步方法不要调用外来方法
  • 减少同步区域内部的工作量
3、executor和task优先于线程
  • 看阿里云的代码,已经在使用ExecutorService这样设置县城了
4、并发工具优先于wait和notify
5、慎用延迟初始化
  • 大多数的域应该正常地进行初始化
  • 如果为了性能目标等,则实例域使用双重检查模式,静态域使用lazy模式
原创粉丝点击