前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >实用主义编程规范:JAVA篇

实用主义编程规范:JAVA篇

作者头像
韩伟
发布2018-03-05 15:30:21
1.2K0
发布2018-03-05 15:30:21
举报
文章被收录于专栏:韩伟的专栏韩伟的专栏

JAVA代码规范

1.规范说明

此规范包含:避免出现常见恶劣代码的禁令;指导编写合格代码的基本规则

此规范不包含:分析与设计出符合业务需求的代码;

2.基本原则

a)规范代码的原因

写程序的过程中,读代码的时间和写代码的时间只比为:10比1

软件生命周期中有80%的时间是维护

丢弃代码,对于老板来说,等于丢弃金钱

b)何时执行规范

童子军第一军规:离开营地前,让营地比你来的时候更干净。

提交代码时,让代码比你打开的时候更规范

如果不随时执行规范,规范将永远不会被执行

修改每行代码的时候,思考一下怎么写才是规范的,不要只急着完成功能

c)一号禁令

不可重复!

重复的代码带来重复的修改,漏掉处理的BUG,重复的修改会让你没日没夜的加班!如果没有重复代码,表示日后不管怎么修改,都不会被以往的代码所“拖累”,特别是另外一个人来修改这份代码的时候

写下段代码之后,回忆一下是否有别处有类似的功能,如果有就立刻抽取相同部分合并成一个新的函数,然后两个地方都调用这个新函数

d)追求表达力

像写文章一样写源代码

文章讲究用词、表达顺序,电脑确不关心源代码的可读性。如果只满足电脑的阅读性,源代码将很快连作者都看不懂

写代码除了关注如何实现功能,动手之前还要考虑一下命名和段落顺序、注释等要数,要为将来一年后重新阅读这些代码的人做好准备,很可能这个人就是你自己,或者是你的老板

e)简单就是美

尽量少的架构,尽量少的类,尽量少的函数,尽量少的源代码

为了满足复杂的需求,需要复杂的代码;但对于我们还不清楚的事情,我们才会搞的复杂。复杂并不会带来将来的简单。写代码不是攒钱,现在多做的工作往往不会减少将来的工作,反而会让你将来难以决定是否应该重新写一个

只完成最清楚的需求,尽量清晰的完成代码,功能越单一,将来可重用的机会越大

f)不可忽视警告

不可关闭IDE和编译器的警告

不可糊弄IDE和编译器的警告

确保你明白这些警告的意义,并且以推荐的方式修改代码解决

IDE和编译器的警告都是很多真正的行家所设定的,如果不了解这些行家为什么设置这些东西,你就一定会在某个地方吃亏

积极认真的对待警告,了解产生警告的原因,认真的思考如果要解决这些警告应该如何做,结果往往是一段高质量的代码,甚至是优秀的程序设计思路

3.命名

a)原则

i.超过1个字符的名字,使用英语单词,禁止使用汉语拼音,禁止使用无意义字符串,禁止使用不通用的缩写

代码是必须要被人阅读的,混杂着缩写、拼音、代号的文章就类似解谜游戏,好玩但浪费时间

虽然英语不是母语,但是用英语键盘输入英语单词,是意思表达最准确的而且效率最高的做法。

ii.禁止出现2个以上近义词

类似Manager和Driver或者Controller都是类似的含义,但如果在代码中表达不同的概念,容易混淆;如果表达相同的概率,让人厌烦,最好只用其中之一

当你难以给一个东西决定名字,而要“随便”搞一个的时候,请看下一条。

iii.优先使用业务逻辑领域词;其次使用技术领域词

一堆和你的业务领域完全无关的名字,很难让人知道这些代码是搞什么功能的,就和你用10000111100这种二进制来表达数字一样。同样如果你在使用某种明显的技术、模式、框架,而用另外一些奇怪的名字,也会让人难以了解你的实现细节,甚至误解你的实现

如果你的代码明确的为某一业务功能所写,大胆用业务功能作为名字,这是最好的选择。如果你的代码属于技术内部实现的部分,则使用你选定的技术惯用的名字,学习标准API里面的名字是个不错的做法。

b)包名(目录名)

全小写,使用URL域名组织。禁止使用不按域名倒序设定包名。

结构:公司域名.项目名.系统名.*

禁止使用纯数字作为包名的一个小节,因为JAVA规范不支持(如com.163.*就是非法的)

例子:com.netease.mail.uià网易邮箱项目的UI系统的包

在混乱的目录中难以找到文件,在不同的逻辑组织成的目录树中也难以找到文件

域名作为几乎免费可以拥有,并且可以良好组织的命名资源来说,几乎是独一无二的。全世界的资源都可以使用这个名字来管理,何况是自己的那一点代码?

