代码规范_JAVA_编程开发_程序员俱乐部

中国优秀的程序员网站程序员频道CXYCLUB技术地图
热搜:
更多>>
 
您所在的位置: 程序员俱乐部 > 编程开发 > JAVA > 代码规范

代码规范

 2014/11/22 12:22:56  伊苏  程序员俱乐部  我要评论(0)
  • 摘要:代码规范这个词困扰了我多年要统一代码规范,我目前还没见过成功的例子,各个公司,各种语言,甚至每个人都有自己的风格,没有形成网格的也有习惯,用别人的总是不那么顺手常见的代码规范:类的命名首字母大写,然后驼峰命名函数取名,第一个词小写,动词开头之类的这2点还算厚道然后内部变量来了以前学习C语言的喜欢_a_i,lcName,lcCount,之类{}C#的if(){}java的if(){}运算符前后加个空格i=1;i=1;for(inti=0;i<len;i++)for(inti=0;i<
  • 标签:代码 代码规范
代码规范
这个词困扰了我多年
要统一代码规范, 我目前还没见过成功的例子,
各个公司, 各种语言, 甚至每个人都有自己的风格, 没有形成网格的也有习惯, 用别人的总是不那么顺手

常见的代码规范:
类的命名首字母大写, 然后驼峰命名
函数取名, 第一个词小写, 动词开头之类的
这2点还算厚道

然后
内部变量来了
以前学习C语言的喜欢 _a _i, lcName, lcCount, 之类

{}
C#的
if()
{
}

java的
if(){
}

运算符前后加个空格
i=1;
i = 1;

for(int i=0;i<len;i++)
for(int i=0; i<len; i++)


bool变量 一定要isExist, 之类的

大部代码规范文档都是这么要求的, 当然也是有它的道理和作用, 但执行起来很困难, 几乎全靠程序员自觉, 但这个人性, 你懂的,  要靠term leader吗? term leader也没那个功夫天天看, 行行看, 抽查的意义不大

而且这让很多编码人员很烦躁, 潜意识里被束缚着
所以, 多年来我一直没有去理会过代码规范这事

最近, 突然间有点觉悟, 是在写注释, 文档, 看代码时的一种突然间的顿悟
我不需要也不想读这么多代码,
80%的情况下, 我希望读少量注释或代码就能知道个大概就行
20%的情况下, 我希望针对小段代码深度分析
甚至有时候, 我希望针对一个方法, 直接进行替换而不是修改

为什么这么多年来都发现呢,
国内的编码环境, 追求快速编码, 快速实现功能
无视需求分析, 无视系统设计, 更别说写注释, 文档了
由程序员什么都没搞清就开始敲代码, 做设计, 那个不叫需求分析和系统设计

好了, 具体的代码规范: 不应该着眼于代码的命名, 变量的首字母之类的细枝末节
而是应该体现在思路上, 算法, 数构结构上, 让代码容易读起来
或者说几行重点代码就能知道个大概了

让人在读代码的时候, 很清淅的知道你在干什么, 或者是你想干什么
典型的场景1: 自己读自己以前的代码的时候, 由于是自己写的, 代码是看懂了, 但却不知道为什么要这么写, 一改, 结果bug出来了

典型的场景2: 自己读自己以前的代码, 搞不清楚类级别的变量是干什么用的, 前后跨几屏的翻代码, 穿插几个函数终于弄清该变量是干什么的了, 然后大骂, 虽然那是你自己亲手造成的

典型的场景3: 自己写的一个类, 要跑单元测试了, 要么就是数据库错误, 要么就是提示缺少组件, 要么就是null异常, 前后翻几个类几个包, 把mysql跑起来, 把tomcat跑起来, 然后才能把这段代码跑起来, 其实我只是想测刚才修改了报表里的一个字段是否正确而已...


以下是我个人整理的代码规范

一 注释
1.类的注释
每个类都要有注释说明, 包括: 这个类的标题, 这个类是干什么用的, 结合使用场景的说, 这个类的使用有什么特殊情况, 这个类的调用说明

2.函数的注释
所有公共函数都强制需要注释, 这个方法是干什么用的, 结合使用场景的说, 这个类的使用有什么特殊情况, 调用方法说明, 每个参数, 能给个例子就给个例子, 如param path, 别人调用时传个"d:/abc/"出错了半天, 才发现原来是要这么传"d:/abc", 你还在那振振有词的说, 你的入参不合法

3.域级变量的注释
所有域级变量都强制需要注释, 这个变量是干什么用的, 结合使用场景的说, 这个变量的使用有什么特殊情况

