前言

最近读了这本书,发现平时在写代码的过程中,也无意有意的使用到了书中的观点,特此记录下来,后用。

创建和销毁对象

建议我们什么时候创建,怎么创建,什么时候销毁,怎么销毁,以及销毁前对对象的管理。

1,使用静态工厂方法代替构造函数

1.平时使用最多的当然是new String()语法来构建一个对象。
2.对于String来说,提供了使用静态工厂方法来构建String对象,比如String.valueOf()方法。
好处:
- 静态方法有自己的方法名,可以区分构造时,传入的参数,构造什么样的对象;
- 不一定非要创建一个新的对象,比如单例模式就使用到了这一点;
- 可以返回一个原返回类型的子类;

2,使用私有构造函数,强化singleton属性

在使用单例模式时,尽量私有化构造方法建议两种写法:

//公有静态属性方式
public class Elvis {public static final Elvis INSTANCE = new Elvis();public Elvis() {}
}
//静态工厂方法方式
public class Elvis {private static final Elvis INSTANCE = new Elvis();public Elvis() {}public static Elvis getInstance() {return INSTANCE;}
}

在序列化时,注意一下要提供readResolve().

通过私有构造函数强化不可实例化能力

有些时候,会编写出只包含静态方法或者静态域的类,比如一些utils,常量类,还有java api中的java.lang.Math,java.util.Arrays等,这些类显然实例化也没有任何意义,这时,应该私有化其无参构造函数,使其不能创建出对象。
最好也对类加final修饰,表示不能被继承。

避免创建重复对象

应该重复使用一个对象,而不是每次都创建一个相同对象。比如说在使用
String s = new String("silly");
创建一个String对象时,就很笨,因为这种方式,每次都会new出一个String对象,你也会发现这些String对象都是相等的(值相等),使用下面的方式来创建就好很多

String s = "No longer silly";

无论调用多少次,都是同一个对象。
避免这一条的方法,就是使用静态static变量

消除过期的对象引用

介绍了数组在使用过程中,会存在过期引用问题。
不过自己写代码过程中,好像没有注意到这个问题,反而一些其他引起OOM的问题注意的更多,比如:IO流,Cursor游标,TypedArray等,都需要及时的关闭。但注意有时我们会不经意间写出这样的代码:

            FileInputStream fis = null;ByteArrayOutputStream bos = null;try {fis = new FileInputStream(file);bos = new ByteArrayOutputStream();int len = 0;byte[] bytes = new byte[1024];while ((len = fis.read(bytes)) != -1) {bos.write(bytes, 0, len);}} catch (Exception e) {e.printStackTrace();} finally {try {fis.close();bos.close();} catch (Exception e) {e.printStackTrace();}}return bos.toByteArray();

bos流已经关闭了,但是后面的代码还会使用到,就会报错。解决方法很简单,就在合适的位置声明一个String类型,在try代码中给它赋值即可。

避免使用终结函数

finalize()是Object的方法,这个方法是在当一个对象销毁的时候被调用,很明显对象销毁的时候,是系统执行的,所以我们不应该去管它。
还记得刚毕业去面试时,面试题目还有final,finally,finalize这3个关键字的关系呢,现在我知道了,原来他们3个根本没有关系。

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

本章主要讲解Object对象需要重写的方法:equals(),hashCode(),toString(),clone()等.因为这些方法很通用,很常用,所以重要性也就会提高。

在改写equals的时候请遵守通用约定

对于这一条,在实际项目中还没有遇到,通常也就用用String类的equals(),可能项目中对数据的处理还是少了些吧。
equals()的几个通用约定:
- 自反性:对于任意的引用值x,x.equals(x)一定为true。
- 对称性:x.equals(y) 等于 true,那么y.equals(x)也为true。
- 传递性:x,y,z三个值,x == y ,y == z ,那么x == z也成立。
- 一致性:就是说,x,y在没有变化的实话,在任何时候调用x.equals(y)都必须一致的返回true(false)。
- 对于任意的非空引用值x,x.equals(null)一定返回false。

