zoukankan      html  css  js  c++  java
  • 《Effective Java》读书笔记

    一、引言

      1.几条基本规则:(清晰性和简洁性最为重要)

          模块的用户永远也不应该被模块的行为所迷惑(那样就不清晰了),模块要尽可能小,但又不能太小

          代码应该被重用,而不是被拷贝

          模块之间的依赖性应该尽可能的降到最小

          错误应该尽早的被检测出来,最好是在编译时刻

          PS.你不该盲目的遵从这些规则,但是,你应该只在偶尔的情况下,有了充分理由之后采取打破这些规则

          学习编程艺术首先要学会基本的规则,然后才能知道什么时候可以打破这些规则

    二、创建和销毁对象

      第一条:考虑用静态工厂方法代替构造器。它有以下优势:

        1)它有名称

        2)不必再每次调用它的时候都创建一个新对象

        3)它可以返回原类型的任何子类型的对象

        4)在创建参数化类型实例的时候,它使代码变得更加简洁

        缺点:

        1)类如果不含共有的或者受保护的构造器,就不能被子类化(它鼓励程序复用而不是继承)

        2)它与其他的静态方法实际上没有任何区别(API文档中无法明确表示出来,可以用惯用命名来弥补)

      第二条:遇到多个构造器参数时要考虑用构建器。一般常用方法:

        1)重叠构造器(telescoping constructor)

        2) JavaBean模式

        3)build构建器

          PS.语法糖:NutritionFacts cocaCola = new NutritionFacts.Builder(240,8).calories(100).sodium(35).carbonydrate(27).build();

      第三条:用私有构造器或者枚举类型强化Singleton属性

      第四条:通过私有构造器强化不可实例化的能力

      第五条:避免创建不必要的对象:

        1)不要用String s = new String("xxxx");而应该用String s = "xxxxx";前者复用会创建大量实例,后者只会创建一个

        2)不要使用Boolean(String);而应该用Boolwan.valueOf(String);对于同时提供了静态工厂方法和构造器的不可变类,通常用静态方法,避免创建不必要的对象

        3)用long sum = 0L;而不要用Long sum = 0L;要优先使用基本类型而不是装箱基本类型,要当心无意识的自动装箱

        4)现代的JVM实现具有高度优化的垃圾回收器,其性能很容易就会超过轻量级对象池的性能,因此除非重量级对象(数据库连接),少用线程池。

      第六条:消除过期的对象引用(主要是为了防范内存泄露):

        1)栈里被弹出的元素,记得要清空引用

        2)缓存用WeakHashMap来实现

        3)注意监听器和其他回调,保存对象的弱引用,例如,只将他们保存成WeakHashMap

      第七条:避免使用终结方法(finalizer)

        原因:它不能及时执行,甚至根本就不保证它们会被执行

        用处:充当安全网,或者是为了终止非关系的本地资源

        用法:记得调用super.finalizer;要记得记录终结方法的非法方法;考虑使用终结方法守卫者

    三、对于所有对象都通用的方法

      第八条:覆盖equals时请遵守通用约定

        1)自反性

        2)对称性

        3)传递性

        4)一致性

        ps.使用诀窍在P36

      第九条:覆盖equals时总要覆盖hashCode

        约定内容:

          1) 如果两个对象相同,那么它们的hashCode值一定要相同。重写equals方法,一定要重写hashCode方法。

          2) 如果两个对象的hashCode相同,它们并不一定相同,这里的对象相同指的是用eqauls方法比较。

        PS.Hash算法原理:当Set接收一个元素时根据该对象的内存地址算出hashCode,看它属于哪一个区间,在这个区间里调用equeals方法。

      第十条:始终要覆盖toString方法

      第十一条:谨慎的覆盖clone

        由于它有许多缺点,另一个实现对象拷贝的好办法是提供一个拷贝构造器或者拷贝工厂

      第十二条:考虑实现Comparable接口

        有些类具有内在的排序功能,但是与equals不一致。有些集合使用comparable而不是equals做同性测试。

    四、类和接口

      第十三条:使类的成员的可访问性最小化

        封装:又被称为信息隐藏,是模块化的前提和保证

        模块化的好处:

          1)各个模块可以独立开发、测试、优化、使用、理解和修改

          2)加快系统开发的速度,因为这些模块可以并行开发

          3)减轻了维护的负担,程序员可以更快的理解模块,而且在调试的时候可以不影响其他维护的负担

          4)虽然模块本身不会带来更好的性能,但是它可以帮助调节性能,通过分析知道哪些模块影响了性能

          5)提高软件的可重用性,模块可以在其它系统中使用

          6)模块可以降低系统风险,整个系统不可用,但是模块却有可能是可用的

      第十四条:在公有类中使用访问方法而非公有域

        变量应该用private定义而不是public的,只能用get/set方法取

        但是如果这个类是包级私有(default)的,或者是内部类的话,则没有关系

      第十五条:使可变性最小化

        使类变为不可变的5条规则:

          1)不要提供任何会修改对象状态的方法(也称为mutator)

          2)保证类不会被扩展(使类成为final的,或者限制访问构造器)

          3)使所有域都是final的

          4)使所有域都是私有的

          5)确保对于任何可变组件的互斥访问(如果能set则不能get对象的引用)

        不可变的类(如复数类),被称作函数(functional)式的做法,相对的是过程(procedural)式的做法和命令(imperative)式的做法

        不可变的类往往有一个可变配套类,来弥补它性能上的缺点(String->StringBuilder)

        坚决不要为每个get方法编写一个相应的set方法,除非有很好的理由。不可变类有很多优点,唯一缺点是潜在的性能问题

      第十六条:复合优先于继承:继承的功能非常强大,但是也存在诸多问题,因为它违背了封装原则。只有当子类和超类之间确实存在子类型关系时,使用继承才是恰当的。否则,可以使用复合来代替继承。    

        第十七条:要么为继承而设计,并提供文档说明,要么就禁止继承

      第十八条:接口优于抽象类:除非演变的容易性比灵活性和功能性更为重要的时候

      第十九条:接口只用于定义类型:常量接口模式是对接口的不良使用,应该使用工具类(utility class)

      第二十条:类层次优于标签类:合理设计类,不要在一个类里塞太多东西,而应该使用抽象类之类的方法分层

      第二十一条:用函数对象表示策略:函数指针的主要用途就是实现策略(Strategy)模式

      第二十二条:优先考虑静态成员变量:四种不同的嵌套类及用法

    五、泛型

       第二十三条:请不要在新代码中使用原生态类型(关于List<?>,一般用于只读模式,因为不知道里面元素的类型,所以不能执行add方法,除非是null。常在方法中出现,限制方法乱add元素,出于安全性考虑。)

       第二十四条:消除非受检警告:使用@SuppressWarnings("unchecked"),并添加注释,尽量加在行上而不要加在方法上。

       第二十五条:列表优先于数组:优先使用泛型而不是数组来存数据,因为泛型是编译时检查类型,而数组是运行时检查,前者更安全。数组和泛型不要混合用。

       第二十六条:优先考虑泛型

       第二十七条:优先考虑泛型方法

      第二十八条:利用有限制通配符来提升API的灵活性:PECS原则(P119)

      第二十九条:优先考虑类型安全的异构容器

    六、枚举和注解

      第三十条:用enum代替int常量

      第三十一条:用实例域代替序数

      第三十二条:用EnumSet代替位域    

      第三十三条:用EnumMap代替序数索引

      第三十四条:用接口模拟可伸缩的枚举

      第三十五条:注释优于命名模式

      第三十六条:坚持使用Override注解

      第三十七条:用标记接口定义类型(标记注解和标记接口各有用处)

    七、方法

      第三十八条:检查参数的有效性

      第三十九条:必要时进行保护性拷贝

      第四十条:谨慎设计方法签名

      第四十一条:慎用重载:重载的话,最好保证参数数目不一致,或者所有重载方法的行为一致。否则程序很容易误入重载方法。

      第四十二条:慎用可变参数:3个以下的参数用重载

      第四十三条:返回零长度数组或是集合,而不是null

      第四十四条:为所有导出的API元素编写文档注释

    八、通用程序设计

      第四十五条:将局部变量的作用于最小化:

        1.不要过早的声明变量,而应该在他第一次使用的地方声明

        2.声明时应该初始化变量,除非是特殊情况(try块内)

        3.for循环优先于while循环,因为有循环变量可以使用

        4.使方法小而集中,也可以将局部变量的作用域最小化

      第四十六条:for-each循环优于传统的for循环

      第四十七条:了解和使用类库:程序员应该把时间花在应用程序上,而不是底层的细节上。不要重复造轮子

      第四十八条:如果需要精度的答案,请避免使用float和double:应该使用BigDecimal处理小数,或者int和long处理整数

      第四十九条:基本类型优先于装箱基本类型:当装箱基本类型和基本类型比较时,装箱基本类型会自动拆箱。如果null对象被自动拆箱,会报NullPointerException异常

      第五十条:如果其他类型更合适,则尽量避免使用字符串:字符串经常被错误的用来代替基本类型、枚举类型和聚合类型等

      第五十一条:当心字符串连接的性能

      第五十二条:通过接口引用对象:优先使用接口,这样会更灵活更聪明

      第五十三条:接口优于反射机制:应该仅仅使用反射机制来实例化对象,而访问对象时则使用编译时已知的某个接口或者超类

      第五十四条:谨慎的使用本地方法

      第五十五条:谨慎的进行优化:不要费力去编写快速的程序——应该努力编写好的程序,速度自然会随之而来

      第五十六条:遵守普遍接受的命名惯例

    九、异常

      第五十七条:只针对异常的情况才使用异常:逻辑控制中,应该使用“状态测试方法”或“可识别的返回值”方法,而不是把异常用于控制流

      第五十八条:对可恢复的情况使用受检异常,对编程错误使用运行时异常

      第五十九条:避免不必要的使用受检的异常

      第六十条:优先使用标准的异常

      第六十一条:抛出与抽象对应的异常

      第六十二条:每个方法抛出的异常都要有文档

      第六十三条:在细节消息中包含能捕获失败的信息

      第六十四条:努力使失败保持原子性

      第六十五条:不要忽略异常

    十、并发

      第六十六条:同步访问共享的可变数据

      第六十七条:避免过度同步

      第六十八条:excutor和task优先于线程

      第六十九条:并发工具优先于wait和notify

      第七十条:线程安全性的文档化

      第七十一条:慎用延迟初始化

      第七十二条:不要依赖线程调度器:确保可运行线程的平均数量不明显的多于处理器的数量

      第七十三条:避免使用线程组(thread group),已基本废弃,应该使用线程池executor

    十一、序列化

      第七十四条:谨慎的实现Serializable接口

      第七十五条:考虑使用自定义的序列化形式

      第七十六条:保护性的编写readObject方法

      第七十七条:对于实例控制,枚举类型优先于readResolve

      第七十八条:考虑用序列化代理代替序列化实例

  • 相关阅读:
    4header组件开发
    3组件骨架开发
    2项目目录设计
    1项目相关的一些简介
    21AJax与Comet
    20JSON
    获取特定筛选条件下数据的四分位点
    动态长度字符串的解析拆分问题
    myBase Desktop 7无限免费试用方法
    VBA 将Excel工作簿中所有表格进行一键排版
  • 原文地址:https://www.cnblogs.com/xujanus/p/4505421.html
Copyright © 2011-2022 走看看