Effective Java有感

会不定时更新,毕竟代码写的越多,理解的越多。

1.考虑用静态工厂方法代替构造函数。

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

3.使用私有构造函数强化不可实例化的能力。

4.避免创建重复的对象。当一个对象被重复使用且该对象非可变时,不能让它每次被调用的时候就创建一个新的对象,应让它持续可用。

String s = new String("hello world");  // Don't DO THIS!
String s = "hello world"; // Good job!

5.消除过期的对象引用。

6.避免使用终结函数。终结函数(finalizer)通常是不可预测的,有可能导致不稳定的行为以及更差的性能。在Java中一般使用try-finally来完成类似工作。这样可能会导致几个方面的问题:

a.用finally来关闭一个打开的文件,但在执行try的时候,这个时间是不可控的且JVM会延迟执行终结函数,所以有可能还没执行finally去关闭的时候另一个程序去打开该文件会导致失败。

b.及时地执行终结函数是垃圾回收算法的一个主要功能,但该算法在不同的JVM环境实现的效果是不一样的。这个程序本地测试良好,但到客户环境有可能运行不了,无法保证平台运行效果的一致性。

c.执行终结函数线程的优先级比其他线程低,所以当需要在终结函数释放的资源还没执行时,其他线程已经在运行了,会导致资源不足OOM等问题。

7.在改写equals的时候请遵守通用约定。在改写equals方法的时候,要遵守它的通用约定:

a.自反性(reflexive)。对于任意的引用值x,x.equals(x)一定为true。

b.对称性(symmetric)。对于任意的引用值x和y,当且仅当y.equals(x)返回true时,x.equals(y)也一定返回true。

c.传递性(transitive)。对于任意的引用值x、y和z,如果x.equals(y)返回true,并且y.equals(z)也true,那么x.equals(z)也一定返回true。

d.一致性(consistent)。对于任意的引用值x和y,如果用于equals比较的对象信息没有被修改的话,那么,多次调用x.equals(y)要么一致地返回true,要么一致地返回false。

e.对于任意的非空值x,x.equals(null)一定返回false。

8.改写equals时总是要改写hashcode。

9.总是要改写toString。toString默认返回类的名称+@+散列码的无符号十六进制,例"People@163b91"。改写toString方法,让它返回我们想要的信息。

10.谨慎地改写clone。

11.考虑实现Comparable接口。

12.使类和成员的可访问能力最小化。判断一个模块是否设计良好,最重要的因素是,这个模块对于外部的其他模块而言,是否隐藏了内部的数据和其他的实现细节。用好private、protected、public。

13.支持非可变性。一个非可变类是一个简单的类,它的实例不能被修改。每个实例中包含的所有信息都必须在该实例被创建时就提供出来,并且在对象的整个生存周期内固定不变。String, 数据类型的包装类, BigIngteger和BigDecimal。非可变类比可变类更加易于设计,实现和使用,不容易出错,更安全。一个非可变类要遵循五条原则:

a.不提供任何会修改对象的方法。b.保证没有可被子类改写的方法。c.使所有的域都是final。d.使所有的域都成为私有的。e.保证对于任何可变组件的互斥访问。

14.复合优先于继承。

15.要么专门为继承而设计,并给出文档说明,要么禁止继承。

16.接口优于抽象类。这边可以参考接口和抽象类的区别。

17.接口只是被用于定义类型。 定义一个接口里面含有一些常量,然后一个类通过继承这个常量接口进而取到值,这种做法是不可取的,会导致很多问题。

18.优先考虑静态成员类。如果声明的成员类不要求访问外界实例,记得加上static修饰符,使之成为静态成员类。若忽略了static修饰符,则每个实例都将包含一个额外的指向外围对象的引用。维护这份引用要消耗时间和空间。但是当在没有外围实例的情况下,也要分配实例的话,则也要让它成为静态成员类,因为非静态成员类需要一个外围实例。

19.用类代替结构。结构(Struct)是C语言的,但在Java中被省略了,因为结构能做到的事情,类都能做到,而且类还能做一些结构做不到的事情。比如继承和被继承。

20.用类层次来代替联合。

21.用类来代替enum结构。

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

23.检查参数的有效性。考虑好参数的各种可能性及边界(null、负数等),从而让程序更健壮。

