Java编程规约(源于阿里,精简版)

简介: Java编程规约(源于阿里,精简版)

一、命名风格

(1)代码中的命名均不能以下划线或美元符号开始,也不能以下划线或美元符号结束


       反例:_name / name$


(2)代码中的命名严禁使用拼音与英文混合的方式,更不允许直接使用中文的方式


       正例:alibaba / taobao / youku / hangzhou 等国际通用的名称,可视同英文


       反例:getPingfenByName() [评分] / int 价格 = 3


(3)类名使用大驼峰命名法


       正例:MarcoPolo / UserDO


(4)方法名、参数名、成员变量、局部变量使用小驼峰命名法


       正例: localValue / getHttpMessage()


(5)包名统一用小写


       正例: com.alibaba.open.util


(6)常量命名全部大写,单词间用下划线隔开


       正例:MAX_STOCK_COUNT


(7)抽象类命名使用 Abstract 或 Base 开头;


        异常类命名使用Exception结尾;


        测试类的命名要以它要测试的类的名称开始,以Test结尾


(8)定义数组的时候,应该 String[ ] args  ,而不 String args[ ]


(9)POJO 类中布尔类型的变量,都不要加 is,否则部分框架解析会引起序列化错误


       反例:定义为基本数据类型 Boolean isDeleted;的属性,它的方法也是 isDeleted(),RPC框架在反向解析的时候,“以为”对应的属性名称是 deleted,导致属性获取不到,进而抛出异常


命名风格总结:


       命名的目标就是让人见名知义,因此要先统一格式,比如,看到大驼峰命名就知道是个类名,并且还需要让人知道是个什么类,所以在命名的时候应该避开不适当的缩写、拼音与英文混用 等问题


     


二、代码书写规范

       如果使用IDEA进行开发,可以直接使用快捷键 Ctrl+Alt+L 进行代码格式化,格式化遵循以下的准则


(1)大括号的使用约定。如果大括号内为空,直接写为{}即可;如果大括号内不空则:


左大括号前部换行

左大括号后换行

右大括号前换行

右大括号后还有 else 等代码则不换行;表示终止的右大括号后必须换行

(2)一句格式化的代码:if[空格](a[空格]==[空格]b)


    该实例可映射出如下规范:


if / for / while / switch / do 等保留字与括号之间都必须加空格

任何二目、三目运算符的左右两边都需要加一个空格 ( == 为二目运算符 )

左小括号和字符之间不出现空格;同样,右小括号和字符之间也不出现空格

(3)注释的双斜线与注释内容之间有且仅有一个空格


       正例://[空格]注释内容


(4)方法参数在定义和传入时,多个参数逗号后边必须加空格


       正例:method("a",[空格]"b",[空格]"c")


以上是代码格式化能帮我们完成的,此外,我们还要遵循如下准则


(1)采用 4 个空格缩进,禁止使用 tab 字符


       如果使用 tab 缩进,必须设置1个 tab 为4个空格。IDEA设置 tab 为4个空格时,不能勾选Use tab character


(2)单行字符数限制不超过 120 个,超出需要换行,换行时遵循如下原则:


第二行相对第一行缩进 4 个空格,从第三行开始,不再继续缩进,参考示例

运算符与下文一起换行

方法调用时,多个参数,需要换行时,在逗号后进行

在括号前不要换行,见反例


(3)IDE 的 text file encoding 设置为 UTF-8;IDE 中文件的换行符使用 Unix 格式,不要使用Windiws 格式


三、OOP(面向对象编程)规约

(1)避免通过一个类的对象引用访问此类的静态变量或静态方法,直接用类名来访问即可


(2)相同参数类型,相同业务含义,才可以使用 Java 的可变参数,并且可变参数必须放置在参数列表的最后(提倡尽量不用可变参数编程)


(3)Object 的 equals 方法容易抛空指针异常,应使用常量或确定有值的对象来调用 equals 方法


       正例:"test".equals(object)


       反例:object.equals("test")


(4)所有的相同类型的包装类对象之间值的比较,全部使用 equals 方法比较,为的是避免128陷阱


(5)构造方法里面禁止加入任何业务逻辑,如果有初始化逻辑,请放在 init 方法中


(6)对于POJO类(可以简单的理解为实体类)的规范


所有的 POJO 类属性必须使用包装数据类型

定义 DO/DTO/VO 等 POJO 类时,不要设定任何属性默认值

POJO 类必须写 toString 方法。使用 IDE 的中工具:source> generate toString时,如果继承了另一个 POJO 类,注意在前面加一下 super.toString

四、集合使用

(1)只要重写 equals,就必须重写 hashCode


       原因:因为 Set 存储的是不重复的对象,依据 hashCode 和 equals 进行判断,所以 Set 存储的对象必须重写这两个方法


       如果自定义对象做为 Map 的键,那么必须重写 hashCode 和 equals


       String 重写了hashCode 和 equals 方法,所以我们可以非常愉快地使用 String 对象作为 key 来使用


