`

Effictive Java 不完全学习笔记

    博客分类:
  • Book
阅读更多

这里只是基于自己的理解做的一些记录, 一些对自己来说已经是一种常识, 将不再列出.

由于作者是sun jdk collection framework的主要贡献者, 因此书中很多的effective rule, 大多数是对collection framework实现的一个总结(很多例子都是拿Collection中的东东在说事儿), 站在JDK API的高度来思考的, 这些考虑是非常严谨的, 而我们平时的开发可能不会注意到这些细节, 或者可能没有作者所说的场景, 因此可以根据需要选择性的理解.

第5条 消除过期的对象引用
这里讲到了一个因为过期引用导致的内存泄漏的问题, 而平时我们也很难注意到这个问题,  这个例子是一个Stack的实现, 在Stack内部用一个数组来缓存堆栈中的所有元素, 在其pop方法里面这样写:
public Object pop(){
	if (size == 0){
		throw new EmptyStackException();
	}
	return elements[--size];
}

当弹出一个元素的时候, elements其实还存在对这个元素的引用. 正确的做法应该是
Object result = elements[--size];
element[size]=null;
return result;

但是对于java来说, 每次对不再使用的对象手工强制设置为null这不是一种好的处理方式, 之所以要这么做的前提是:需要对象自己来管理内存, 即对于不再使用的对象, 需要明确的告诉垃圾收集器不再使用, 否则就会造成内存泄漏.

第8条 改写equals时总是要改写hashCode
hashCode对HashMap这种需要用到HashCode的容器具有非常重要的意义.
这里作者举了个电话号码的例子, 如果一个电话号码包括区号, 号码和分机号, 对象为PhoneNumer("0571", "88155188", "1234"), 但是未实现hashCode()方法;在hashMap中用PhoneNumber作为key, 用户名作为value这样保存, hashMap.put(new PhoneNumer("0571", "88155188", "1234"),"jenny"), 如果用PhoneNumer("0571", "88155188", "1234")到hashMap中取得的却是null

计算hashCode, 17是一个不错的初始值, 37是一个不错的乘数因子, 计算hashcode, 一般采用这种写法:
result = 17;
result = result * 37 + property1 hashcode;
result = result * 37 + property2 hashcode;
result = result * 37 + property3 hashcode;


第12条 使类和成员的可访问能力最小化
如果需要声明一个共有的静态final数组时, 应该将其声明为私有,  然后提供一个非可变的 final List, 比如下面的做法:
private static final type[] PRIVATE_VALUES = {...};
public static final List VALUES = Collections.unmodiableList(Arrays.asList(PRIVATE_VALUES));

还有一个做法是通过一个公共的方法, 然后返回数组的clone, 即保护性拷贝

第14条 复合优于继承
这是一个老生常谈的话题, 继承的优点是有利于重用, 但是却带来安全的问题.
在一个包内的继承是可以接受的, 因为包内的继承几乎可以被认为是在同一个程序员的控制范围之内, 还有只有那些专门为继承而设计的基类, 这样的继承基本上也是安全的, 而对于普通的具体类使用继承的一个问题就是破坏了原有类的封装性, 从而给程序埋下了bug的种子.
这里作者举了继承HashSet实现计数功能的例子, 计数针对add和addAll方法来进行, 但是addAll内部是调用add方法来添加元素的, 而子类的计数功能必须依赖父类这个并没有承诺的实现细节,  如果父类addAll方法的实现细节发生改变, 将导致子类的计数功能失败. 为了保证子类的计数功能不依赖父类的实现, 通常不得已的做法是重写父类的相关代码.
盲目的继承会存在各种问题, 而优于继承的复合却能克服这些问题, 作者针对上面的问题用复合来举例子, 让用于计数的HashSet实现Set接口, 内部持有一个真正的HashSet实例, 然后将所有的方法转发到HashSet实例上, 这样整个计数Set完全不用依赖HashSet内部的实现细节, 除了带来健壮性外, 还带来了灵活性
只有两个类A和B之间存在is-a关系的时候(B确实是一个A), 才应该采用继承.

第15条
好的API文档应该描述一个方法做了什么工作, 而并非描述它是如何做到的.
构造函数最好不要调用(或依赖)可被改写的方法, 这个主要是处于初始化的考虑, 因为父类的构造函数会在子类构造函数初始化之前被调用, 而被改写的方法又依赖于子类是否初始化, 这样导致初始化失败.

第16条 接口优于抽象类
抽象类主要处理具有层次关系的架构(在这种场景下, 抽象类可能优于接口了), 而接口则可以不受这个应用场景的限制, 他可以为类mixin新的功能.

第17条 接口只能用于定义类型
这个主要是作者针对在接口中定义常量的做法的控诉, 我觉得没那么严重, 只要没有让需要使用常量的类继承常量接口即可, 这样常量接口跟在类中定义常量没有区别.

第18条 优先考虑静态成员类
如果你声明的成员类不要求访问外围实例, 那么请记住把static修饰符放到成员类的声明中.
非静态成员类的每一个实例都隐含的与外围类的一个实例紧密的关联在一起, 这样非静态成员类的实例才能调用外围类实例的方法.
作者举了几个Collection中的例子.一个是List中的Iterator, Map中的keySet, valueSet, 因为他们自己都不缓存数据, 需要访问外部类实例中数据, 因此必须是非静态的内部类.而对于HashMap中的每一对键值(key-value)的包装类Entry来说, 虽然一个Entry需要与一个具体的Map关联, 但是它的getValue, setValue等方法并不需要访问外部类HashMap, 而是在创建每一个Entry的时候就已经从Map中拿到key, value并塞到Entry中去了.
对于匿名类, 主要用来封装那些非常简短的逻辑, 如果代码超过20行, 则采用匿名类就不是很理想了.

第28条 为导出的API编写文档
为API编写的JavaDoc文档应该简洁的描述它与客户之间的约定, 应该说明它做了什么, 而不是描述它如何做的, 如果是方法的话, 最好描述它的前置条件(调用这个方法必须满足的条件)和后置条件(成功调用之后, 哪些条件必须满足), 一般情况下, @throws中隐含的非检查异常就是前置条件 ,因为每一个非检查异常就意味着一个不满足的条件, 有时候也在@param中来说明前置条件.
此外还应该描述方法的副作用, 也就是对其他相关内容造成的影响.
在写方法的JavaDoc的时候, 一般@param和@return后面应该接一个名词, 而@throws 应该以"如果"开头来表明异常将在什么情况下抛出来.
对于方法, 类, 属性的描述有一些不成为的规律:
对于方法和构造函数的概要描述, 应该是一个动词短语, 比如
ArrayList(int)描述为:用指定的初始容量构造一个空的列表
Collection.size() 返回集合中元素的数目
对于类, 接口和属性, 概要描述应该是一个名词短语,比如
TimerTask:可以被一次调度的一项任务.

第29条 将局部变量的作用域最小化
这里说明了for循环比while要好的例子.
因为while需要在循环之外定义变量, 而for循环则被包含在了循环内部, 这样就可以避免那些偷懒拷贝代码带来隐患

第30条 了解和使用库
主要是为了说明避免重复发明轮子.
每个程序员应该熟悉java.lang, java.util甚至java.io类库
另外apache的一些库也是我们每个人应该熟悉的:)

第31条 如果要求精确计算, 请避免使用float和double
就是说用float, double来进行涉及到小数的计算是不靠谱的, 应该转换成int和long或者使用BigDecimal.

第39条 只针对不正常的条件才使用异常
异常永远不能用于正常的控制流

第40条 对于可恢复的条件使用被检查的异常, 对于程序错误使用运行时异常
其实我们的程序中, 抛出的异常绝大部分是不可恢复的.因此应该避免使用被检查的异常

第42条 尽量使用标准的异常
IllegalStateException, 这个异常应该属于常用的异常, 如果在一个对象被正确初始化之前被调用, 那么应该抛出这个异常.
一般来说, 所有错误方法的调用可以归结为非法的参数和非法的状态, 但是我们一般不能笼统的抛出IllegalArgumentException, 而应该使用更明确说明异常原因的异常, 比如NullPointerException, IndexOutOfBoundsException等.

第48条 对共享可变数据的同步访问
这里举了个很好的使用同步的例子:使用双检查, 将同步缩小在最小范围
延迟初始化, 一般会这样写:
private static Foo foo = null;
public synchronized static Foo getFoo(){
	if (foo == null){
		foo = new Foo();
	}
	return foo;
}

但是可以将同步进一步缩小, 这里采用双检查模式, 在foo初始化之后, 不用再被同步(但是可能存在部分初始化的问题):
public static Foo getFoo(){
	if (foo == null){
		synchronized(Foo.class){
			if (foo == null){
				foo = new Foo();
			}
		}
	}
	return foo;
}

但是更精妙的做法是完全不用同步:
private static class FooHolder{ static final Foo foo = new Foo();}
public static Foo getFoo(){return FooHolder.foo;}

他主要利用了java语言中的"只有当一个类被用到的时候才被初始化"
分享到:
评论

相关推荐

    effective java 读书笔记

    《Effective Java》是Java开发领域的经典著作,作者Joshua Bloch深入浅出地阐述了编写高效、健壮的Java代码的技巧和最佳实践。以下是对该书部分内容的详细解释: 1. **产生和销毁对象** - Item1:静态工厂方法相比...

    读书笔记:Effective Java中文版学习项目.zip

    读书笔记:Effective Java中文版学习项目

    java入门级学习笔记

    【Java入门级学习笔记】 ...总之,Java学习笔记旨在为初学者提供全面的学习路径,从基础知识到核心概念,再到实际应用,逐步构建扎实的Java编程基础。通过持续学习和实践,你可以逐渐掌握这门强大且多用途的语言。

    effectiveJava的笔记

    以下是对《Effective Java》笔记中可能涉及的关键知识点的详细解读: 1. **单例模式**:书中强调了如何正确实现单例模式,推荐使用`enum`来创建线程安全且唯一的实例,避免传统双重检查锁定的潜在问题。 2. **构造...

    Effective-Java读书笔记

    《Effective Java》是Java...以上仅是《Effective Java》一书中部分核心知识点的概述,实际的读书笔记中会更详细地解释这些概念,并给出具体的示例代码。通过深入学习和实践,开发者可以极大地提升其Java编程的水平。

    Effective Java.zip

    《Effective Java》是一本经典Java编程指南,作者是Joshua Bloch,这本书深入探讨了...以上内容仅是《Effective Java》各章节的部分知识点概述,书中还有更多关于Java编程的最佳实践和深入理解等待读者去发掘和学习。

    java学习PDF下载地址全 百度云盘下载

    本资源集合提供了一份完整的“Java学习PDF”,旨在帮助学习者系统地理解和掌握Java编程。 这份PDF教程可能涵盖以下关键知识点: 1. **Java简介**:介绍Java的历史、特点、应用领域以及与其它编程语言的对比,使...

    java学习书籍

    以下是一些关于Java学习书籍的知识点,这些书籍可以帮助你从入门到精通,全面提升你的Java编程技能。 1. **《Java核心技术卷》**:这套书籍通常分为两卷,卷I主要涵盖基础知识,如语法、数据类型、控制结构、类和...

    5本java学习用书

    让我们逐一探讨这些书籍及其在Java学习中的价值。 1. **《21天学通JAVA》**:这本书通常被推荐为初学者入门的读物,它以简洁易懂的方式介绍了Java的基础知识,包括语法、数据类型、流程控制、面向对象编程概念等。...

    java7hashmap源码-for-java:java学习笔记

    Java学习笔记 Effective Java Topic2:插件销毁对象 2. 多参数情况 使用重叠构造器; 使用Build模式【构建器】: new A.Build().set.set.build(); Build模式也适用于类层次结构 递归类型参数 /* * 递归类型参数: ...

    Java开源项目汇总.pdf

    * CS-Notes:Java学习笔记,涵盖了Java的基础知识、数据结构、算法、设计模式等。 * advanced-java:Java高级教程,涵盖了Java的高级知识、Java设计模式、Java框架和工具等。 Java实战 * miaosha:Java电商项目,...

    JAVA学习百度云资料

    2. **2018年黑马程序员最新Java学习笔记**:这份笔记是由专业教师精心整理的,包含济南校区的精华教学内容,不仅覆盖了基础理论,还有实践案例,是学习过程中的重要参考资料。链接:...

    notes:JavaJava后端工程师的学习笔记https

    loveincode's notes 学习工作中的一些记录,收藏。 操作系统 , 编译原理 , 计算机网络 , 互联网协议... 常用数据结构与算法 Java 实现 数据结构 与 排序算法 ...Effective Java , HTTP权威指南 , Java

    drools学习笔记

    在 LHS(左侧)中,"," 和 "&&"、"||" 不能混合使用,确保了逻辑的清晰性。drools 提供了多种比较操作符,如 >、<、==、!= 以及更复杂的 contains、memberOf 和 matches。例如,contains 用于检查对象的集合字段...

    java-note:Java学习笔记

    Structure /src/main/java ... ├ effective_java Effective Java 中文第二版 ├ jvm 深入理解Java虚拟机:JVM高级特性与最佳实践 ├ lambda JAVA 8实战 ├ netty Netty权威指南 ├ oop ├ recursion

    这些年学习JAVA的资源,包括工具和资源包

    比如Awesome Java集合了各种Java资源,Java-Interview提供了面试准备资料,JDK源码阅读笔记帮助理解Java内部机制,Java设计模式实现则涵盖了各种设计原则,而Java学习笔记提供了从JavaSE到JavaWeb的逐步学习路径。...

    Maven 2 学习笔记.txt

    ### Maven 2 学习笔记 #### 一、Maven 项目的基本结构及创建 Maven使用特定的目录结构来组织项目文件,通过`mvn archetype:create`命令可以快速创建项目模板。例如: ```shell mvn archetype:create -DgroupId=...

    Java心得 学JAVA必看

    根据给定的文件信息,以下是对“Java心得 学JAVA必看”的详细...以上这些心得不仅仅是针对Java学习者,对于所有编程爱好者来说都是非常宝贵的建议。希望每位读者都能够在这条道路上越走越远,成为一名真正的编程高手。

    leetcode题库-MyNote:`13的学习笔记

    的学习笔记 学习笔记与练习项目源码整理 The Only Easy Day Was Yesterday 编程语言 C 参考书籍 : 《c primer plus》 6th edition 书内习题答案总结 , 优秀源码赏析 快速平方根算法 kilo (1000行的源文本编辑器) ...

Global site tag (gtag.js) - Google Analytics