c)类名(文件名)

类名必须是名词

必须是完整单词,禁止使用非通用缩写,通用缩写使用全大写,如URL,而不是Url或者url

首字母必须大写

例子:FightingSkillà战斗技能类

类表示了代码的组织,名词更容易分类和理解

使用业务领域或技术解决方案的名词作类名,可以让读者直接从名字就了解这些代码的用途。

d)方法名

方法名必须是动词或动词短语

首字母必须小写,后续单词的首字母必须大写

例子:startFighting() à开始战斗

你定义了一段代码,在做某些事,如果是一个名词,会很误解读者

使用功能作为方法名,参数作为方法名的宾语,参数名即是宾语,阅读这样的方法定义甚至完全不需要文档

e)变量名

变量名除了只有一个字符的循环技术器外,全部都必须是名词

首字母必须小写,后续单词的首字母必须大写

只有一个字符作为名字的变量,不得用作公开属性(表示位置的x,y,z除外)

例子:i,j,k à用于for循环的变量

userNameà用户名

变量代表了某些东西,这些东西需要被人通过阅读所理解,为啥不直接就叫它的名字呢?

使用业务领域或技术解决方案的名词作变量名,可以让读者直接从名字就了解这些代码的用途。ß和类名的做法是一样的

f)常量名

必须用全大写,单词间用下划线连接

例子:MAX_USER à最大用户数

常量必须和变量区分开来

4.格式

a)源文件布局

每个源文件只包含一个公共类或者接口。

公共类必须是这个文件中的第一个类或接口。

每个文件需要有以下三部分:

  • 开头注释

/*

* 类名

* 建立此文件时的版本说明(最初开发版、内测版、公测版、某个对外版本代号)

* 版权说明

*/

  • 包和引入语句

package java.awt

import java.awt.peer.CanvasPeer;

  • 类和接口声明:

i. 使用/**……*/编写“文档注释”;

ii. 类/接口的声明

iii. 类/接口实现的注释,用/*……*/编写,该注释应包含针对整个类或接口,是怎样实现的大概说明,而这些信息不适合作为文档的一部分。

iv. 类的静态变量,首先是类的公共变量,随后是保护变量,之后是包一级变量,最后是私有变量

v. 实例变量,按公共、保护、包一级、私有排列

vi. 构造器

vii. 方法,应该按功能分组排列,一个主要功能的方法后,跟着被调用的一系列方法,即自上向下展示各方法的依赖顺序。而不是杂乱的堆放。

b)垂直格式

i. 单个文件禁止超过1000行

ii. 两个方法之间只是用一个空行

iii. 方法内局部变量和方法的第一条语句之间要有一个空行

iv. 块注释或单行注释之前要有一个空行

c)水平格式

i. 每行禁止超过120个字符

ii. 是用标准的C++或者JAVA缩进格式,并且一直使用。禁止混用两种缩进格式。

iii. 是用一个制表符(TAB键)而不是空格产生一个缩进

5.注释

a)文档注释

是用标准JAVADOC语法产生文档注释。每个公共类、公共方法、公共变量必须要有中文的文档注释。

b)实现注释

i. 注释内容:编写“为什么”要写下这段代码的原因,而非“如何实现”

ii. 翻译英文:对于一些比较复杂的英文命名,必须要用注释翻译

iii. 禁止的注释:禁止出现注释掉的代码残留在代码中;禁止出现明显误导或者无用的注释。

6.属性(变量)与常量

a) 每行声明变量的数量

b) 初始化

c) 声明变量的位置

d) 禁止继承常量,使用静态属性

e) 禁止在定义语句以外写入字面值常量

在需要多国语言版本时,遍布代码的字面常量将是一场灾难。

7.方法(函数)

a) 禁止多于4个参数

b) 禁止使用“输出参数”

c) 除非必要情况,禁止返回null

d) 禁止返回“错误码”,使用“异常”来代替“错误码”

e) 禁止一个方法中多于5层的缩进

f) 禁止一个方法多于300行

g) 从容器类(Map,ArrayList,Vector,数组等)中获取对象一定要检查是否null值

8.语句

a)简单语句

每行只包括一条语句,禁止出现一行中有两个或以上的分号

b)for语句

禁止使用三个以上计数器变量。

禁止在for()语句以外修改计数器变量的内容。

计数器变量是最容易导致产生死循环的地方,for语句每次循环更新计数器变量,程序在另外一个地方修改这个变量,会让事情变得非常复杂,导致产生致命的BUG。

c)while语句

在使用可能长时间死循环的while语句时,必须在循环体中增加一句让当前线程暂停50毫秒的语句,如Thread.sleep(50);

一个死循环线程会大大占用CPU,导致CPU使用率轻易达到100%

