您好,欢迎来到花图问答。
搜索
您的当前位置:首页《Effective Java》读书笔记 —— 通用程序设计

《Effective Java》读书笔记 —— 通用程序设计

来源:花图问答

本文讨论一些 Java 语言的具体细节,局部变量的处理、控制结构、类库的用法、各种数据类型的用法等。

1.将局部变量的作用域最小化

将局部变量的作用域最小化的优点:

  • 增强代码可读性
  • 可维护性
  • 降低出错可能性

具体做法:

  • 在第一次使用变量的地方声明
  • 几乎每个局部变量的声音都应该包含一个初始化表达式
  • for循环中,优先使用循环变量
  • 优先使用for循环,而不是while循环,因为for循环可以定义循环变量,while循环只能在外部定义变量
  • 使方法小而集中

2.for-each循环优先于传统for循环

for-each的优点:

  • 可以隐藏迭代器或者索引变量,避免出现混乱和错误
  • 不会有性能损失,甚至有性能优势,因为它对数组索引的边界值只计算一次(虽然可以手动将数组索引边界提取到循环外)。
  • 对于嵌套多层循环,for-each更有优势,可以避免 Iterable 嵌套循环出现的bug
  • for-each不仅可以遍历集合和数组,还可以遍历任何实现 Iterable 接口的对象
    for (Iterator i = c.iterator(); i.hasNext();) {
        
    }
    
    for (int i = 0; i < a.length; i++) {
        
    }

    for (Element e : elements) {
        
    }

无法使用 for-each 的情况:

  • 过滤:如果需要遍历集合,并删除选定的元素,就只能使用显式的迭代器,以便可以调用 remove 方法
  • 转换:如果需要遍历列表或者数组,并取代它部分或者全部的元素,就需要列表迭代器或数组索引,以便设定元素的值
  • 平行迭代:如果需要并行地遍历多个集合,就需要显式地控制迭代器或者索引变量,以便所有迭代器或者索引变量都可以得到同步前移。

3.了解和使用类库

4.如果需要精确的答案,请避免使用 float 和 double

float和double执行的是二进制浮点运算,为了在广泛的数值范围上提供较为精确的快速近似计算而设计。缺点是,让一个float和double精确表示0.1(或者10的任何其他负数次方数值)是不可能的。

替换方案:BigDecimal、int、long

BigDecimal缺点,它不是基本数据类型,这样操作简单问题很不方便。优点可以支持舍入操作

int和long需要自己处理十进制小数点

5.基本类型优于装箱基本类型

基本类型和装箱基恩类型的区别:

  • 基本类型只有值,装箱类型则具有与它们的值不同的同一性。两个装箱基本类型可以具有相同的值和不同的同一性
  • 基本类型只有功能完备的值,而装箱类型还包括一个非功能值,null
  • 基本类型比装箱类型更节省时间和空间

当在一项操作中混合使用基本类型和装箱基本类型时,装箱基本类型就会自动拆箱,这种情况无一例外,如果null对象引用被自动拆箱,就会得到一个 NulPointerException 异常。

另外,混合使用时,尤其在循环中,变量反复的装箱和拆箱,会导致明显的性能下降。

使用装箱基本类型的场景:

  • 作为集合中的元素、key或者value,因为不能将基本类型放到集合中
  • 必须使用装箱基本类型作为类型参数,Java 不允许使用基本类型,ThreadLocal<int> 错误,ThreadLocal<Integer> 正确
  • 进行反射的方法里,必须使用装箱基本类型

自动装箱减少了使用装箱基本类型的繁琐,但并没有减少它的风险。尤其在使用==操作符时要注意

6.如果其他类型更合适,则尽量避免使用字符串

不应该使用字符串的情景:

  • 字符串不适合代替其他的值类型,应该使用 int、float或者BitInteger 类型,如果是是或者否,应该转换为boolean
  • 字符串不适合代替枚举类型,枚举类型比字符串更加适合用来表示枚举类型的常量
  • 字符串不适合代替聚集类型,如果一个实体有多个组件,用一个字符串来表示这个实体通常是不恰当的,而且要想访问组件域,解析过程也很繁琐,可以用一个私有的静态成员类替代
  • 字符串不适合代替能力表(capalities)

7.当心字符串连接的性能

字符串连接操作 + 是把多个字符串合并为一个字符串的遍历途径。缺点:不适合运用在大规模的场景中,为连接n个字符串而重复地使用字符串连接操作符,需要n的平方级的时间。这是由于字符串不可变性导致的,当两个字符串被连接时,它们的内容都要被拷贝。

具体例子:

    String result = "";
    for (int i = 0; i < 100; i++) {
        result += lineForItem(i);
    }
    return result;

解决方案:

  • 使用StringBuilder替换String,append方法
  • 使用字符数组,或者每次只处理一个字符串,而不是将它们组合起来

8.通过接口引用对象

应该使用接口而不会类作为类型的参数。更一般的讲,应该优先使用接口而不是类来引用对象。如果有合适的接口类型存在,那么对于参数、返回值、变量和域来说,都应该使用接口类型进行声明。

List<String> stringList = new ArrayList<String>()  正确
ArrayList<String> stringList = new ArrayList<String>() 错误

用接口作为类型的优点:更加灵活,方便更换实现,只需改变构造器中类的名称(或者使用一个不同的静态工厂)

9.接口优先于反射机制

核心反射机制,提供了“通过程序来访问关于已装载的类的信息”的能力。

反射的缺点:

  • 丧失了编译时类型检查的好处,包括异常检查,如果程序企图调用不存在或者不可访问的方法,在运行时它将会失败。
  • 执行反射访问所需要的代码非常笨拙和冗长
  • 性能损失,反射方法调用比普通方法慢很多

使用反射的情况:

  • 类浏览器
  • 对象监视器
  • 代码分析工具
  • 解释型的内嵌式系统
  • RPC(远程过程调用)

10.谨慎使用本地方法

JNI 允许 Java 应用程序调用本地方法(C或者C++)。本地方法在本地语言中可以执行任意的计算任务,并返回到Java中。

本地方法的用途:

  • 访问特定于平台的机制,比如访问注册表和文件锁
  • 访问遗留代码块的能力
  • 编写应用程序注重性能的部分

本地语言是不安全的,不再能免受内存毁坏错误的影响,本地语言和平台相关,不再是可移植的。随着Java平台的成熟,已经提供了越来越多以前只有在宿主平台才拥有的特性,并且JVM的实现也越来越快。

11.谨慎地进行优化

有三条有关优化的格言。

很多计算机上的过失都归咎于效率(没有必要达到的效率),而不是任何其他的原因——甚至包括盲目的做傻事。
不要去计较效率上的一些小小的得失,在97%的情况下,不成熟的优化才是一切问题的根源。
在优化方面的两个规则:1.不要优化。2.还是不要优化。

要努力编写好的程序,而不是快的程序

12.遵守普遍接受的命名规范

Copyright © 2019- huatuowenda.com 版权所有 湘ICP备2023022495号-1

违法及侵权请联系:TEL:199 1889 7713 E-MAIL:2724546146@qq.com

本站由北京市万商天勤律师事务所王兴未律师提供法律服务