24.需要时使用保护性拷贝。

25.谨慎设计方法的原型。a.谨慎选择方法名称(Java API库参考);b.不要过于追求提供便利的方法。让每个方法都有存在的意义,方法太多会使类难以使用和理解;c.避免长长的参数列表。必要时可以考虑封装成对象。d.对于参数类型,优先使用接口而不是使用实现该接口的类。接口支持更多的参数类型。

26.谨慎地使用重载。

27.返回零长度的数组而不是null。如果返回null的话,原本的集合或者数组的数据结构会发生变化,后续操作也会产生不必要的麻烦。所以建议返回空数组或者空集合。

// Don't do this!
private List infoList = ...; 
if (infoList.size()) {
    return null;
}
// Good job!
private List infoList = ...; 
if (infoList.size()) {
    return Collections.emptyList();
}

28.为所有导出的API元素编写文档注释。

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

30.了解和使用库。

31.如果要求精确的答案,请避免使用float和double。float和double类型主要设计目标是为了科学计算和工程计算,它们执行二进制浮点运算,是为了广域数值范围上提供较为精确的快速近似计算而精心设计的,并没有提供完全精确的结果。

32.如果其他类型合适,则尽量避免使用字符串。如果有合适的数据类型,则应避免使用字符串来表示对象。若使用不当,则字符串比其他类型更加笨拙,缺乏灵活性,速度缓慢,也容易出错。

33.了解字符串连接的性能。字符串用"+"拼接适合规模比较小的,不适合规模比较大的情形。为连接n个字符串而重复地使用字符串连接操作符,要求n的平方级的时间。这是由于字符串是非可变的(13)而导致的结果,当两个字符串被连接的时候,它们的内容都要被拷贝。

// Don't do this!
public String statement() {
    String s = "";
    for (int i = 0; i < num; i++)
        s += lineForItem(i);
    return s;
}
// Good job!
public String statement() {
    StringBuffer s = new StringBuffer(num * LINE_WIDTH);
    for (int i = 0; i < num; i++)
        s.append(lineForItem(i));
    return s.toString;
}

String的做法的开销随数量呈平方级增加,StringBuffer是线性增加。

34.通过接口引用对象。程序会相对灵活。

35.接口优先于映像机制。

36.谨慎地使用本地方法。

37.谨慎地进行优化。

38.遵守普遍接受的命名惯例。参考命名规则

39.只针对不正常的条件才使用异常。不随意在正常代码中try-catch,异常应用于不正常的条件。

40.对于可恢复的条件使用被检查的异常,对于程序错误使用运行时异常。Java提供了三种可抛出结构(throwable):被检查的异常(checked exception)、运行时异常(run-time exception)和错误(error)。

41.避免不必要地使用被检查的异常。

42.尽量使用标准的异常。重用现有的异常有几个好处:让你的API更容易学习和使用,因为它与程序员原本已经熟悉的习惯用法是一致的;API程序的可读性更高,因为不会充斥着程序员不熟悉的异常;异常类越少,意味着内存占用越小,并且装载这些类的时间开销也越小。别随意抛莫名其妙的异常,应针对具体场景抛出异常。

43.抛出的异常要适合于相应的抽象。抛出的异常应与执行的任务有明显的关联关系。

44.每个方法抛出的异常都要有文档。

45.在细节消息中包含失败-捕获信息。

46.努力使失败保持原子性。一个失败的方法调用应该使对象保持“它在被调用之前的状态”。

47.不要忽略异常。只管捕捉,而不做捕捉后的任何操作,这是一种不负责任的行为。

// Don't do this!
try {
    ...
} catch (Exception e) {
}

48.对共享可变数据的同步访问。Synchronized关键字可以保证在同一时刻,只有一个线程在执行一条语句或者一段代码块。

49.避免过多的同步。过多的同步可能会导致性能降低,死锁,甚至不确定等行为。

50.永远不要在循环的外面调用wait。

51.不要依赖于线程调度器。

52.线程安全性的文档化。

53.避免使用线程组。

54.谨慎地实现Serializable

55.考虑使用自定义的序列化形式。

56.保护性地编写readObject方法。

57.必要时提供一个readResolve方法。

转载于:https://my.oschina.net/134596/blog/2223438

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值