第68项:遵守普遍接受的命名惯例

  Java平台建立了一整套很好的命名惯例(naming convention),其中有许多命名惯例包含在了《The Java Language Specification》[JLS, 6.1]中。不严格地讲,这些命名惯例分为两大类:字面的(typographical)和语法的(grammatical)。

  字面的命名惯例比较少,涉及包、类、接口、方法、域和类型变量。应该尽量不违反这些惯例,没有很好的理由就绝不要违反它们。在这两种情况下,违反惯例都会潜在地给使用这些代码的其他程序猿带来困惑和苦恼,并且使他们做出错误的假设,造成程序出错。本项将对这些惯例做简要的介绍。

  包的名称应该是层次状的,用句号【英文句号】分隔每个部分。每个部分都包括小写字母和数字(很少使用数字)。任何将在你的组织之外使用的包,其名称都将以你的组织的Internet域名开头,并且顶级域名放在前面,例如edu.cmu、com.google、org.eff。标准类库和一些可选的包,其名称以java和javax开头,这属于这一规则的例外。用户创建的包的名称绝不能以java和javax开头。可以在JLS中找到将Internet域名转换为包名称前缀的详细规则[JLS, 6.1]。

  包名称的其余部分应该包括一个或者多个描述该包的组成部分。这些组成部分应该比较简短,通常不超过8个字符。鼓励使用有意义的缩写形式,例如,使用util而不是utilities。只取首字母的缩写形式也是可以接受的,例如awt。每个组成部分通常都应该由一个单词或者一个缩写词组成。

  许多包的名称中除了Internet域名就只有一个组成部分。大型工具包可适当使用额外的组成部分,它们的规模决定了应该分隔成非正式的层次结构。例如,javax.util包有着非常丰富的包层次,如java.util.concurrent.atomic。这样的包通常被称为子包,尽管Java语言并没有提供对包层次的支持。

  类和接口名称(包括枚举和注释类型名称)应由一个或多个单词组成,每个单词的首字母大写,例如,List或FutureTask。除了首字母缩略词和某些常用缩写(如max和min)之外,应避免使用缩写。关于首字母缩略词是大写还是仅首字母大写,存在一些分歧。虽然一些程序员仍然使用大写字母,但可以提出一个强有力的论据,只支持第一个字母大写:即使连续出现多个首字母缩写的形式,你仍然可以区分出一个单词的起始处和结束处。下面这个类名你更愿意看到哪一个,HTTPURL和HttpUrl?

  方法和字段的名称遵循与类和接口名称相同的字面惯例,但方法或字段名称的第一个字母应为小写,例如remove或ensureCapacity。如果首字母缩略词作为方法或字段名称的第一个单词出现,则它应该是小写的。

  上述规则的唯一例外是“常量域”,其名称应由一个或多个大写单词组成,单词之间使用下划线字符分隔,例如VALUES或NEGATIVE_INFINITY。常量域是个静态final域,它的值是不可变的。如果静态final域具有基本类型,或者有不可变的引用类型(第17项),则它是常量域。例如,枚举常量是常量域。如果静态final域有个可变的引用类型,若被引用的对象是不可变的,它也仍然可以是个常量域。注意,常量域仍然是唯一推荐使用下划线的情形。

  局部变量名称的字面命名惯例与成员名称类似,只不过它也允许缩写,单个字符和短字符序列的意义取决于局部变量所在的上下文环境,例如i、denom和houseNum。输入参数是一种特殊的局部变量。它们的名称【命名】应该比普通的局部变量更加仔细,因为它们的名称是其方法文档中不可或缺的一部分。

  类型参数名称通常由单个字母组成。这个字母通常是以下五种类型之一:T表示任意的类型,E表示集合的元素类型,K和V表示映射的键和值类型,X表示异常。函数的返回类型通常是R。任何类型的序列可以使T、U、V或者T1、T2、T3。

  为便于快速参考,下表显示了字面惯例的示例。

Identifier TypeExamples
Package or moduleorg.junit.jupiter.api, com.google.common.collect
Class or InterfaceStream, FutureTask, LinkedHashMap, HttpClient
Method or Fieldremove, groupingBy, getCrc
Constant FieldMIN_VALUE, NEGATIVE_INFINITY
Local Variablei, denom, houseNum
Type ParameterT, E, K, V, X, R, U, V, T1, T2

  语法命名惯例比字面命名惯例更加灵活,也更有争议。对于包而言,没有语法命名惯例。类(包括枚举类型)通常用一个名词或者名词短语命名,例如Thread、PriorityQueue或者ChessPiece。不可实例化的工具类(第4项)通常以复数名词命名,例如Collectors或者Collections。接口的命名与类相似,例如Collection或Comparator,或者用一个able或ible结尾的形容词来命名,例如Runnable、Iterable或者Accessible。由于注解类型有那么多用处,因此没有单独安排词类。名词、动词、介词和形容词都很常用,例如BindingAnnotation、Inject、ImplementedBy或者Singleton。

  执行某些操作的方法通常使用动词或动词短语(包括对象)命名,例如append或drawImage。返回布尔值的方法通常具有以单词is开头(很少用has开头)的名称,后跟名词,名词短语或任何用作形容词的单词或短语,例如isDigit,isProbablePrime,isEmpty,isEnabled,或hasSiblings。

  返回非布尔函数或调用它们的对象的属性的方法通常以名词,名词短语或以动词get开头的动词短语命名,例如size,hashCode或getTime。有一种声音认为,只有第三种形式(以“get”开头)才可以接受,但是这种说法没有什么根据。前两种形式往往会产生可读性更好的代码,例如:

if (car.speed() > 2 * SPEED_LIMIT)
    generateAudibleAlert("Watch out for cops!");

  以get开头的形式源于大部分过时的Java Beans规范,该规范构成了早期可重用组件体系结构的基础。有一些现代工具继续依赖于Beans命名约定,你可以随意在任何与这些工具结合使用的代码中使用它。如果一个类包含同一属性的setter和getter,那么遵循这个命名约定也有一个很好的惯例。在这种情况下,这两个方法通常命名为getAttribute和setAttribute。

  一些方法的名称值得特别提及。转换对象类型、返回不同类型的独立对象的实例方法,通常称为toType,例如toString或toArray。返回视图(view)(返回类型与接收对象类型不同的视图)的方法通常称为asType,例如asList。返回与调用它们的对象具有相同值的基本类型的方法通常称为typeValue,例如intValue。静态工厂的通用名称包括from,of,valueOf,instance,getInstance,newInstance,getType和newType(第1项,【原书】第9页)。

  域名称的语法惯例没有很好地建立起来,也没有类、接口和方法名称的惯例那么重要,因为设计良好的API很少会包含暴露出来的域。boolean类型的域命名与boolean类型的访问方法(accessor method)很类似,但是省去了初始的“is”,例如initialized和composite。其他类型的域通常用名词或者名词短语来命名,比如height、digits或bodyStyle。局部变量的语法惯例类似于域的语法惯例,但是更弱一些。

  总而言之,把标准的命名惯例当作一种内在的机制来看待,并且学着用它们作为第二天性(nature)。字面惯例是非常直接和明确的;语法惯例则更复杂,也更松散。下面这句话引自《The Java Language Specification》[JLS, 6.1]:“如果长期养成的习惯用法与此不同,请不要盲目遵从这些命名惯例。”请运用常识。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值