《Effective java》-----读书笔记

时间:2022-06-10 06:03:27

2015年进步很小,看的书也不是很多,感觉自己都要废了,2016是沉淀的一年,在这一年中要不断学习、看书,努力提升自己!预计在2016年要看12本书,主要涉及java基础、Spring研究、java并发、JVM、分布式之类的。在今年面试的时候深受打击,到处都是问分布式、集群的?难道现在工作两三年的都这么牛逼了?都在搞分布式、集群之类的?

2016书单如下:

1、深入理解Java虚拟机:JVM高级特性与最佳实践---(已看,预计今年看三遍)

2、Oracle查询优化改写技巧与案例---(已看)

3、Effective Java---(已看)

4、Spring3.x企业应用开发实战

5、Spring技术内幕:深入解析Spring架构与设计原理---(这本书在去年已经看了一遍了,今年在好好研究下)

6、Java并发编程的艺术

7、Java并发编程实战---(这本书在去年已经看了一遍了,今年在好好研究下)

8、型网站系统与Java中间件实践

9、分布式服务框架原理与实践

10、大型分布式网站架构设计与实践

11、从Paxos到Zookeeper分布式一致性原理与实践

12、高性能mysql

目前已经看完了三本书:深入理解Java虚拟机:JVM高级特性与最佳实践、Oracle查询优化改写技巧与案例、Effective Java。其中深入理解jvm这本书确实是一本神书,看完之后真的有种豁然开朗的感觉,期待三遍之后给我醍醐灌顶的感觉。Oracle查询优化,感觉一般般。Effective java,四大圣经之一不做解释。

各位,有什么好书,麻烦推荐下,LZ不胜感激!

LZ没看一本书,都会做一些笔记,当然这些仅仅只是笔记而已!刚刚开始有点儿简陋,不要介意,如果对你还有点儿帮助,LZ一心满意足了!

二、:创建和销毁对象

2.1.考虑用静态工厂方法替换构造器

1.2.用私有构造器或者枚举类型强化Singleton属性

1.4.通过私有构造器强化不可实例化的能力。

1.5.避免创建不必要的对象。

优先使用基本类型而不是装箱基本类型,要当心无意识的自动装箱。

1.6.消除过期的对象引用

        如果一个栈先是增长,再是收缩,那么,从栈中弹出来的对象将不会被当做垃圾回收,即使使用栈的程序不再引用这些对象,他们也不会被回收。这是因为,栈内部维护这对这些对象的过期引用。所谓过期引用则是指永远也不会再被解除的引用。

一般来说,对于过期引用我们都是清空这些引用即可(也就是set null),但是这样势必会导致程序变得异常混乱,最好的办法则是让包含该引用的变量结束生命周期。

出现内存溢出常见的来源有:1、过期引用,2、缓存,3、监听器和其他回调。对于缓存我们通常的做法则是定时地清除一些没有用的项,想想缓存里面保存了几年了无用的项是不是都觉得恶心?回调则是只保存他们的弱引用,例如只将他们保存成WeakHashMap的键。

      可以借助Heap剖析工具分析内存泄漏的问题

四、类和接口

4.1、使类和成员的可访问行最小化

    良好的模块设计可以将所有的实现细节隐藏,把他的API与具体的实现清晰地隔离开来,模块与模块之间只通过他们的API进行通信,一个模块不需要知道其他模块的内部工作情况---信息隐藏。

4.2、使可变性最小化

    1)为了使类不可变,需要遵循如下规则:

1.不要提供任何会修改对象状态的方法

2.保证类不会被扩展

3.所有域都要是final,且为私有

4.确保对于任何可变组件的互斥访问。

    2)不可变类的好处

    1.不可变对象本质是线程安全的,不要求同步

    2.不可变对象为其他对象提供了大量的构件

    3)缺点在于需要为每一个不同的值提供不同的对象。如果创建的对象比较大,那么所产生的代价就有点高了。

    为了不可变性,类是绝对不允许被子类化,我们首先想到的就是“final”修饰,其实除了这点还有一个比较好的办法:让类的所有构造器全部变为私有,并且提供一个公有的静态工厂。

4.3、组合、继承

    优先使用组合,慎用继承。

 

组 合 关 系 继 承 关 系
优点:不破坏封装,整体类与局部类之间松耦合,彼此相对独立 缺点:破坏封装,子类与父类之间紧密耦合,子类依赖于父类的实现,子类缺乏独立性
优点:具有较好的可扩展性 缺点:支持扩展,但是往往以增加系统结构的复杂度为代价
优点:支持动态组合。在运行时,整体对象可以选择不同类型的局部对象 缺点:不支持动态继承。在运行时,子类无法选择不同的父类
优点:整体类可以对局部类进行包装,封装局部类的接口,提供新的接口 缺点:子类不能改变父类的接口
缺点:整体类不能自动获得和局部类同样的接口 优点:子类能自动继承父类的接口
缺点:创建整体类的对象时,需要创建所有局部类的对象 优点:创建子类的对象时,无须创建父类的对象

请记住下面两句话:

继承要慎用,其使用场合仅限于你确信使用该技术有效的情况。一个判断方法是,问一问自己是否需要从新类向基类进行向上转型。如果是必须的,则继承是必要的。反之则应该好好考虑是否需要继承。《Java编程思想》

只有当子类真正是超类的子类型时,才适合用继承。换句话说,对于两个类A和B,只有当两者之间确实存在is-a关系的时候,类B才应该继续类A。《Effective Java》

4.4、接口、抽象类

1.接口是定义mixin的理想选择

2.接口允许我们构造非层次接口的类型框架

    3.骨架实现类