高质量equals()的’处方’:
1. 使用==检查“实参是否指向同一个对象的引用”
2. 使用instanceof检查”实参是否是正确的类型”
3. 把实参转换到正确的类型(因为第二步已经检查过了)
4. 对于该类的每一个“关键域”,都要做检查,只有所有匹配成功才能返回true
5. 写好equals()后,检测一下,是否符合上面提到的通用准则
注意:不要将equals(Object o)中的参数修改为其他类型,这样做并没有重写Object中的equals方法(参数不同),会增加对象的复杂度,例:

public boolean equals(MyClass o){...
}

改写equals()时,总是要改写hashCode()

改写的目的就是为了在某些集合类中正常工作,比如:HashMap、HashSet 、Hashtable等基于散列值(Hash)的集合。
hashCode()的几个通用约定:
- 在一次程序执行期间,只要一个对象的equals()比较信息没有修改过,那么多次执行hashCode(),必须返回同一个整数。在多次程序执行期间,hashCode()返回值可以不同。
- 如果两个对象的通过equals()判断相等,那么他们的hashCode()返回值也相等。
- 如果两个对象的通过equals()判断不相等,那么他们的hashCode()返回值不要求必须产生不同的值(就说可以是相同的hashCode值),但我们要知道,产生不同的值,能提高hash表的性能。

所以没有重写hashCode(),就违反了第二条约定。
这一条也很少用到,反正我们应该从对象的属性中去获取一些基本类型的对象,然后在想办法返回一个不同的值,比如,如果都是int型的属性,那么可以编写一个固定的公式算出一个值返回。如果是String类型,可以先求出单个的hashCode()然后在组合起来。

总是要重写toString()

调用toString(),应该返回一个“简洁的,信息丰富,便于阅读”的字符串。如果该类没有重写toString()就会调用Object提供的toString():getClass().getName() + '@' + Integer.toHexString(hashCode()),返回形式:”PhoneNumber@:63b91”。只能看出类名,所以最好重写toString()返回更有意义的字符串。
在使用字符串连接操作符”+”时,toString()会自动调用,例如:System.out.println("failed to connect: " + phoneNumber)
这里要注意一点,就是toString()返回的字符串应该是我们感兴趣的信息,并且如果有特定需求,还应该返回一些固定格式的字符串,比如json,xml格式。
在实际项目中,发现java bean对象总是应该重写该方法,这样做方便我们打印日志时看清楚对象的值。特定的情况下,还应该返回具有格式的字符串,方便后面保存到数据库或者文件中,供下次使用时,方便生成对象。

谨慎的重写clone()

目前项目中并没有遇到重写该方法。

考虑实现Comparable接口

实现该接口后,在保存该对象的集合,数组中,可以对所有该对象排序。
数组:Arrays.sort();
list集合:Collections.sort()
记得是在展示手机通讯录中信息是用到的,当时是按照人名拼音字母排序,重写过这个方法。

类和接口

使类和成员的可访问能力最小化

考虑到封装性,我们应该这么做。好处:类之间无关联,每个类可以单独开发,维护,测试等。使得程序员可以并行开发产品。
- private使用场景:field域,私有方法,内部类
- protected使用场景:父类中方法,父类的field域
- public使用场景:只要是允许对象成员访问的域或者方法

支持非可变性

就是说,我们可以设计一个不可变的类,该类所有域都是final private的,只要该对象一生成就不可变。
这样的类在实际项目中还没有遇到。书中举了一个虚数的栗子。

复合优先继承

继承是实现代码重用的有力手段,但不一定是最佳选择。在一个包内部使用继承是非常安全的,但是跨包继承则很危险。
继承会打破封装性,使得父类的方法修改会影响到子类。所以常常我们更应该考虑用复合机制来设计类,也就是装饰模式Decorator。
这两种机制很容易搞混,在实际项目中常常会遇到这样的问题:
需要扩展一个类的时候,到底是继承一个这个类,还是在一个类中保持这个类的对象?
原则就是只有明显为继承关系而设计类时,才使用继承,否则用复合,特别是使用别人api的时候,更要用复合。

要么专门为继承二设计,并给出文档说明,要么禁止继承

和上一条类似

接口优于抽象类

任何情况下都要考虑使用接口来扩展类的功能。
只有在专门为继承来设计类结构时,将他们的公用方法抽取出来,使用抽象类来实现的使用是有抽象类机制。
所以抽象类在项目中使用明显少于接口,因为接口很灵活。