4.数据结构的注释
重要的数据结构前添加注释, 样例

//转算为M M=1024byte*1024Kb
double d1=result[1]/((double)1024*1024);
//转算为G G=1024byte*1024Kb*1024Mb
double d2=(double)result[1]/(1024*1024*1024);

针对d1, d2, 与其在命名写 sizeOfMb, sizeOfGb, 还不如直接标个注释更清晰

5.注释越多越好
曾经在合资企业呆过一阵子, 用英文写过注释, 自己看起来还可以,
但问题是: 你能保证你的英文不写错, 却不能保证别人的英文不读错, 这里还有语言背景问题, 所以, 作为中国人, 还是别装B了, 有条件的话, 老老实实母语吧, 这样才能有最详细最有质量的备注,


二 类的设计
1. 类的定义
这个类是干什么的, 要在设计是就定义好, 要杜绝客串其他功能, 经常有"临时"需要添加的方法, 几个临时下来, 这个类的就偏离它的定义了, 事后你老人家一不小心想不起来, 那坑的就是自己, 你老人家拍拍屁股一走, 坑的就是接手的人, 对于"临时"函数, 要在类的注释里详细说明这个临时的缘由, 以及事后找时间重构(有条件的话)
2. 函数的定义
慎重使用公共方法, 每个公共函数都要有清淅的理由, 可public又可private的, 一律private, public是公开给外人使用的, 没事就别给别人找麻烦了, 再说了, 那个别人, 多半是你自己
3. 上下文
类和函数的上下文清淅, 要做到这点, 会付出一点代价: 性能浪费在上下文转化
但在95%的情况, 可以方便的整块替换函数比追求函数的运算效率更有意义

三 资源的生命周期
1. 资源的规划
规划好资源是内部生成还是依赖外面, 如connection, inputstream之类的, 内部资源要自己释放, 参见下面的 "2. 内部资源的释放" 和 "3. 外面资源的使用"

2. 内部资源的释放
在自己类里面生成的资源, 要自己释放, 系统后期大部分null, permSpace out of memory就是这么产生的, 虽说java有回收机制, 但你也不能完全靠它, 用完后写个obj=null相当于买一份保险, 例子: 对于foutinputstream fout之类的, 用完后一定要写个fout.close();而fout=null;则是建议写

3. 外面资源的使用
来自外面的资源, 用完就还, 别多手
典型案例:
class="java" name="code">
public int setItem(conneciton, con, String sql, String[] param){
	int flag=0;
	try{
		...
	}catch(exception ex){
		...
	}finally{
		//这里手一抖, 把con关掉了, 调用者就悲剧了
		con.close();
		con=null;
	}
	return flag;
}


可以看见, 代码规范其实保是系统设计(类设计)的衍生物, 有一个良好的系统设计(类设计), 才能用良好的代码规范


综合例子
package zkhelper;

import java.io.File;
import java.util.LinkedList;
import java.util.List;

public class FileCounter {

	long current;
	long total;
	
	List<IprocessAction> listener=new LinkedList<IprocessAction>();
	
	public void checkFile(String name, File file) throws Exception{
		try {
			//long[] result=checkFileCnt(new File("d:/hyt/test60w"));
			System.out.println("正在计算文件夹...");
			long count_dir=checkFileCount(file);
			total=count_dir;
			current=0;
			System.out.println("开始计算文件数量和容量...");
			long[] result=checkFileSize1(file);
			//转算为M M=1024byte*1024Kb
			double d1=result[1]/((double)1024*1024);
			//转算为G G=1024byte*1024Kb*1024Mb
			double d2=(double)result[1]/(1024*1024*1024);
			System.out.println(name);
			System.out.println(String.format("容量: %.3f M", d1));
			System.out.println(String.format("容量: %.3f G", d2));
			System.out.println("文件数量:"+result[0]);
			System.out.println(String.format("容量: %.3fG, 数量: %d", d2, result[0]));
		} catch (Exception e) {
			e.printStackTrace();
		}
	}
	
	public static long checkFileCount(File file) throws Exception {
		if(null==file)
			throw new Exception(String.format("指定目录为null"));
		if(!file.isDirectory())
			throw new Exception(String.format("指定目录(%s)无效", file.getPath()));
		
		long count=0;
		File[] ff=file.listFiles();
		for(File f : ff){
			String name=f.getName().toLowerCase();
			if(f.isDirectory()){
				System.out.println(name);
				count++;
				long n=checkFileCount(f);
				count+=n;
			}
		}
//		System.out.println("file: "+file.getName());
//		System.out.println(String.format("total file cnt: %d", cnt));
//		System.out.println(String.format("total size: %d", amount));
		return count;
	}
	