(2)ArrayList的subList结果不可强转成ArrayList,否则会抛出ClassCastException异常


       说明:subList 返回的是 ArrayList 的内部类 SubList,并不是 ArrayList ,而是ArrayList 的一个视图,对于 SubList 子列表的所有操作最终会反映到原列表上


(3)使用集合转数组的方法,必须使用集合的 toArray(T[] array),传入的是类型完全一样的数组,大小就是 list.size()


例子:

List<String> list = new ArrayList<String>(2); 
list.add("guan"); 
list.add("bao"); 
String[] array = new String[list.size()]; 
array = list.toArray(array)

(4)使用工具类 Arrays.asList()把数组转换成集合时,不能使用其修改集合相关的方法,它的add / remove / clear 方法会抛出 UnsupportedOperationException 异常


       原因:asList 的返回对象是一个 Arrays 内部类,并没有实现集合的修改方法      


(5)泛型通配符<? extends T>来接收返回的数据,此写法的泛型集合不能使用 add 方法,而<? super T>不能使用 get 方法,做为接口调用赋值时易出错


(6)不要在 foreach 循环里进行元素的 remove/add 操作。remove 元素请使用 Iterator方式,如果并发操作,需要对 Iterator 对象加锁

正例:
Iterator<String> iterator = list.iterator(); 
while (iterator.hasNext()) { 
    String item = iterator.next(); 
    if (删除元素的条件) { 
        iterator.remove(); 
    } 
}
反例:
List<String> list = new ArrayList<String>(); 
list.add("1"); 
list.add("2"); 
for (String item : list) { 
    if ("1".equals(item)) { 
        list.remove(item); 
    } 
}

(7)在 JDK7 版本及以上,Comparator 要满足如下三个条件,不然 Arrays.sort,Collections.sort 会报 IllegalArgumentException 异常


三个条件如下:


x,y 的比较结果和 y,x 的比较结果相反

x>y,y>z,则 x>z

x=y,则 x,z 比较结果和 y,z 比较结果相同

       反例: 下例中没有处理相等的情况,实际使用中可能会出现异常

new Comparator<Student>() { 
    @Override 
    public int compare(Student o1, Student o2) { 
        return o1.getId() > o2.getId() ? 1 : -1; 
    } 
};

五、注释规范

(1)类、类属性、类方法的注释必须使用/**内容*/格式,不得使用// xxx 方式


(2)所有的抽象方法(包括接口中的方法)必须要用 Javadoc 注释、除了返回值、参数、异常说明外,还必须指出该方法做什么事情,实现什么功能


(3)所有的类都必须添加创建者和创建日期


(4)方法内部单行注释,在被注释语句上方另起一行,使用//注释。方法内部多行注释使用/* */注释,注意与代码对齐所有的枚举类型字段必须要有注释,说明每个数据项的用途


(5)所有的枚举类型字段必须要有注释,说明没个数据项的用途


六、并发处理

(1)线程资源必须通过线程池提供,不允许在应用中自行显式创建线程


       原因:使用线程池的好处是减少在创建和销毁线程上所花的时间以及系统资源的开销,解决资 源不足的问题。如果不使用线程池,有可能造成系统创建大量同类线程而导致消耗完内存或者 “过度切换”的问题


(2)高并发时,同步调用应该去考量锁的性能损耗。能用无锁数据结构,就不要用锁;能 锁区块,就不要锁整个方法体;能用对象锁,就不要用类锁


(3)对多个资源、数据库表、对象同时加锁时,需要保持一致的加锁顺序,否则可能会造成死锁


(4)并发修改同一记录时,避免更新丢失,需要加锁。要么在应用层加锁,要么在缓存加锁,要么在数据库层使用乐观锁,使用 version 作为更新依据


(5)线程池不允许使用 Executors 去创建,而是通过 ThreadPoolExecutor 的方式,这样的处理方式让写的同学更加明确线程池的运行规则,规避资源耗尽的风险


       说明:Executors 返回的线程池对象的弊端如下


FixedThreadPool 和 SingleThreadPool:允许的请求队列长度为 Integer.MAX_VALUE,可能会堆积大量的请求,从而导致 OOM。

CachedThreadPool 和 ScheduledThreadPool:允许的创建线程数量为 Integer.MAX_VALUE,可能会创建大量的线程,从而导致 OOM。

七、其他规范

(1)在一个 switch 块内,每个 case 要么通过 break/return 等来终止,要么注释说明程序将继续执行到哪一个 case 为止;在一个 switch 块内,都必须包含一个 default 语句并且放在最后,即使它什么代码也没有


(2)任何数据结构的构造或初始化,都应指定大小,避免数据结构无限增长吃光内存


(3)注意 Math.random() 这个方法返回是 double 类型,注意取值的范围 0≤x<1(能够取到零值,注意除零异常),如果想获取整数类型的随机数,不要将 x 放大 10 的若干倍然后取整,直接使用 Random 对象的 nextInt 或者 nextLong 方法


       正例:随机生成[0,8]区间的整数


       Random random = new Random();


       int num = random.nextInt(9);


(4)获取当前毫秒数 System.currentTimeMillis(); 而不是 new Date().getTime(),如果想获取更加精确的纳秒级时间值,使用 System.nanoTime()的方式