接口只是被用于定义类型

这节讲了接口不应该设计成包含常量的接口,虽然可以在接口中定义常量。比如下面的接口就是接口的不良使用:

public interface PhysicalConstants {static final doubel AVOGADROS_NUMBER = 6.02214199e23;
}

更应该把这些常量写在具体的类中,比如:Integer.MAX_VALUE.

优先考虑静态成员类

嵌套类(nested class)是指被定义在另一个类内部的类。嵌套类存在的目的就是只为他的外围类提供服务,如果用于其他环境中,则不应该这样设计。
嵌套类有4种:
- 静态成员类
- 非静态成员类
- 匿名类
- 局部类
后3种被称为内部类。
这几种嵌套类中,使用最频繁的就是匿名类,特别是在Android开发中:

View.onClickListener(new onClickListener(){...
});

只要在表达式可以使用的地方都可以使用,会生成一个匿名对象。
其次就是非静态成员类,在安卓中Adapter的编写,均可以作为嵌套类:

//有个一外围类
class VideoAdapter extends BaseAdapter {...
}

书中说如果该Adapter不需要保存一个外部实例,应该设计为静态成员类,那好像这里的VideoAdapter对象确实不需要保存外部势力,应该也可以设计为静态成员类吧。
局部类项目中很好用,也没有用过,书中表示局部类和域类似的作用区间
引用书中总结:

C语言结构的替代

这一章讲了如何使用java语法代替C语法的办法。虽然博主学过C,也是从C转过来的,不过由于现在java发展成熟了,而且现在好多人都是直接学的java,所以本章的知识点显得没有那么重要了,不过还是把标题列出来吧。

用类代替结构

用类层次来代替联合

用类来代替enum结构

目前jdk1.5开始已经又Enum类型了。

用类和接口来代替函数指针

方法

本章讨论几个方面:如何处理参数和返回值,如何设计方法原型,如何为方法编写文档。

检查参数的有效性

在很多方法和构造函数中都会对传递给它们的参数值有某些限制。比如,索引值是非负数,对象引用不能为null等。这些限制,我们应该在文档中说明,有必要的话,更应该在方法的开头对这些参数做检查。
因为某些时候无效的参数会使程序抛出一个运行时异常。特别是某些时候,参数不会再改方法中时候,而是赋值给field变量,留在后面使用。这样的话,如果后面的方法抛出关于这个变量的异常,就不容易找到异常的源头了。常常这样的事件就在构造函数中发生,因为构造函数的参数,一般都是初始化变量的。
在项目中,因为是自己写的方法,参数,所以一般只在有必要时去检测参数的有效性。

需要时使用保护性拷贝

谨慎设计方法的原型

  • 谨慎选择方法的名字,尽量保持和系统api命名方式一致,比如getXXX(),setXXX(),removeXXX()等
  • 不要对于最求提供便利的方法,每个方法一个功能点
  • 避免长长的参数列表
  • 对于参数类型,优先使用接口 而不是类

谨慎地使用重载

重载机制,确实会让人在调用的时候考虑该传那些参数,会增加代码复杂度。当然系统api自己用习惯了,当然感觉很好用,但用第三方api时就会感觉复杂。就如同书中提的建议,重载时,尽量保持参数不同。
其实这一条到不是很重要,项目中使用时,方法都是你写的,很熟悉,不容易搞混。

返回零长度的数组而不是null

集合也一样,这样做我相信能避免很多空指针异常。
因为我们常常会忘记去判空,直接for(),但是在for()中,如果数组为空,则会直接报异常,而零长度数组不会。

为所有导出API元素编写文档注释

如果项目中需要的话,则很必要。如果项目没有要求,可以在关键处使用标准的文档注释。这样做也可以在IDE中,自己写代码时,可以使用快捷键查看方法的注释。