	public static long[] checkFileSize(File file) throws Exception {
		if(null==file)
			throw new Exception(String.format("指定目录为null"));
		if(!file.isDirectory())
			throw new Exception(String.format("指定目录(%s)无效", file.getPath()));
		
		File[] ff=file.listFiles();
		long count=0;
		long size=0;
		for(File f : ff){
			String name=f.getName().toLowerCase();
			if(f.isDirectory()){
				long[] tmp=checkFileSize(f);
				count+=tmp[0];
				size+=tmp[1];
			}else if(f.isFile()){
				boolean flag=false;
				if(name.lastIndexOf(".jpg")>=0 || name.lastIndexOf(".gif")>=0 || name.lastIndexOf(".tif")>=0)
					flag=true;
				if(!flag)
					continue;
				count++;
				long d=f.length();
				size+=d;
			}
		}
//		System.out.println("file: "+file.getName());
//		System.out.println(String.format("total file cnt: %d", cnt));
//		System.out.println(String.format("total size: %d", amount));
		long[] result={count, size};
		return result;
	}
	
	public long[] checkFileSize1(File file) throws Exception {
		if(null==file)
			throw new Exception(String.format("指定目录为null"));
		if(!file.isDirectory())
			throw new Exception(String.format("指定目录(%s)无效", file.getPath()));
		
		File[] ff=file.listFiles();
		long count=0;
		long size=0;
		for(File f : ff){
			String name=f.getName().toLowerCase();
			if(f.isDirectory()){
				current++;
				String[] param={String.valueOf(current), String.valueOf(total), name};
				notify(param);
				long[] tmp=checkFileSize1(f);
				count+=tmp[0];
				size+=tmp[1];
			}else if(f.isFile()){
				boolean flag=false;
				if(name.lastIndexOf(".jpg")>=0 || name.lastIndexOf(".gif")>=0 || name.lastIndexOf(".tif")>=0)
					flag=true;
				if(!flag)
					continue;
				count++;
				long d=f.length();
				size+=d;
			}
		}
//		System.out.println("file: "+file.getName());
//		System.out.println(String.format("total file cnt: %d", cnt));
//		System.out.println(String.format("total size: %d", amount));
		long[] result={count, size};
		return result;
	}
	
	public void notify(String[] param){
		for(IprocessAction e : listener){
			e.actionPerom(param);
		}
	}
	
	public void addEvent(IprocessAction e){
		listener.add(e);
	}
	
	public void removeEvent(IprocessAction e){
		listener.remove(e);
	}
	
	/**
	 * @param args the command line arguments
	 */
	public static void main(String[] args) throws Exception {
		String name="网球图片";
		File file=new File("E:\\picture\\[20120102]莲花二村");
		FileCounter fc=new FileCounter();
		fc.addEvent(new IprocessAction() {

			@Override
			public void actionPerom(String[] param) {
				double n=100*new Double(param[0])/new Integer(param[1]);
				System.out.println(String.format("current: %s, total: %s, process: %.0f%%, name: %s", param[0], param[1], n, param[2]));
			}
		});
		fc.checkFile(name, file);
	}
	
	interface IprocessAction {
		
		/**
		 * 进度事件
		 * @param param {current, total, desc}
		 */
		public void actionPerom(String[] param);
	}
}


FileCounter这个类是我去年写的, 我只依稀记得这个类是计算文件数量和容量的, 如今我要使用这个类了, 看着这个类的导航,



我面临以下问题

1.有动态函数和静态函数, 我要怎么使用呢, 这涉及到是否new FileCounter的问题, 这需要我去读代码
2.checkFileSize和checkFileSize1是怎么回事
3.checkFile, checkFileCount, checkFileSize, 看起来第一个函数包括了第2,3个函数的作用, 但我不敢肯定, 这需要我看一下checkFile的代码
4.公共域current和long是干什么用的

------------------------------------------------------------

这是添加注释之后的代码
package zkhelper;

import java.io.File;
import java.util.LinkedList;
import java.util.List;

/**
 * 检查子图数量和容量的工具类<br />
 * <br />
 * 调用方法:<br />
 * 1.FileCounter fc=new FileCounter()<br />
 * 2.fc.addEvent(IprocessAction); 注册进度事件<br />
 * 3.checkFile(name, file); 开始运算<br />
 * 科目, 子图容量, 子图数量会显示在控制台<br />
 * @author lizw
 */
public class FileCounter1 {

//	long current;
//	long total;
	
