看啥推荐读物
专栏名称: minute5
目录
相关文章推荐
今天看啥  ›  专栏  ›  minute5

Effective Java理解(结尾)

minute5  · 掘金  ·  · 2019-08-31 11:46
阅读 9

Effective Java理解(结尾)

最小化局部变量的作用域

  1. 在首次使用局部变量的地方声明它

for-each 循环优于传统 for 循环

有三种常见的情况是你不能分别使用 for-each 循环的:

  1. 有损过滤(Destructive filtering)——如果需要遍历集合,并删除指定选元素,则需要使用显式迭代器,以便可以调用其 remove 方法。 通常可以使用在 Java 8 中添加的 Collection 类中的 removeIf 方法,来避免显式遍历。
  2. 转换——如果需要遍历一个列表或数组并替换其元素的部分或全部值,那么需要列表迭代器或数组索引来替换元素的值。
  3. 并行迭代——如果需要并行地遍历多个集合,那么需要显式地控制迭代器或索引变量,以便所有迭代器或索引变量都可以同步进行

若需要精确答案就应避免使用 float 和 double 类型,尤其是货币运算

  1. 使用 BigDecimal、int 或 long 进行货币计算总之,对于任何需要精确答案的计算,不要使用 float 或 double 类型。
  2. 如果希望系统来处理十进制小数点,并且不介意不使用基本类型带来的不便和成本,请使用 BigDecimal。
  3. 使用 BigDecimal 的另一个好处是,它可以完全控制舍入,当执行需要舍入的操作时,可以从八种舍入模式中进行选择。
  4. 如果你使用合法的舍入行为执行业务计算,这将非常方便。如果性能是最重要的,那么你不介意自己处理十进制小数点,而且数值不是太大,可以使用 int 或 long。如果数值不超过 9 位小数,可以使用 int;如果不超过 18 位,可以使用 long。如果数量可能超过 18 位,则使用 BigDecimal。

谨慎优化

  1. 不要努力写快的程序,要努力写好程序;速度自然会提高。但是在设计系统时一定要考虑性能,特别是在设计API、线路层协议和持久数据格式时。
  2. 当完成了系统的构建之后,请度量它的性能。如果足够快,就完成了。如果没有,利用分析器找到问题的根源,并对系统的相关部分进行优化。第一步是检查算法的选择:再多的底层优化也不能弥补算法选择的不足。根据需要重复这个过程,在每次更改之后测量性能,直到你满意为止。

异常不要乱用

  1. 异常应该只用于异常的情况下;他们永远不应该用于正常的程序控制流程。
  2. 比如使用异常来作为循环的退出条件,这种基于异常的循环模式不仅模糊了代码的意图,降低了它的性能,而且它还不能保证正常工作!如果出现了不相关的 bug,这个模式会悄悄的消失从而掩盖了这个 Bug,极大地增加了调试过程的复杂性。

异常使用

  1. 对于可恢复的情况,比如某一时刻系统访问量增大,内存不足,要抛出受检异常;
  2. 对于程序错误,比如内存泄漏,就要抛出运行时异常。
  3. 不确定是否可恢复,就抛出为受检异常。不要定义任何既不是受检异常也不是运行异常的抛出类型。要在受检异常上提供方法,以便协助程序恢复。
  4. 如果不能阻止或者处理来自更低层的异常,一般的做法是使用异常转译,转译成高层适用的异常,只有在低层方法的规范碰巧可以保证“它所抛出的所有异常对于更高层也是合适的”情况下,才可以将异常从低层传播到高层。
  5. 要为你编写的每个方法所能抛出的每个异常建立文档。
  6. 为异常的失败- 捕获信息,比如数组越界时的上界,下界和当前位置index。

失败的原子性

  1. 失败的方法调用应该使对象保持在被调用之前的状态

同步异步

  1. 当多个线程共享可变数据的时候,每个读或者写数据的线程都必须执行同步。 如果没有同步,就无法保证一个线程所做的修改可以被另一个线程获知。未能同步共享可变数据会造成程序的活跃性失败( liveness failure )和安全性失败( safety failure ) 。
  2. 为了避免活性失败和安全性失败,在一个被同步的方法或者代码块中,永远不要放弃对客户端的控制。 就是不要在需要同步的代码中使用到调用者提供的方法 。从包含该同步区域的类的角度来看,这样的方法是外来的( alien ) 。这个类不知道该方法会做什么事情,也无法控制它。根据外来方法的作用,从同步区域中调用它会导致异常、死锁或者数据损坏。
  3. 应该在同步区域内做尽可能少的工作
  4. 多使用executor 、task 和 stream 而不是线程

避免使用序列化

  1. 序列化是危险的,应该避免。如果你从头开始设计一个系统,可以使用跨平台的结构化数据,如 JSON 或 protobuf。不要反序列化不可信的数据。如果必须这样做,请使用对象反序列化过滤,但要注意,它不能保证阻止所有攻击。避免编写可序列化的类。如果你必须这样做,一定要非常小心。
  2. 如果非要实现序列化,那么有很多缺陷
    1. 实现 Serializable 接口的一个主要代价是,一旦类的实现被发布,它就会降低更改该类实现的灵活性。
    2. 增加了出现 bug 和安全漏洞的可能性
    3. 增加了与发布类的新版本相关的测试负担
    4. 去实现Serializable 接口需要考虑的很多
    5. 为继承而设计的类很少情况适合实现 Serializable 接口,接口也很少情况适合扩展它
    6. 内部类不应该实现 Serializable,静态成员类可以实现 Serializable 接口
参考:
  1. 《effective java》3rd -- Joshua Bloch



原文地址:访问原文地址
快照地址: 访问文章快照