目录
相关文章
|
2月前
|
Java 开发者
Java多线程编程中的常见误区与最佳实践####
本文深入剖析了Java多线程编程中开发者常遇到的几个典型误区,如对`start()`与`run()`方法的混淆使用、忽视线程安全问题、错误处理未同步的共享变量等,并针对这些问题提出了具体的解决方案和最佳实践。通过实例代码对比,直观展示了正确与错误的实现方式,旨在帮助读者构建更加健壮、高效的多线程应用程序。 ####
|
2月前
|
安全 Java UED
深入浅出Java多线程编程
【10月更文挑战第40天】在Java的世界中,多线程是提升应用性能和响应能力的关键。本文将通过浅显易懂的方式介绍Java中的多线程编程,从基础概念到高级特性,再到实际应用案例,带你一步步深入了解如何在Java中高效地使用多线程。文章不仅涵盖了理论知识,还提供了实用的代码示例,帮助你在实际开发中更好地应用多线程技术。
57 5
|
1月前
|
Java 程序员
Java编程中的异常处理:从基础到高级
在Java的世界中,异常处理是代码健壮性的守护神。本文将带你从异常的基本概念出发,逐步深入到高级用法,探索如何优雅地处理程序中的错误和异常情况。通过实际案例,我们将一起学习如何编写更可靠、更易于维护的Java代码。准备好了吗?让我们一起踏上这段旅程,解锁Java异常处理的秘密!
|
13天前
|
存储 缓存 Java
Java 并发编程——volatile 关键字解析
本文介绍了Java线程中的`volatile`关键字及其与`synchronized`锁的区别。`volatile`保证了变量的可见性和一定的有序性,但不能保证原子性。它通过内存屏障实现,避免指令重排序,确保线程间数据一致。相比`synchronized`,`volatile`性能更优,适用于简单状态标记和某些特定场景,如单例模式中的双重检查锁定。文中还解释了Java内存模型的基本概念,包括主内存、工作内存及并发编程中的原子性、可见性和有序性。
Java 并发编程——volatile 关键字解析
|
17天前
|
算法 Java 调度
java并发编程中Monitor里的waitSet和EntryList都是做什么的
在Java并发编程中,Monitor内部包含两个重要队列:等待集(Wait Set)和入口列表(Entry List)。Wait Set用于线程的条件等待和协作,线程调用`wait()`后进入此集合,通过`notify()`或`notifyAll()`唤醒。Entry List则管理锁的竞争,未能获取锁的线程在此排队,等待锁释放后重新竞争。理解两者区别有助于设计高效的多线程程序。 - **Wait Set**:线程调用`wait()`后进入,等待条件满足被唤醒,需重新竞争锁。 - **Entry List**:多个线程竞争锁时,未获锁的线程在此排队,等待锁释放后获取锁继续执行。
50 12
|
13天前
|
存储 安全 Java
Java多线程编程秘籍:各种方案一网打尽,不要错过!
Java 中实现多线程的方式主要有四种:继承 Thread 类、实现 Runnable 接口、实现 Callable 接口和使用线程池。每种方式各有优缺点,适用于不同的场景。继承 Thread 类最简单,实现 Runnable 接口更灵活,Callable 接口支持返回结果,线程池则便于管理和复用线程。实际应用中可根据需求选择合适的方式。此外,还介绍了多线程相关的常见面试问题及答案,涵盖线程概念、线程安全、线程池等知识点。
93 2
|
2月前
|
设计模式 Java 开发者
Java多线程编程的陷阱与解决方案####
本文深入探讨了Java多线程编程中常见的问题及其解决策略。通过分析竞态条件、死锁、活锁等典型场景,并结合代码示例和实用技巧,帮助开发者有效避免这些陷阱,提升并发程序的稳定性和性能。 ####
|
2月前
|
缓存 Java 开发者
Java多线程编程的陷阱与最佳实践####
本文深入探讨了Java多线程编程中常见的陷阱,如竞态条件、死锁和内存一致性错误,并提供了实用的避免策略。通过分析典型错误案例,本文旨在帮助开发者更好地理解和掌握多线程环境下的编程技巧,从而提升并发程序的稳定性和性能。 ####
|
30天前
|
安全 算法 Java
Java多线程编程中的陷阱与最佳实践####
本文探讨了Java多线程编程中常见的陷阱,并介绍了如何通过最佳实践来避免这些问题。我们将从基础概念入手,逐步深入到具体的代码示例,帮助开发者更好地理解和应用多线程技术。无论是初学者还是有经验的开发者,都能从中获得有价值的见解和建议。 ####
|
30天前
|
Java 调度
Java中的多线程编程与并发控制
本文深入探讨了Java编程语言中多线程编程的基础知识和并发控制机制。文章首先介绍了多线程的基本概念,包括线程的定义、生命周期以及在Java中创建和管理线程的方法。接着,详细讲解了Java提供的同步机制,如synchronized关键字、wait()和notify()方法等,以及如何通过这些机制实现线程间的协调与通信。最后,本文还讨论了一些常见的并发问题,例如死锁、竞态条件等,并提供了相应的解决策略。
50 3