	List<IprocessAction> listener=new LinkedList<IprocessAction>();
	
	/**
	 * 在控制台打印科目子图容量和数量
	 * @param name 科目别名
	 * @param file 科目子图路径, 如//192.168.1.200/d$/2014yczk/YCZK/jykm/jy_dl/jpg/Current/Image
	 * @throws Exception 
	 */
	public void checkFile(String name, File file) throws Exception{
		try {
			//long[] result=checkFileCnt(new File("d:/hyt/test60w"));
			System.out.println("正在计算文件夹...");
			long count_dir=checkFileCount(file);
			long total=count_dir;
			long current=0;
			System.out.println("开始计算文件数量和容量...");
			long[] result=checkFileSize1(file);
			//转算为M M=1024byte*1024Kb
			double d1=result[1]/((double)1024*1024);
			//转算为G G=1024byte*1024Kb*1024Mb
			double d2=(double)result[1]/(1024*1024*1024);
			System.out.println(name);
			System.out.println(String.format("容量: %.3f M", d1));
			System.out.println(String.format("容量: %.3f G", d2));
			System.out.println("文件数量:"+result[0]);
			System.out.println(String.format("容量: %.3fG, 数量: %d", d2, result[0]));
		} catch (Exception e) {
			e.printStackTrace();
		}
	}
	
	/**
	 * 计算目录数量, 为统计子图数量的进度提供总数
	 * @param file
	 * @return
	 * @throws Exception 
	 */
	public static long checkFileCount(File file) throws Exception {
		if(null==file)
			throw new Exception(String.format("指定目录为null"));
		if(!file.isDirectory())
			throw new Exception(String.format("指定目录(%s)无效", file.getPath()));
		
		long count=0;
		File[] ff=file.listFiles();
		for(File f : ff){
			String name=f.getName().toLowerCase();
			if(f.isDirectory()){
				System.out.println(name);
				count++;
				long n=checkFileCount(f);
				count+=n;
			}
		}
//		System.out.println("file: "+file.getName());
//		System.out.println(String.format("total file cnt: %d", cnt));
//		System.out.println(String.format("total size: %d", amount));
		return count;
	}
	
	/**
	 * 计算图像的数和大小<br />
	 * 图像大小返回的是byte单位, 默认只统计(jpg, gif, tif)<br />
	 * 使用了递归算法
	 * @param file 科目子图路径, 如//192.168.1.200/d$/2014yczk/YCZK/jykm/jy_dl/jpg/Current/Image
	 * @return {count, size}
	 * @throws Exception 
	 */
	public static long[] checkFileSize(File file) throws Exception {
		if(null==file)
			throw new Exception(String.format("指定目录为null"));
		if(!file.isDirectory())
			throw new Exception(String.format("指定目录(%s)无效", file.getPath()));
		
		File[] ff=file.listFiles();
		long count=0;
		long size=0;
		for(File f : ff){
			String name=f.getName().toLowerCase();
			if(f.isDirectory()){
				long[] tmp=checkFileSize(f);
				count+=tmp[0];
				size+=tmp[1];
			}else if(f.isFile()){
				boolean flag=false;
				if(name.lastIndexOf(".jpg")>=0 || name.lastIndexOf(".gif")>=0 || name.lastIndexOf(".tif")>=0)
					flag=true;
				if(!flag)
					continue;
				count++;
				long d=f.length();
				size+=d;
			}
		}
//		System.out.println("file: "+file.getName());
//		System.out.println(String.format("total file cnt: %d", cnt));
//		System.out.println(String.format("total size: %d", amount));
		long[] result={count, size};
		return result;
	}
	
	/**
	 * 把checkFileSize由动态转成静态函数, 这里暂时保留备用
	 * @param file
	 * @return
	 * @throws Exception 
	 */
	public long[] checkFileSize1(File file) throws Exception {
		if(null==file)
			throw new Exception(String.format("指定目录为null"));
		if(!file.isDirectory())
			throw new Exception(String.format("指定目录(%s)无效", file.getPath()));
		
		File[] ff=file.listFiles();
		long count=0;
		long size=0;
		long total=0;
		int current=0;
		for(File f : ff){
			String name=f.getName().toLowerCase();
			if(f.isDirectory()){
				current++;
				String[] param={String.valueOf(current), String.valueOf(total), name};
				notify(param);
				long[] tmp=checkFileSize1(f);
				count+=tmp[0];
				size+=tmp[1];
			}else if(f.isFile()){
				boolean flag=false;
				if(name.lastIndexOf(".jpg")>=0 || name.lastIndexOf(".gif")>=0 || name.lastIndexOf(".tif")>=0)
					flag=true;
				if(!flag)
					continue;
				count++;
				long d=f.length();
				size+=d;
			}
		}
//		System.out.println("file: "+file.getName());
//		System.out.println(String.format("total file cnt: %d", cnt));
//		System.out.println(String.format("total size: %d", amount));
		long[] result={count, size};
		return result;
	}
	