通过对你导出的每一个重要接口都提供一个抽象的骨架实现类,把接口和抽象类的优点结合起来。这个时候接口的作用仍然是定义类型,但是骨架实现类接管了所有域接口实现相关的工作。骨架实现被称之为AbstractInterface。

    骨架实现的美妙之处在于,它们为抽象类提供了实现上的帮助,但是又不会强加“抽象类被用做定义类型时”所特有的严格限制。同时在编写骨架实现时一般都需要经过认真研究接口,并确定那些方法是最为基础的,其他方法则可以根据他们来实现。这些基本的方法将成为骨架实现类中的抽象方法(这里是模板方法模式??)。

    4.接口只用于定义类型。

    5.常量接口不值得效仿,接口应该只被用来定义类型,不应该被用来导出常量。

    6.对于常量的使用我们应该遵循如下规则:如果常量与某个现有的类或者接口紧密相关,就应该把这些常量添加到这个类或者接口中;如果常量最好被看做枚举类型的成员,则应该用枚举类型来导出这些常量;否则应该使用不可实例化的工具类来导出这些常量。

4.5内部类

    内部类的主要作用应该只为他的外围类提供服务。内部类主要有四种:静态成员类、非静态成员类、匿名类、局部类。

静态成员类常用作为公有的辅助类,仅当与它的外部类一起使用时才有意义。私有静态成员类一种常用的方法是用来代表外围类所代表的对象的组件,他它不需要依赖外围类。

    匿名内部类没有名称,它并不是外围类的一个成员,它并不与其他的成员一起被声明,而是在使用的同时被声明和实例化。在使用的过程中,除了在他们被声明的时候之外,是无法将他们实例化的。匿名类有三种常用的用法:动态创建函数对象,创建过程对象(Runable、Thread、TimeTask)、静态工厂方法的内部。

五、泛型

    推荐使用泛型,虽然他在运行时会被擦除。

    尽可能地消除每一个非受检警告。如果无法消除警告,同时可以证明引起警告的代码是类型安全的,则可以使用@SuppressWarnings("unchecked")注解来禁止这条警告,同时我们必须要竟可能小的范围使用该注解,禁止在整个类上使用该注解。

七、方法

    7.1必要时,对不可变对象的构造器和访问方法进行检查性保护。

    7.2、谨慎设计方法签名

    1.谨慎地选择方法的名称:方法名称应该始终遵循标准的命名习惯。

    2.不要过于追求提供便利的方法,每个方法应该极尽其所能。

    3.避免过长的参数列表,一边提供四个参数或者更少。

    避免参数过长一般有三种方法:1).将该方法分解成多个方法 2).创建辅助类,用来保护参数的分组 3).从对象构建到方法的调用都采用Builder模式。

    4.优先使用接口而不是实现类来作为参数类型。你应该不会把HashMap作为一个参数的!!

    7.3、慎用重载

    1.方法重载是在编译时做出决定的。

    2.永远都不要导出两个具有相同参数数目的重载方法,这是一个安全保守的方法。

    3.任何一组给定的实际参数将应用于那个重载方法上。

    4.同一组参数只需要经过类型转换就可以被传递给不同的重载方法,如果不能避免这种情况,就应该保证:当传递同样的参数是,所有重载方法的行为必须一致。

    7.4、慎用可变参数

    可变参数接受0个或者多个指定类型的参数。其机制是先创建一个数组,数组的大小为在调用位置所传递参数的数量,然后将参数值传递给数组,最后将数组传递给方法。

    7.5、返回零长度的数组或者集合,而不应该是null。不重要但是值得注意。

八、通用程序设计

    8.1局部变量作用域最小化

    将局部变量的作用域最小化,可以增强代码的可读性和可维护性,并降低出错的可能性。

    要是局部变量的作用域最小化,最有力的方法就是在第一次使用它的地方声明。一般来说每个局部变量都应该有一个初始化,如果没有足够的信息来对该变量进行有意义的初始化,则需要推迟该变量的声明,直到可以被初始化为止。

    对于方法而言,应该尽可能地使方法小而集中,这样就可以将局部变量的作用域尽可能地小化。

   8.2、优先使用for-each循环

    for循环相比于while循环它可以使局部变量更小化,同时程序更加简短增强了可读性。

    for-each循环在简洁性和预防bug方面有着传统for循环无法比拟的优势,并且没有性能损失,所以我们应该尽可能使用for-each循环,但是在以下三种情况是否无法使用for-each循环的:

    1.过滤:如果需要遍历某个集合,删除特定的元素,则需要使用显示的迭代器。

    2.转换:如果需要遍历列表或者数组,并取代它部分或者全部元素值,这时就需要迭代器来进行设置元素的值。

    3.平行迭代

    8.3、优先使用基本类型

    基本类型相当于其引用类型有如下几个区别:1.)基本类型只有值,而引用类型则具有他们值不同的同一性,也就说new Integer(1) != new Integer(1);2).基本类型具有功能完备的值,而引用还有一个null值 3).基本类型通常比引用类型更加节省空间和时间。

    当在一项操作中混合使用基本类型和其引用类型时,其引用类型会自动进行拆箱动作。

    在进行迭代时需要格外注意拆箱装箱机制,因为频繁的拆箱装箱会导致性能的下降。

其他

    1.如果需要精确的答案,请使用BigDecimal而不是double和float。

    2.如果有合适的接口类型存在,那么对于参数、返回值、变量和域来说,就都应该使用接口类型进行声明。

九、异常

    异常应该只用于异常的情况下,他们永远不应该用于正常的控制流。

    异常机制设计是用于不正常的情况,所以很少会有JVM会对他进行优化,所以异常一般运行都比较慢。

    我们应该尽量让异常代码块小,因为try..catch会阻碍JVM实现本来可能要执行的某些特定的优化。