• 《Effective Java》知识点(8)--通用编程


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

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

           要使局部变量的作用域最小化,最有力的方法就是在第一次要使用它的地方进行声明。另一方法是使方法小而集中。

           几乎每一个局部变量的声明都应该包含一个初始化表达式

           for循环优先于while循环。for循环更能避免“剪切-粘贴”错误;更简短,可读性更好。

    58. for-each循环优先于传统的for循环

           与传统的for循环相比,for-each循环在简洁性、灵活性以及出错预防性方面都占有绝对优势,并且没有性能惩罚的问题。多重循环时,for循环容易出错。

           无法使用for-each的三种情况:

       a. 如果需要遍历集合,并删除选定的元素,就需要使用显式的迭代器,以便调用remove方法。

       b. 如果需要遍历列表或者数组,并取代它的部分或者全部元素值,就需要用迭代器或数组索引。

       c. 如果需要并行地遍历多个集合,就需要显式地控制迭代器或者索引变量,以便所有迭代器或索引变量可以同步前进。

    59. 了解和使用类库

           使用标准类库的好处: 

       a. 可以充分利用这些编写标准类库的专家的知识,以及在你之前的其他人的使用经验。

       b. 不必浪费时间在底层细节,而把时间花在应用程序上。

       c. 它们的性能会随着时间推移而不断提高。

       d. 它们会随着时间的推移而增加新的功能。

       e. 可以使自己的代码融入主流。

    每个程序员都应该熟悉java.lang、java.util、java.io及其子包中的内容。 

    优先在类库查找所需功能,如果类库找不到,下一个选择应该是在高级的第三方类库去寻找,如Guava类库。如果都找不到,最后才是选择自己实现这些功能。

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

         float和double类型尤其不适合用于货币计算。请优先使用BigDecimal,如果性能是关键,可以使用int或long。如果数值不超过9位十进制数,使用int;如果不超过18位,使用long;如果可能超过18位,还是用BigDecimal。

    61. 基本类型优先于装箱基本类型

          基本类型(int,double,boolean)比装箱基本类型(Integer,Double,Boolean)更加简单、快速,应优先使用。

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

      a. 基本类型只有值,而装箱类型具有与它们的值不同的同一性。

      b. 基本类型只有函数值,而装箱类型除了函数值,还有个null。

      c. 基本类型通常比装箱类型更节省时间和空间

    61.2 什么时候用装箱类型

       a. 作为集合中的元素、键和值

       b. 在参数化类型和方法中,必须用装箱类型作类型参数

       c. 在进行反射的方法调用时

    61.3 使用装箱注意事项

        a. 对装箱类型运用==操作符通常是错误的,因为比较的是对象而不是值

        b. 当在一项操作中混用基本类型和装箱类型是,装箱类型会自动拆箱,可能抛出空指针异常

        c. 当基本类型转装箱时,会导致资源消耗和不必要的对象创建

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

           字符串不适合代替基本类型。

           字符串不适合代替枚举类型。

           字符串不适合代替聚合类型。

           字符串不适合代替能力表(capabilities),如授权访问中作key。 

    63. 了解字符串连接的性能

    63.1 不要使用字符串连接操作符来合并多个字符串(需要n的平方级的时间)

    63.2 使用StringBuilder的append方法来连接字符串

    63.3 使用字符数组,或者每次只处理一个字符串,而不是将它们组合起来

    64. 通过接口引用对象

           如果有合适的接口类型存在,那么对于参数、返回值、变量和域来说,就都应该使用接口类型进行声明。养成用接口作为类型的习惯,程序将会更加灵活。如果没有合适的接口,就用类层次结构中提供了必要功能的最小的具体类来引用对象。

           不存在适当接口类型的情形:

       a. 值类(如String,BigInteger)经常是final的,且很少有对应的接口。

       b. 对象属于一个框架,而框架的基本类型是类,不是接口。一般用基类(抽象类)引用对象。

       c. 类实现了接口,但它提供了接口不存在的额外方法。 这种类只能引用它的实例。

    65. 接口优先于反射机制

           核心反射机制(core reflection facility),java.lang.reflect包,提供了“通过程序来访问任意类”的能力。反射机制允许一个类使用另一个类,即使当前者被编译的时候,后者还根本不存在。如果编写的程序必须要与编译时未知的类一起工作,如有可能应该仅仅用反射机制来实例化对象,而访问对象时则使用编译时已知的某个接口或者超类。

           反射机制的代价:

       a. 损失了编译时类型检查的优势,包括异常检查。可能运行时失败。

       b. 执行反射访问所需的代码非常笨拙和冗长,阅读困难。

       c. 性能损失。 反射方法调用比普通方法调用慢许多。

    66. 谨慎地使用本地方法

          所谓本地方法是指用本地编程语言(如C或C++)来编写的方法。JNI允许Java程序调用本地方法。使用本地方法来访问特定于平台的机制是合法的,但是几乎没有必要。

          使用本地方法来提高性能的做法不值得提倡。

          使用本地方法的一些缺陷:

      a. 程序可能受内存毁坏错误的影响,因为本地语言不是安全的。

      b. 程序不可自由移植,因为本地语言是平台相关的。

      c. 程序更难调试

      d. 还可能降低性能,因为内存回收不是自动的,并且进入和退出本地代码需要相关开销。

      e. 需要“胶合代码”的本地方法编写起来单调乏味,难于阅读。

    67. 谨慎地进行优化

          优化的弊大于利,特别是不成熟的优化。

          不要为了性能而牺牲合理的结构。努力编写好的程序而不是快的程序。

           必须在设计过程中考虑性能问题,而不是系统完成之后要努力避免那些限制性能的设计决策。最主要的组件是API、交互层协议以及永久数据格式。要考虑API设计决策的性能后果。

           在每次试图做优化之前和之后,要对性能进行测量。如果将要在多个JVM实现和多种硬件平台上运行程序,则需要在每个Java实现和平台上测量优化效果。

           系统构建完后应该测量性能。如果不够快,则可以在性能分析器的帮助下,找到问题的根源,然后设法优化系统中相关的部分。第一个步骤是检查所选择的算法:再多的低层优化也无法弥补算法的选择不当。必要时重复这个过程。

    68. 遵守普遍接受的命名惯例

          命名惯例分两大类:字面的和语法的。

    标识符类型字面惯例示例
    包或者模块名称应该是层次状的,用句号分割每个部分。每个部分是小写字母,偶有数字。org.junit.jupiter.api
    类或者接口(包括枚举和注解)一个或多个单词,每个单词的首字母大写Stream,HttpClient
    方法或者域第一个字母小写remove,groupingBy
    常量域字母都小写,每个单词间用下划线MIN_VALUE
    局部变量允许缩写,单个字符和短字符序列,取决于上下文环境i,houseNum
    类型参数单个大写字母

    T:  任意类型

    E:  集合的元素类型

    K和V: 映射的键和值

    X:  异常

    R:  函数的返回类型

    T、U、V、T1、T2、T3: 任何类型的序列

          语法命名惯例比字面惯例更加灵活,也更有争议。

    标识符类型语法惯例示例
    可实例化的类(包括枚举)名词或名词短语Thread
    不可实例化的工具类复数名词Collectors
    接口名词或形容词Collection,Runnable,Accessible
    注解名词、动词、介词、形容词Inject,Singleton
    执行动作的方法动词或动词短语append
    返回boolean的方法is开头isDigit
    设置对象属性的方法set开头setAttribute
    获取对象属性的方法get开头getAttribute
    转换对象类型的实例方法toTypetoString,toArray
    返回视图的方法asTypeasList
    返回与被调用对象同值的方法typeValueintValue
    静态工厂

    from,of,valueOf,

    instance,getInstance,newInstance,

    getType,newType

           不要盲目遵从惯例,请使用大家公认的做法。

  • 相关阅读:
    Linux驱动开发:字符设备驱动开发实战
    PYTHON蓝桥杯——每日一练(简单题)
    【C++】list容器模拟实现
    JAVA - 反射
    NJU操作系统公开课笔记(1)
    2023年度中国开源研究报告
    Leetcode.1123 最深叶节点的最近公共祖先
    .Net 472&6.0 Razor编译时的小差异
    信奥 提高篇 高级数据结构 RMQ问题 ST算法(2022.11.02)
    Git(11)——Git相关问题解答以及常用命令总结
  • 原文地址:https://blog.csdn.net/myepicure/article/details/133434974