	public void notify(String[] param){
		for(IprocessAction e : listener){
			e.actionPerom(param);
		}
	}
	
	public void addEvent(IprocessAction e){
		listener.add(e);
	}
	
	public void removeEvent(IprocessAction e){
		listener.remove(e);
	}
	
	/**
	 * @param args the command line arguments
	 */
	public static void main(String[] args) throws Exception {
		String name="结业地理";
		File file=new File("E:\\picture\\[20120102]莲花二村");
		FileCounter1 fc=new FileCounter1();
		fc.addEvent(new IprocessAction() {

			@Override
			public void actionPerom(String[] param) {
				double n=100*new Double(param[0])/new Integer(param[1]);
				System.out.println(String.format("current: %s, total: %s, process: %.0f%%, name: %s", param[0], param[1], n, param[2]));
			}
		});
		fc.checkFile(name, file);
	}
	
	interface IprocessAction {
		
		/**
		 * 进度事件
		 * @param param {current, total, desc}
		 */
		public void actionPerom(String[] param);
	}
}



缩略版
/**
 * 检查子图数量和容量的工具类<br />
 * <br />
 * 调用方法:<br />
 * 1.FileCounter fc=new FileCounter()<br />
 * 2.fc.addEvent(IprocessAction); 注册进度事件<br />
 * 3.checkFile(name, file); 开始运算<br />
 * 科目, 子图容量, 子图数量会显示在控制台<br />
 * @author lizw
 */
public class FileCounter1 {
	/**
	 * 在控制台打印科目子图容量和数量
	 * @param name 科目别名
	 * @param file 科目子图路径, 如//192.168.1.200/d$/2014yczk/YCZK/jykm/jy_dl/jpg/Current/Image
	 * @throws Exception 
	 */
	public void checkFile(String name, File file)

	/**
	 * 计算目录数量, 为统计子图数量的进度提供总数
	 * @param file
	 * @return
	 * @throws Exception 
	 */
	public static long checkFileCount(File file)

	/**
	 * 计算图像的数和大小<br />
	 * 图像大小返回的是byte单位, 默认只统计(jpg, gif, tif)<br />
	 * 使用了递归算法
	 * @param file 科目子图路径, 如//192.168.1.200/d$/2014yczk/YCZK/jykm/jy_dl/jpg/Current/Image
	 * @return {count, size}
	 * @throws Exception 
	 */
	public static long[] checkFileSize(File file)

	/**
	 * 把checkFileSize由动态转成静态函数, 这里暂时保留备用
	 * @param file
	 * @return
	 * @throws Exception 
	 */
	public long[] checkFileSize1(File file)
}



面对这份代码, 我的问题就完全解决了, 而且不需要读代码, 除了注释里的代码

对比:

1.有动态函数和静态函数, 我要怎么使用呢, 这涉及到是否new FileCounter的问题, 这需要我去读代码
2.checkFileSize和checkFileSize1是怎么回事
3.checkFile, checkFileCount, checkFileSize, 看起来第一个函数包括了第2,3个函数的作用, 第2个看起来是计算文件数量, 第3个看起来是计算文件容量, 但我不敢肯定, 这需要我看一下checkFile的代码
4.公共域current和long是干什么用的

重构注释后

1.从类的说明看到, 直接用动态方法, 还额外知道了, 有进度功能, 实现接口即可实现进度监控, 差点又跑去写一段进度监控代码, 原来一年前我已经想到计算时间太长的卡顿问题
2.checkFIleSize1是备用的, 由动态类转静态类遗留下来的
3.由于第1点的关系, 我已经知道了直接调用checkFile即可, 而且上面注释已经告诉我, fileCount是计算文件夹目录而不是计算文件数量, fileFileSize是计算文件数量和容易, 而不是只是容量, 这里不需要再深入了, 只有出现bug时, 我才需要深入
4.是不需要的, 去掉了, 不存在这问题了

额外的
看着checkFileCount上面的"计算目录数量, 为统计子图数量的进度提供总数", 我不用看代码就回忆起来了, 进度的显示是按目录的进度, 而不是真实的文件数量的进度

  • 大小: 21.6 KB
  • 查看图片附件
发表评论
用户名: 匿名