尽量少用while循环,除非你在写多线程相关的程序,使用for循环较少出现死循环以及无穷递归

d)switch语句

每个case子句中最后一个必须要有一个break;

9.错误处理

a) 使用异常而非返回码

b) 定义常规流程,而不是把所有流程情况用if来描述,当出现常规流程外的业务逻辑流程,使用自定义异常类来跳出流程。

c) 为调用者定义异常类,异常类应该具备业务逻辑含义

d) 非业务流程问题,而是API抛出的异常,应该捕捉并且抛出不可控异常(Error类)。避免API异常类被到处抛出和捕捉。

e) 给出异常发生的环境说明,至少要打印printStackTrace()

相同的一个if判断业务逻辑,可能大量重复存在。

为了避免大量重复某种业务逻辑判断,应该使用自定义异常类,来说明这种业务逻辑上的异常。并且在最原始的操作函数处检查并且抛出这个异常。

错误应该分为两类:一类是和用户操作、数据无关的,如SQL异常、文件读写异常、网络异常,应该使用“不可控异常”,由一个统一的地方接收并且处理;另外一类是和用户操作有关的,在业务逻辑的流程中有定义,但是不属于常规流程的情况,应该定义一个以业务逻辑状态为含义的异常,由可能出异常的最原子函数抛出,并且由调用者根据业务逻辑的流程定义来处理。

10.工程目录约定

a) 统一目录结构

使用Maven目录结构,或者——

使用Eclispe标准项目目录:

工作区目录/项目名/系统名(如客户端、服务端)/

/src ß源代码目录

/binß编译后目录

/libß使用的工具库目录,包括工具库需要的配置文件

/resß源代码需要用到的其他数据文件,包括配置文件

/docß文档目录

b) 统一开发工具以及设定参数

i. 统一使用一个版本的开发工具

ii. 统一开发工具的所有设定,包括安装目录、库设定等参数(除字体、工具栏等表现部分)

c) 对整个工作区作版本管理

i. 统一工作区目录路径位置

ii. 对整个工作区目录使用SVN,作为源代码部分的版本管理,但剔除bin目录

11.代码外三要素:

a)文档编写

严格按照注释要求编写javadoc类型文档注释。并且每次发布版本都自动更新文档。

如果懒得写文档,或者想少写注释,尽量少用公共类和公开方法、变量。简化代码结构能同时减轻文档的工作量

对于超过一周以上的开发项目,画UML的类结构图。

对于参与者超过三个的流程,画UML的流程图。

对于每个数据表,都必须要有数据字典文档。每次修改数据表结构都必须更新此文档。

你可以使用数据库管理工具,在建立表的时候就一并做好这个工作。

每一种自定义资源文件,如XML或者美术资源文件,都需要最少一个文档介绍其结构。

以上所有文档应该跟随源代码一起在SVN上管理。

b)版本管理

  • 源代码使用一个单独的SVN库,设置三类分支管理
    • branch类分支:开发中的多个分支,进入QA测试前合并至trunk分支;开发新功能时从trunk分支建立出来。
    • trunk分支:一个单一的分支,用来存放当前正在QA人员测试的源代码,通常是下一个即将发布的版本。所有的其他分支都是从这个分支建立出来的。
    • tag分支:多个已经发布版本的分支。每次发布版本就建立一个此类分支用于备份源代码状态。便于将来回溯版本。
  • 发布文件使用一个单独的SVN库管理
  • 部署安装脚本以及配置文件和发布文件使用SVN管理
    • 包括每个安装环境的不同配置文件
    • 包括多个安装环境公有的文件

c)自动构建

从源代码变成发布文件,并且安装部署到即使是空白的目标环境上,必须使用自动构建程序。可以是make或者ant系统,又或者是自己额外写的脚本。

自动构建程序必须可以仅用一个步骤就自动运行完成。并且写下构建日志以提供分析问题的依据。

感谢大家的阅读,如觉得此文对你有那么一丁点的作用,麻烦动动手指转发或分享至朋友圈。如有不同意见,欢迎后台留言探讨。

本文参与 腾讯云自媒体分享计划,分享自微信公众号。
原始发表:2015-12-28,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 韩大 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • JAVA代码规范
相关产品与服务
容器服务
腾讯云容器服务(Tencent Kubernetes Engine, TKE)基于原生 kubernetes 提供以容器为核心的、高度可扩展的高性能容器管理服务,覆盖 Serverless、边缘计算、分布式云等多种业务部署场景,业内首创单个集群兼容多种计算节点的容器资源管理模式。同时产品作为云原生 Finops 领先布道者,主导开源项目Crane,全面助力客户实现资源优化、成本控制。
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档