Effective Java高效编程(一)相关推荐

  1. java高效编程_Java高效编程

    非可变类就是类的实例不能被修改的类.如String. 非可变类有很多好的存在理由非可变类更容易设计.实现和使用 不易犯错误 更安全 为了使类成为非可变的,要遵循下面5条原则不要提供任何修改对象的方法. ...

  2. Java高效编程之Builder模式

    前言 在<Effective Java 第2版>中有提到,遇到多个构造器参数时要考虑使用构建器(Builder模式).相比于重叠构造器(telescoping constructor)模式 ...

  3. 告别996,开启Java高效编程之门

    教程介绍 所谓"武以快为尊,天下武功唯快不破".本课程剑指Java高效编程,致力于从"技术"和"工具"两大 维度提高编程效率,帮助广大程序员 ...

  4. 关于阅读java编程思想和effective java的一些看法

    个人认为,java编程思想并不适合当作新手入门书籍来看,它更多是像给已经使用过java的人群对于基础的一些查缺补漏,有点像一本大部头的工具书,目前该书已看至第十章 -- 内部类, 而effective ...

  5. 架构师速成之路 架构师速成-如何高效编程 for java

    赵云大喝一声,挺枪骤马杀入重围,左冲右突,如入无人之境.那枪浑身上下,若舞梨花:遍体纷纷,如飘瑞雪. 赵云是所有历史人物中我最喜欢的一个,如果放到现代,他走了it的道路,一定可以成为一个编程高手.为什 ...

  6. 架构师速成-如何高效编程 for java

    引子 赵云大喝一声,挺枪骤马杀入重围,左冲右突,如入无人之境.那枪浑身上下,若舞梨花:遍体纷纷,如飘瑞雪. 赵云是所有历史人物中我最喜欢的一个,如果放到现代,他走了it的道路,一定可以成为一个编程高手 ...

  7. Java编程思想+Effective Java+Java核心技术+Java核心技术 卷II+Java语言程序设计(中文+英文+源码)

    Java四大名著(中文+英文+源码 ) 传说中的java四大名著,分享出来方便大家学习! 书名如下: Java编程思想 Effective Java(第2版) Java核心技术 卷I(第8版) Jav ...

  8. 简明高效的 Java 并发编程学习指南

    你好,我是宝令,<Java 并发编程实战>专栏作者,很高兴你能看到这篇内容. 对于一个Java程序员而言,能否熟练掌握并发编程是判断他优秀与否的重要标准之一.因为并发编程是Java语言中最 ...

  9. 大话深入浅出Effective Java核心实战编程思想之——猴王的把戏

    不知道大家还记不记得在<西游记>里的莲花洞夺宝的故事,就是猴王巧夺宝物,收复金银角大王那一章.到底这个故事给了我们什么启示呢?这故事又和Effective Java有什么联系?还是延续上篇 ...

最新文章

  1. 《ABAQUS 6.14超级学习手册》——1.2 ABAQUS分析模块
  2. TNS-12545: Connect failed because target host or object does not exist
  3. 【TensorFlow-windows】学习笔记七——生成对抗网络
  4. Kubernetes基础:Pod的详细介绍
  5. Forrester:华为云容器是容器混合云最佳选择
  6. HBase流量限制和表负载均衡剖析
  7. Js 将图片的绝对路径转换为base64编码(3)
  8. BIO | NIO | AIO (Java版)
  9. python3.9.5安装教程加汉化
  10. LINUX矩阵键盘简单介绍,矩阵键盘程序流程图的详细介绍
  11. JS 替换字符串中指定字符
  12. adb shell wm 命令使用
  13. 【图片识别算法】黑白图片输出为二进制矩阵 --python代码
  14. 如何自己制作一个GIF微信表情
  15. 打开记事本文件出现黑色方块的解决办法
  16. TCP 与 CPU 架构发展史
  17. 百词斩个人中心功能测试
  18. Ubuntu视频没有声音
  19. 快速Euclidean算法
  20. 阿里巴巴java开发规范手册

热门文章

  1. 2021年最新k8s面试题
  2. Python爬取半次元图片[一]
  3. layui单元格内的多个名称,通过拼接的方式显示
  4. P1640 [SCOI2010]连续攻击游戏:(二分图)
  5. Python中pymssql 的使用操作
  6. 2019产业AI速写:农业篇
  7. 初学者对PHP的总结,PHP初学者总结
  8. Android 开机自动加载新wifi模块驱动
  9. 补一个 pima-indians-diabetes.data
  10. android极光推送成功率,记一次调用极光推送的惨痛经历