非规范汉字字符编码最普遍检查是什么意思

教育改变生活,知识改变命运
java中编码与解码分别指什么? 如何向非技术人员解释 Unicode 是什么?
java中编码与解码分别指什么?
如何向非技术人员解释 Unicode 是什么?
一部国际标准,主要是为计算机中用到的所有字符分配各自的通用代号。
就像给地球上每个人都发一张全球通用的身份证,而非让人们持有世界各地五花八门、互不兼容的身份证件。
为什么需要编码
计算机只认0和1,0和1可以组成无穷的数字现实世界中很多字符需要在计算机中表示(英语的[a-zA-Z] 中文的汉字,还有各种标点)使用编码,可以把现实世界中的字符映射成计算机能表示的数字上面去什么是ASCII
一种把英文字符和一些符号编码到数字上的编码方法比如说,把a编码成1,把b编码成2,。。。把Z编码成52.但ASCII码,只规定了128个数字。也就是说它只能编码128个字符。中文肯定不能编码在上面了,需要新的编码方法什么是UNICODE
一种把现实世界中所有的字符和标点都编码到数字上的方法比如说,把中编码成1,把国编码成2,。。。把a编码成10002,等等。当然,具体把哪个字符编码到哪个数字上,不能随你所定,这个已经被国际标准给规定好了,这样全球的用户可以使用同样的编码方式来无误的使用它们。
问题一:在java中读取文件时应该采用什么编码?Java读取文件的方式总体可以分为两类:按字节读取和按字符读取。按字节读取就是采用InputStream.read()方法来读取字节,然后保存到一个byte[]数组中,最后经常用new String(byte[]);把字节数组转换成String。在最后一步隐藏了一个编码的细节,new String(byte[]);会使用默认的字符集来解码字节数组,中文就是GBK。而我们从输入流里读取的字节很可能就不是GBK编码的,因为从输入流里读取的字节编码取决于被读取的文件自身的编码。举个例子:我们在D:盘新建一个名为demo.txt的文件,写入”我们。”,并保存。此时demo.txt编码是ANSI,中文下就是GBK。此时我们用输入字节流读取该文件所得到的字节就是使用GBK方式编码的字节。那么我们最终new String(byte[]);时采用平台默认的GBK来编码成String也是没有问题的(字节编码和默认解码一致)。试想一下,如果在保存demo.txt文件时,我们选择UTF-8编码,那么该文件的编码就不在是ANSI了,而变成了UTF-8。仍然采用输入字节流来读取,那么此时读取的字节和上一次就不一样了,这次的字节是UTF-8编码的字节。两次的字节显然不一样,一个很明显的区别就是:GBK每个汉字两个字节,而UTF-8每个汉字三个字节。如何我们最后还使用new String(byte[]);来构造String对象,则会出现乱码,原因很简单,因为构造时采用的默认解码GBK,而我们的字节是UTF-8字节。正确的办法就是使用new String(byte[],”UTF-8”);来构造String对象。此时我们的字节编码和构造使用的解码是一致的,不会出现乱码问题了。说完字节输入流,再来说说字节输出流。我们知道如果采用字节输出流把字节输出到某个文件,我们是无法指定生成文件的编码的(假设文件以前不存在),那么生成的文件是什么编码的呢?经过测试发现,其实这取决于写入的字节编码格式。比如以下代码:OutputStream out = new FileOutputStream("d:\\demo.txt");out.write("我们".getBytes());getBytes()会采用操作系统默认的字符集来编码字节,这里就是GBK,所以我们写入demo.txt文件的是GBK编码的字节。那么这个文件的编码就是GBK。如果稍微修改一下程序:out.write("我们".getBytes(“UTF-8”));此时我们写入的字节就是UTF-8的,那么demo.txt文件编码就是UTF-8。这里还有一点,如果把”我们”换成123或abc之类的ascii码字符,那么无论是采用getBytes()或者getBytes(“UTF-8”)那么生成的文件都将是GBK编码的。这里可以总结一下,InputStream中的字节编码取决文件本身的编码,而OutputStream生成文件的编码取决于字节的编码。下面说说采用字符输入流来读取文件。首先,我们需要理解一下字符流。其实字符流可以看做是一种包装流,它的底层还是采用字节流来读取字节,然后它使用指定的编码方式将读取字节解码为字符。说起字符流,不得不提的就是InputStreamReader。以下是java api对它的说明: InputStreamReader是字节流通向字符流的桥梁:它使用指定的charset 读取字节并将其解码为字符。它使用的字符集可以由名称指定或显式给定,否则可能接受平台默认的字符集。说到这里其实很明白了,InputStreamReader在底层还是采用字节流来读取字节,读取字节后它需要一个编码格式来解码读取的字节,如果我们在构造InputStreamReader没有传入编码方式,那么会采用操作系统默认的GBK来解码读取的字节。还用上面demo.txt的例子,假设demo.txt编码方式为GBK,我们使用如下代码来读取文件:InputStreamReader
in = new InputStreamReader(new FileInputStream(“demo.txt”));那么我们读取不会产生乱码,因为文件采用GBK编码,所以读出的字节也是GBK编码的,而InputStreamReader默认采用解码也是GBK。如果把demo.txt编码方式换成UTF-8,那么我们采用这种方式读取就会产生乱码。这是因为字节编码(UTF-8)和我们的解码编码(GBK)造成的。解决办法如下:InputStreamReader
in = new InputStreamReader(new FileInputStream(“demo.txt”),”UTF-8”);给InputStreamReader指定解码编码,这样二者统一就不会出现乱码了。下面说说字符输出流。字符输出流的原理和字符输入流的原理一样,也可以看做是包装流,其底层还是采用字节输出流来写文件。只是字符输出流根据指定的编码将字符转换为字节的。字符输出流的主要类是:OutputStreamWriter。Java api解释如下:OutputStreamWriter 是字符流通向字节流的桥梁:使用指定的 charset 将要向其写入的字符编码为字节。它使用的字符集可以由名称指定或显式给定,否则可能接受平台默认的字符集。说的很明白了,它需要一个编码将写入的字符转换为字节,如果没有指定则采用GBK编码,那么输出的字节都将是GBK编码,生成的文件也是GBK编码的。如果采用以下方式构造OutputStreamWriter:OutputStreamWriter out = new OutputStreamWriter(new FileOutputStream(“dd.txt”),”UTF-8”);那么写入的字符将被编码为UTF-8的字节,生成的文件也将是UTF-8格式的。问题二: 既然读文件要使用和文件编码一致的编码,那么javac编译文件也需要读取文件,它使用什么编码呢?
这个问题从来就没想过,也从没当做是什么问题。正是因为问题一而引发的思考,其实这里还是有东西可以挖掘的。下面分三种情况来探讨,这三种情况也是我们常用的编译java源文件的方法。
1.javac在控制台编译java类文件。
通常我们手动建立一个java文件Demo.java,并保存。此时Demo.java文件的编码为ANSI,中文操作系统下就是GBK.然后使用javac命令来编译该源文件。”javac Demo.java”。Javac也需要读取java文件,那么javac是使用什么编码来解码我们读取的字节呢?其实javac采用了操作系统默认的GBK我们读取的字节,这个编码正好也是Demo.java文件的编码,二者一致,所以不会出现乱码情况。让我们来做点手脚,在保存Demo.java文件时,我们选择UTF-8保存。此时Demo.java文件编码就是UTF-8了。我们再使用”javac Demo.java”来编译,如果Demo.java里含有中文字符,此时控制台会出现警告信息,也出现了乱码。究其原因,就是因为javac采用了GBK我们读取的字节。因为我们的字节是UTF-8编码的,所以会出现乱码。如果不信的话你可以自己试试。那么解决办法呢?解决办法就是使用javac的encoding参数来制定我们的解码编码。如下:javac -encoding UTF-8 Demo.java。这里我们指定了使用UTF-8来解码读取的字节,由于这个编码和Demo.java文件编码一致,所以不会出现乱码情况了。
2.Eclipse中编译java文件。
我习惯把Eclipse的编码设置成UTF-8。那么每个项目中的java源文件的编码就是UTF-8。这样编译也从没有问题,也没有出现过乱码。正是因为这样才掩盖了使用javac可能出现的乱码。那么Eclipse是如何正确编译文件编码为UTF-8的java源文件的呢?唯一的解释就是Eclipse自动识别了我们java源文件的文件编码,然后采取了正确的encoding参数来编译我们的java源文件。功劳都归功于IDE的强大了。
3.使用Ant来编译java文件。
Ant也是我常用的编译java文件的工具。首先,必须知道Ant在后台其实也是采用javac来编译java源文件的,那么可想而知,1会出现的问题在Ant中也会存在。如果我们使用Ant来编译UTF-8编码的java源文件,并且不指定如何编码,那么也会出现乱码的情况。所以Ant的编译命令&javac&有一个属性” encoding”允许我们指定编码,如果我们要编译源文件编码为UTF-8的java文件,那么我们的命令应该如下:
&javac destdir="${classes}" target="1.4" source="1.4" deprecation="off" debug="on" debuglevel="lines,vars,source" optimize="off" encoding="UTF-8"&
指定了编码也就相当于”javac –encoding”了,所以不会出现乱码了。问题三:tomcat中编译jsp的情况。
这个话题也是由问题二引出的。既然javac编译java源文件需要采用正确的编码,那么tomcat编译jsp时也要读取文件,此时tomcat采用什么编码来读取文件?会出现乱码情况吗?下面我们来分析。
我们通常会在jsp开头写上如下代码:&%@ page language="java" contentType="text/ charset=utf-8" pageEncoding="utf-8"%&我常常不写pageEncoding这个属于,也不明白它的作用,但是不写也没出现过乱码情况。其实这个属性就是告诉tomcat采用什么编码来读取jsp文件的。它应该和jsp文件本身的编码一致。比如我们新建个jsp文件,设置文件编码为GBK,那么此时我们的pageEncoding应该设置为GBK,这样我们写入文件的字符就是GBK编码的,tomcat读取文件时采用也是GBK编码,所以能保证正确的解码读取的字节。不会出现乱码。如果把pageEncoding设置为UTF-8,那么读取jsp文件过程中转码就出现了乱码。上面说我常常不写pageEncoding这个属性,但是也没出现过乱码,这是怎么回事呢?那是因为如果没有pageEncoding属性,tomcat会采用contentType中charset编码来读取jsp文件,我的jsp文件编码通常设置为UTF-8,contentType的charset也设置为UTF-8,这样tomcat使用UTF-8编码来解码读取的jsp文件,二者编码一致也不会出现乱码。这只是contentType中charset的一个作用,它还有两个作用,后面再说。可能有人会问:如果我既不设置pageEncoding属性,也不设置contentType的charset属性,那么tomcat会采取什么编码来解码读取的jsp文件呢?答案是iso-8859-1,这是tomcat读取文件采用的默认编码,如果用这种编码来读取文件显然会出现乱码。
问题四:输出。问题二和问题三分析的过程其实就是从源文件à过程中的转码情况。最终的都是以unicode编码的,我们前面所做的工作就是把各种不同的编码转换为unicode编码,比如从GBK转换为unicode,从UTF-8转换为unicode。因为只有采用正确的编码来转码才能保证不出现乱码。Jvm在运行时其内部都是采用unicode编码的,其实在输出时,又会做一次编码的转换。让我们分两种情况来讨论。1.java中采用Sysout.out.println输出。比如:Sysout.out.println(“我们”)。经过正确的解码后”我们”是unicode保存在内存中的,但是在向标准输出(控制台)输出时,jvm又做了一次转码,它会采用操作系统默认编码(中文操作系统是GBK),将内存中的unicode编码转换为GBK编码,然后输出到控制台。因为我们操作系统是中文系统,所以往终端显示设备上打印字符时使用的也是GBK编码。因为终端的编码无法手动改变,所以这个过程对我们来说是透明的,只要编译时能正确转码,最终的输出都将是正确的,不会出现乱码。在Eclipse中可以设置控制台的字符编码,具体位置在Run Configuration对话框的Common标签里,我们可以试着设置为UTF-8,此时的输出就是乱码了。因为输出时是采用GBK编码的,而显示却是使用UTF-8,编码不同,所以出现乱码。2.jsp中使用out.println()输出到客户端浏览器。Jsp编译成class后,如果输出到客户端,也有个转码的过程。Java会采用操作系统默认的编码来转码,那么tomcat采用什么编码来转码呢?其实tomcat是根据&%@ page language="java" contentType="text/ charset=utf-8" pageEncoding="utf-8"%&中contentType的charset参数来转码的,contentType用来设置tomcat往浏览器发送HTML内容所使用的编码。Tomcat根据这个编码来转码内存中的unicode。经过转码后tomcat输出到客户端的字符编码就是utf-8了。那么浏览器怎么知道采取什么编码格式来显示接收到的内容呢?这就是contentType的charset属性的第三个作用了:这个编码会在HTTP响应头中指定以通知浏览器。浏览器使用http响应头的contentType的charset属性来显示接收到的内容。总结一下contentType charset的三个作用:1).在没有pageEncoding属性时,tomcat使用它来解码读取的jsp文件。2).tomcat向客户端输出时,使用它来编码发送的内容。3).通知浏览器,应该以什么编码来显示接收到的内容。为了能更好的理解上面所说的解码和转码过程,我们举一个例子。新建一个index.jsp文件,该文件编码为GBK,在jsp开头我们写上如下代码:&%@ page language="java" contentType="text/ charset=utf-8" pageEncoding="GBK"%&这里的charset和pageEncoding不同,但是也不会出现乱码,我来解释一下。首先tomcat读取jsp内容,并根据pageEncoding指定的GBK编码将读取的GBK字节解码并转换为unicode字节码保存在中。然后tomcat在输出时(out.println())使用charset属性将内存中的unicode转换为utf-8编码,并在响应头中通知浏览器,浏览器以utf-8显示接收到的内容。整个过程没有一次转码错误,所以就不会出现乱码情况。
问题五:Properties和ResourceBundle使用的解码编码。
以上两个是我们常用的类,他们在读取文件过程中并不允许我们指定解码编码,那么它们采取什么解码方式呢?查看源码后发现都是采用iso-8859-1编码来解码
的。这样的话我们也不难理解我们写的properties文件为什么都是iso-8859-1 的了。因为采取任何一个别的编码都将产生乱码。因为iso-8859-1编码是没
有中文的,所以我们输入的中文要转换为unicode,通常我们使用插件来完成,也可以使用jdk自带的工具。
编码和解码通俗解释
字符编码 与 解码
Java中Unicode转码
java对unicode的编码 和 解码
Java实现字符与Unicode互转
JAVA方法 字符串与unicode的相互转换
从原理上搞懂编码——究竟什么是编码?什么是解码?什么是字节流?
编码和解码
js解码与编码是什么意思?
关于编程中编码和解码的问题
没有更多推荐了,您好,欢迎来到365建站网-快速批量建站_企业免费建站_智能建站软件系统_在线建站和seo工具
您现在的位置:& >
> PHP_CodeSniffer安装使用教程检查代码是否符合编码规范
PHP_CodeSniffer安装使用教程检查代码是否符合编码规范
文章来源:365jz.com &&&&点击数:104&&&&更新时间: 11:42 &&
_CodeSniffer是一款自动化的PHP代码规范检查工具。PHP_CodeSniffer是PEAR中的一个用PHP5写的用来检查嗅探PHP代码是否有违反一组预先设置好的编码标准的一个包,它是确保你的代码简洁一致的必不可少的开发工具,甚至还可以帮助程序员减少一些语义错误。CodeSniffer内置MySource、PEAR、PHPCS、PSR1、PSR2、Squiz和Zend等几套代码规范。当然,你也可以新增自己的代码规范。PHP_CodeSniffer包含两个工具,phpcs用来检查代码规范,phpcbf用来纠正代码规范。1 安装PHP_CodeSniffer 有好几种安装方式。1.1 可执行文件方式安装用git命令下载(或直接下载)仓库源码,然后直接执行:git&clone&https://github.com/squizlabs/PHP_CodeSniffer.gitcd&PHP_CodeSniffer
php&bin/phpcs&-h
php&bin/phpcbf&-h要使用非最新版本,可以到PEAR下载,地址:http://pear.php.net/package/PHP_CodeSniffer/download例如,要用2.9.1,PEAR下载之后解压,执行的命令是:php&scripts/phpcs&-h
php&scripts/phpcbf&-h与 githuh 下载不同的是,执行文件在scripts目录。1.2 phar文件安装方式phar也就是php archive,把php文件打包成一个文件供服务。Linux系统用命令下载phar文件:curl&-OL&https://squizlabs.github.io/PHP_CodeSniffer/phpcs.pharcurl&-OL&https://squizlabs.github.io/PHP_CodeSniffer/phpcbf.pharWindows系统用浏览器访问上面的两个链接,下载这两个phar文件。然后在phar文件的目录里面执行:php&phpcs.phar&-hphp&phpcbf.phar&-h能看到phpcs和phpcbf的帮助信息,说明安装成功。说明:1.3 pear安装方式如果本地安装了pear(pear安装方法),也可以通过pear来安装PHP_CodeSniffer,命令:pear&install&PHP_CodeSniffer通过pear安装后,CodeSniffer的规范文件会安装在:/path/to/pear/PHP/CodeSniffer/src/Standards。1.4 composer安装方式composer安装也很方便,一个命令:composer&global&require&&squizlabs/php_codesniffer=*&说明:这里需要composer命令已经在PATH环境变量中。也可以在composer.json文件中使用:{
&&&&&require-dev&:&{
&&&&&&&&&squizlabs/php_codesniffer&:&&3.*&
}完成后执行命令:./vendor/bin/phpcs&-h
./vendor/bin/phpcbf&-h1.5 配置phpcs直接在命令行中执行以上的方式中,除了pear安装方式,其他方式要执行phpcs命令,都需要在前面加上php。如果是Linux提供,因为php执行文件路径已经在环境PATH中,所以把bin(或scripts) 的路径加入PATH,就可以在终端执行phpcs命令了。但是在Windows系统中,实际是执行phpcs.bat文件,这个文件又引用了同目录下的phpcs文件。在phpcs.bat中,我们需要配置两个变量,才能在CMD中正确执行phpcs命令。如下,需指定.exe和phpcs文件的绝对位置:if&&%PHPBIN%&&==&&&&set&PHPBIN=D:\php56n\php.exe
if&not&exist&&%PHPBIN%&&if&&%PHP_PEAR_PHP_BIN%&&neq&&&&goto&USE_PEAR_PATH
:USE_PEAR_PATH
set&PHPBIN=%PHP_PEAR_PHP_BIN%
&%PHPBIN%&&&D:\www\PHP_CodeSniffer-2.9.1\scripts\phpcs&&%*然后把路径D:\www\PHP_CodeSniffer-2.9.1\scripts\加入到PATH中,就可以在CMD中执行phpcs了。说明:phpcbf也需要这样的修改。2 使用上面我们看到 PHP_CodeSniffer 有两个命令。默认情况下,PHP_CodeSniffer 使用PEAR规范检查代码。2.1 使用命令以下命令用默认规范来来检查文件和目录。$&phpcs&/path/to/code/myfile.php&&&&&&&&&&&&&&&&&&&&&&&&#&检查文件$&phpcs&/path/to/code&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&#&检查目录和子目录下的所有文件$&phpcs&-l&/path/to/code&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&#&检查目录下的所有文件,不包括子目录$&phpcs&/path/to/code/myfile.inc&/path/to/code/my_dir&&&#&检查文件和目录2.2 检查结果默认情况下,检查结果包含错误和警告,如下:$&phpcs&/path/to/code/myfile.php
FILE:&/path/to/code/myfile.php
--------------------------------------------------------------------------------
FOUND&5&ERROR(S)&AND&1&WARNING(S)&AFFECTING&5&LINE(S)
--------------------------------------------------------------------------------
&&2&|&ERROR&&&|&Missing&file&doc&comment
&20&|&ERROR&&&|&PHP&keywords&must&be&&expected&&false&&but&found
&&&&|&&&&&&&&&|&&FALSE&
&47&|&ERROR&&&|&Line&not&indented&&expected&4&spaces&but&found&1
&47&|&WARNING&|&Equals&sign&not&aligned&with&surrounding&assignments
&51&|&ERROR&&&|&Missing&function&doc&comment
&88&|&ERROR&&&|&Line&not&indented&&expected&9&spaces&but&found&6
--------------------------------------------------------------------------------如果不要显示警告,加个-n参数:$&phpcs&-n&/path/to/code/myfile.php仅显示检查结果概要:$&phpcs&--report=summary&/path/to/code2.3 指定规范可以使用&参数指定一个或多个规范来检查。$&phpcs&--standard=PEAR&/path/to/code/myfile.inc&&&&&&&&&&&&&&&&&&&&&&#&使用内置规范
$&phpcs&--standard=/path/to/MyStandard&/path/to/code/myfile.inc&&&&&&&#&使用指定路径下的规范
$&phpcs&--standard=PEAR,PHPCS,/path/to/MyStandard&file.php&&&&&&&&&&&&#&使用多个规范
$&phpcs&--config-set&default_standard&Squiz&&&&&&&&&&&&&&&&&&&&&&&&&&&#&修改默认规范为Squiz(原本是PEAR)查看现有规范:$&phpcs&-i2.4 查看帮助$&phpcs&-h
如对本文有疑问,请提交到交流论坛,广大热心网友会为你解答!!
您可能感兴趣的文章:
if(f.msg.value.length 500)
alert("你的评论是不是太长了?请填写500字以内的评论。");
$("#commetcontentNew").html(waithtml);
url:'/plus/comment.php?dopost=send&aid=24492&time='+Number(new Date()),
type: 'POST',
data:{msg:f.msg.value,username:f.username.value,validate:f.validate.value},
success:function(d){
$("#commetcontentNew").html(d);
(104人查看,0条评论)
------分隔线----------------------------
大家感兴趣的内容
最近更新的内容
手机客户端&&&&&&&&&&&&&&&&&&
posts - 228,comments - 223,trackbacks - 0
一、研发流程规范
二、SQL编码规范
  数据库命名规范:数据库名一律小写,必须以字母开头。库名包含多个单词的,以下划线&_&分隔。如果采用分库方案,分库编号从&0&开始,用&0&左补齐为四位。
  表名规范:表名一律小写,必须以字母开头。表名中包含多个单词的,以下划线&_&分隔。如果采用分表方案,同时分表编号从&0&开始,用&0&左补齐为四位。建议使用&数据库名_表名&形式,例如:tkn_users。
  字段名和字段类型规范:字段名一律小写,必须以字母开头,言简意赅且不含拼写错误的单词(限用有歧义的缩写形式)。字段名中包含多个单词的,以&_&分隔。字段类型越小越好,并留有一定余地。字段类型尽量设置为not null(特别是primary key和unique key引用的字段,更要注意这一点);数字类型尽量设置为unsigned(防止溢出之后数值变负);不要保存default数值,以免表结构中存在业务逻辑。primary key引用的字段,主表必须为数字型非负非空自增id,分表必须为数字型非负非空自增id或数字型非负非空id。注意约定俗成的字段,如user_id、gmt_create和gmt_modified。意义相同的情况下,要使用约定俗成的字段。其中,gmt_create和gmt_modified字段需要定义为datetime not null,user_id需要定义为bigint unsigned。在表中使用扩展字段如features时,尽量使用key-value形式存储,每一个key_value使用&;&隔开,key全部小写,必须以字母开头,多个单词使用'_'分割,不适用含有歧义的缩写形式。
  索引规范:不要使用含有null的列:只要列中包含有NULL值都将不会被包含在索引中,复合索引中只要有一列含有NULL值,那么这一列对于此复合索引就是无效的。所以我们在数据库设计时不要让字段的默认值为NULL。尽量使用段索引:对串列进行索引,如果可能应该指定一个前缀长度。例如,如果有一个CHAR(255)的列,如果在前10个或20个字符内,多数值是惟一的,那么就不要对整个列进行索引。短索引不仅可以提高查询速度而且可以节省磁盘空间和I/O操作。最好使用数字做索引。扩展索引:索引修改尽量使用扩展索引,不要新建索引。比如表中已经有a的索引,现在要加(a,b)的索引,那么只需要修改原来的索引即可。索引列排序:MySQL查询只使用一个索引,因此如果where子句中已经使用了索引的话,那么order by中的列是不会使用索引的。因此数据库默认排序可以符合要求的情况下不要使用排序操作;尽量不要包含多个列的排序,如果需要最好给这些列创建复合索引。like语句操作:一般情况下不鼓励使用like操作,如果非使用不可,如何使用也是一个问题。like &%aaa%& 不会使用索引而like &aaa%&可以使用索引。不要在列上进行运算:select * from users where YEAR(adddate)&2007,将在每个行上进行运算,这将导致索引失效而进行全表扫描,因此我们可以改成:select * from users where adddate&&&。索引顺序:mysql会一直向右匹配直到遇到范围查询(&、&、between、like)就停止匹配,比如a = 1 and b = 2 and c & 3 and d = 4 如果建立(a,b,c,d)顺序的索引,d是用不到索引的,如果建立(a,b,d,c)的索引则都可以用到,a,b,d的顺序可以任意调整。
  此外,分表查询:分表查询必须添加分表键作为参数,以防止tddl对表进行join查询,如无法使用分表键需要考虑分表键设置是否合理。单表数据量:单表数据量不超过500W,超过1000W的表需考虑使用分表,如无法使用分表需要控制表记录数,历史数据考虑迁移。
三、异常处理规范
  在项目IDCM中,异常ServiceException继承自RuntimeException。
package com.alibaba.tboss.
public class ServiceException extends RuntimeException {
private static final long serialVersionUID = -52539L;
protected String
public ServiceException(String errorMsg){
super(errorMsg);
public ServiceException(String errorMsg, Exception e){
super(errorMsg, e);
public ServiceException(ErrorCode msgObj){
super(msgObj.getFullMsg());
this.errCode = msgObj.getCode();
public ServiceException(ErrorCode msgObj, String... arg){
super(msgObj.getFullMsg(arg));
this.errCode = msgObj.getCode();
public ServiceException(ErrorCode msgObj, Throwable cause){
super(msgObj.getFullMsg(), cause);
this.errCode = msgObj.getCode();
public String getErrCode() {
return this.errC
public void setErrCode(String errCode) {
this.errCode = errC
  异常的总体原则:忽略不能处理的异常,留给框架统一处理。仔细定义业务异常,谨慎处理,不要吃掉任何异常。
  数据访问层:DAO中的方法可以不声明抛出异常(推荐)或声明抛出DAOException(这个异常是SqlMapClientDaoSupportEx类封装结果,没有什么作用)。数据访问层一般不要定义业务异常。
//正确的声明方式:
CustomerSettings getCustomerSettingsById(long customerId);
CustomerSettings getCustomerSettingsById(long customerId) throws DAOE
//不推荐的声明方式:这样会强制要求调用它的类捕获这个异常处理
CustomerSettings getCustomerSettingsById(long customerId) throws E
  业务层:BO中的方法可以不声明抛出异常(推荐)或声明抛出BOException或其他的checked exception(业务异常)。对于业务异常,需要强制外部调用处理的,需合理规范和定义业务异常类。
//正确的声明方式:
public Long updateTrade(String tradeNo,String alitradeno,String totalFee);
public Long updateTrade(String tradeNo,String alitradeno,String totalFee) throws BOE
//对于一些特殊的业务异常:
public Long updateTrade(String tradeNo,String alitradeno,String totalFee) throws TradeE
public class TradeException extends Exception {...}
  展现层:Controller中的方法可以声明抛出Exception,并且在处理过程中不catch任何Exception。框架会捕获并做后续操作,框架在捕到异常后,会打到root logger中,并且重定向到通用的错误页面。如果你需要对特定的异常做特殊处理(如跳转到其他的错误页面)的话,才需要考虑抓住异常,这时请正确地记录这个异常,以方便后期跟踪问题。
  其他规范:如果不是一定要处理,尽可能忽略RuntimeException(包括DAOException和BOException等),留给框架处理。如果需要抓异常,尽量抓某一个特定的异常(如TradeException),不要将所有Exception全部抓住。抓住异常后,要么记录异常详细信息到日志文件,要么带上原有异常重新抛出,不要两样都做,避免重复记录。不要两样都不做,会吃掉异常。不要使用e.printStackTrace(),因为有性能问题,而且不能指定记录日志的文件。
// 不推荐这种方式:抓住异常log一下再抛出来,这是多余的,框架会为我们处理。
// 当然,如果需要抛出的是checked exception则另当别论
} catch (Exception e) {
log.error("abcd", e);
throw new BOException("abcd", e);
// 吃掉了异常,外面不知道怎么回事
try { .... } catch (Exception e) { }
// 没有正确记录异常,日志文件中记录的信息太少不利于错误跟踪
try { .... } catch (Exception e) { log.error("abcd" + e.getMessage); }
try { .... } catch (Exception e) { log.error("abcd" + e); }
try { .... } catch (Exception e) { log.error(e); }
// 正确的使用
try { .... } catch (Exception e) { log.error("abcd", e); }
  在我们的项目IDCM中,是如何处理异常信息的呢?
RPC层处理异常信息:
@ResourceMapping("rackList")
public DataResult&Rack& queryRackList(@RequestParams
PagePara pagePara, @RequestParams
Rack rack, @RequestParam(name = "operateType")
String operateType) {
DataResult&Rack& dataResult = new DataResult&Rack&();
// TODO 业务逻辑处理
} catch (Exception e) {
logger.error("queryRackList err : ", e);
if (e instanceof ServiceException) throw (ServiceException)
else throw new ServiceException("查询数据失败");
return dataR
BoImpl层的异常信息:
public DataResult&WorkOrderMain& queryOrderPagination(WorkOrderMain orderMain, PagePara pagePara) {
DataResult&WorkOrderMain& dr = new DataResult&WorkOrderMain&();
// TODO 调用dao层的业务逻辑
} catch (Exception e) {
logger.error(" WorkOrderLogisticsBoImpl_queryOrderPagination_error [orderMain={}]:",
JSON.toJSON(orderMain).toString(), e);
throw new ServiceException(ErrorCode.Query_Error, e);
四、日志规范
  日志的作用: 记录重要数据、操作以备日后核对;记录案发现场,方便日后定位问题。日志的分类: 按日志的用途可以分为系统异常日志,应用相关日志,用户操作日志等。不同类型的日志分开记录,系统异常日志一般记录在root logger下;如velocity相关的日志也可以分记到不同的日志文件中,方便问题查找。记录日志INFO或DEGUB级别的应该先做log.isXXXenabled()判断。(如果是应用日志就打算记录成INFO级别则不用这一条)业务代码中,尽可能少用DEBUG级别的日志,容易混淆业务逻辑。在通用的底层代码中,可以适当用一些INFO和DEBUG级别的日志。在调试代码时可以利用这些日志信息,避免过于深入的跟踪。
  异常日志需要打印异常的详细信息,如stackTrace等,方便问题查找。现在的框架会统一处理异常。自己捕获异常处理后如果不继续往外抛出,不要忘记记录该异常。
import org.apache.commons.logging.L
import org.apache.commons.logging.LogF
= LogFactory.getLog(getClass());//名字统一用logger
= LogFactory.getLog(getClass()); //不推荐
构造log格式:必须有的字段:时间(%d{yy-MM-dd HH:mm:ss})、日志级别( %-5p)、类名(%c)、行号(%L) log内容(%m%n)
logger.error("xxxxx",e);
logger.error("xxxxx"+e);
异常log,需要错误堆栈,异常对象,要放到第二个参数。
变量前面一定要有!。
最好加上大括号(不强制),变量名前后加上{}。
五、Java编码规范
  重载方法不应该分开:当一个类有多个构造函数,或者多个同名成员方法时,这些函数应该写在一起,不应该被其他成员分开。
  命名:包名:包名全部用小写字母,通过 . 将各级连在一起。不应该使用下划线。类名:类型的命名,采用以大写字母开头的大小写字符间隔的方式(UpperCamelCase)。class命名一般使用名词或名词短语。interface的命名有时也可以使用形容词或形容词短语。annotation没有明确固定的规范。测试类的命名,应该以它所测试的类的名字为开头,并在最后加上Test结尾。例如:HashTest 、 HashIntegrationTest。(PS:经常见到写成TestXXXX的类名,以后注意了)。方法名:方法命名,采用以小写字母开头的大小写字符间隔的方式(lowerCamelCase)。方法命名一般使用动词或者动词短语。在JUnit的测试方法中,可以使用下划线,用来区分测试逻辑的名字,经常使用如下的结构:test&MethodUnderTest&_&state& 。例如:testPop_emptyStack 。测试方法也可以用其他方式进行命名。常量名:常量命名,全部使用大写字符,词与词之间用下划线隔开。(CONSTANCE_CASE),常量一般使用名词或者名词短语命名。PS:常量是一个静态成员变量,但不是所有的静态成员变量都是常量。在选择使用常量命名规则给变量命名时,需要明确这个变量是否是常量。例如,如果这个变量的状态可以发生改变,那么这个变量几乎可以肯定不是常量。只是计划不会发生改变的变量不足以成为一个常量,但是我们这里把这种情况也定义为常量,所以也要大写,下面是常量和非常量的例子:
static final int
static final List&String&
= Collections.unmodifiableList(Arrays.asList("ed", "ann"));
static final ImmutableList&String& NAMES2
= ImmutableList.of("ed", "ann");
static final SomeMutableType[] EMPTY_ARRAY={};
enum SomeEnum{ENUM_CONSTANT}
//不是常量
= "non-final";
= "non-static";
static final Set&String& mutableCollection = new HashSet&String&();//集合不是不可变的
//下面三种情况虽然内部存放对象可能会改变,但是属于计划不会发生改变的变量,我们也算做常量,所以也要大写。
static final ImmutableSet&SomeMutableType& MUTABLE_ELEMENTS=ImmutableSet.of(mutable);
static final Logger LOGGER=Logger.getLogger(MyClass.getName());
static final String[]
NON_EMPTY_ARRAY
= { "these", "can", "change" };
非常量的成员变量名:非常量的成员变量命名(包括静态变量和非静态变量),采用lowerCamelCase命名。一般使用名词或名词短语。参数名:参数命名采用lowerCamelCase命名。#应该避免使用一个字符作为参数的命名方式#。特殊变量或参数名:DTO(Data Transfer Object):在变量、类名、参数等地方使用的时候,如果要用DTO结尾做名字,必须用大写。例如:UserDTO.class、userDTO、userDTOs、userDTOList。DO(Data Object咱们这边经常用在DB操作):在变量、类名、参数等地方使用的时候,如果要用DO结尾做名字,必须用大写。文件后缀:Service表明这个类是个服务类,里面包含了给其他类提同业务服务的方法。DAO这个类封装了数据访问方法。Impl这个类是一个实现类,而不是接口(通常是实现DAO和Service)。&
六、代码格式规范
if(a!=null)return true
需要改成:
if(a!=null){
return true;
  花括号一般用在if, else, for, do, 和 while等语句。甚至当它的实现为空或者只有一句话时,也需要使用。
  if语句的嵌套层数保证在3层以内。太多层嵌套,最后自己都看不懂。直观感受一下,加上代码块,就会很复杂,而且还会有else。尤其是在代码不断增加需求的过程中,要重构一些代码,造成代码if嵌套混乱。
  类的文件代码长度不要超过1000行。方法的长度不要超过150行,超出的考虑拆分一下。
public enum EnumExample {
EXAMPLE_ONE, EXAMPLE_TWO;
public enum EnumExample {
/** 例子一 */
EXAMPLE_ONE("1"),
/** 例子二 */
EXAMPLE_TWO("2");
private EnumExample(String index) {
  枚举经常需要被外部引用,如果名字不能直接表达,需要加javadoc。枚举名需要全大写,单词用&_&分割。
  局部变量:局部变量不应该习惯性地放在语句块的开始处声明,而应该尽量离它第一次使用的地方最近的地方声明,以减小它们的使用范围。局部变量应该在声明的时候就进行初始化。如果不能在声明时初始化,也应该尽快完成初始化。
  switch必须有default:每个switch语句中,都需要显式声明default标签。即使没有任何代码也需要显示声明。
  修饰符的顺序:多个类和成员变量的修饰符,按Java Lauguage Specification中介绍的先后顺序排序。具体是:
synchronized
除注释外的代码,不允许出现中文。经常看到log里面用中文,这样不允许,还有用中文直接equals比较,也同样不允许。
  项目中禁止使用System.out.println()。如果有log需求,直接用log4j好了,可以随意指定输出位置。
public String toString() {
@Override:@override 都应该使用。@override annotations只要是符合语法的,都应该使用。PS:如果没写Override intellij&eclipse默认都会有警告出现。
  异常捕获,不应该被忽略:一般情况下,catch住的异常不应该被忽略,而是都需要做适当的处理。例如将错误日志打印出来,或者如果认为这种异常不会发生,则应该作为断言异常重新抛出。
return Integer.parseInt(response);
}catch (NumberFormatException ok){
// 不是数字没关系,继续往下走就行啦
如果这个catch住的异常确实不需要任何处理,也应该通过注释做出说明。
emptyStack.pop();
} catch (NoSuchMethodException expected) {
在测试类里,有时会针对方法是否会抛出指定的异常,这样的异常是可以被忽略的。但是这个异常通常需要命名为: expected。
七、javadoc规范
  对外的接口一定要有javadoc(强制),例如一些hsf服务什么的接口必须要有。
* 我多行我开心
/** 我单行我快乐 */
  @从句:所有标准的@从句,应该按照如下的顺序添加:@param、@return、@throws、@deprecated。并且这四种@从句,不应该出现在一个没有描述的Javadoc块中。
  何处应该使用Javadoc:至少,Javadoc应该应用于所有的public类、public和protected的成员变量和方法。和少量例外的情况。例外情况如下:例外一:方法本身已经足够说明的情况。当方法本身很显而易见时,可以不需要javadoc。例如:getFoo。没有必要加上javadoc说明&Returns the foo&。单元测试中的方法基本都能通过方法名,显而易见地知道方法的作用。因此不需要增加javadoc。注意:有时候不应该引用此例外,来省略一些用户需要知道的信息。例如:getCannicalName 。当大部分代码阅读者不知道canonical name是什么意思时,不应该省略Javadoc,认为只能写/** Returns the canonical name. */例外二:重载方法:重载方法有时不需要再写Javadoc。
八、二方库版本控制规范
对外公开的api类二方库版本控制规范
  版本格式:主版本号.次版本号.修订号,版本号递增规则如下:
    主版本号:当你做了不兼容的API 修改。
    次版本号:当你做了向下兼容的功能性新增(新增接口、接口兼容性修改等)。
    修订号:当你做了向下兼容的问题修正或者实现的修改。
  其他版本版本编译信息加到&主版本号.次版本号.修订号&的后面,作为延伸。
  好处:版本号及其更新方式包含了相邻版本间的底层代码和修改内容的信息,通过版本号可以知道如何升级,例如:次版本/修订版本升级了,就可以考虑升级,因为是向后兼容的。
  版本控制规范:
    标准的版本号XYZ格式,其中X、Y和Z为非负的整数,X是主版本、Y是次版本号、而Z为修订号。每个元素必须以数值来递增。例如:1.9.1 -& 1.10.0 -& 1.11.0。
    有版本号的二方库发布后,禁止改变该版本的内容。任何修改都必须增加新版本发行(snapshot除外)。
    主版本号为零(0.yz)的软件处于开发初始阶段,一切都可能随时被改变。这样的公共API 不应该被视为稳定版。
    1.0.0 的版本号用于界定公共API 的形成。这一版本之后所有的版本号更新都基于公共API 及其修改内容。
    修订号Z(xyZ | x & 0)&必须&在只做了向下兼容的修正时才递增。这里的修正指的是针对不正确结果而进行的内部修改(例如:修bug)或者在内部程序有大量新功能或改进被加入时递增(我们业务需求经常干的)。在任何公共API的功能被标记为弃用时也&必须&递增(例如:废弃了某个接口)。
    次版本号Y(xYz | x & 0)&必须&在有向下兼容的新功能出现时递增。(例如:新增接口/接口参数从int变为Integer类似),但每当次版本号(Y)递增时,修订号(Z)&必须&归零。
    主版本号X(Xyz | X & 0)&必须&在有任何不兼容的修改被加入公共API时递增。其中&可以&包括次版本号(Y)及修订级别(Z)的改变。每当主版本号递增时,次版本号和修订号&必须&归零。
    先行版本(例如SNAPSHOT版本、alpha等)可以标注在修订版(Z)之后,先加上一个连接号()再加上一连串以句点分隔的标识符号来修饰。标识符号&必须&由ASCII码的英数字和连接号[0-9A-Za-z]组成,且&禁止&留白。数字型的标识符号&禁止&在前方补零。被标上先行版本号则表示这个版本并非稳定而且可能无法达到兼容的需求。范例:1.0.0-snapshot、1.0.0-alpha、1.0.0-alpha.1、 1.0.0-0.3.7、1.0.0-x.7.z.92。
我们的实践方案
  根据上面的规范,我们的对外二方库,可以遵循上面的方式开发,不能使用SNAPSHOT版本,对内的使用或者不适用SNAPSHOT都可以。
  如果是对外的api(例如:market.open.share),有对应的open.client这种sdk,open.share和open.client必须联动升级,例如:open.share 主次版本修改open.client也必须跟着修改,并且版本一致。
  外部使用,market举例,针对有open.client这种sdk的对外api二方库,使用api的时候,直接依赖open.client就可以了,不需要手动指定open.share,原因见上一条。
  对外公布的二方库里面增加文件(README.md) 记录每个主版本和次版本号的升级日志。
  对外open的二方库只能依赖其他open的二方库或者三方库,不能依赖自己的非open的二方库。
PS: 对内的二方库使用SNAPSHOT版本,要大写
九、三方库的使用
import com.google.common.collect.L
import com.google.common.collect.M
import com.google.common.collect.S
List&String& keys = Lists.newArrayListWithCapacity(infos.size());
Map&K, V& resultMap = Maps.newHashMapWithExpectedSize(tmpList.size());
Set&String& sets=Sets.newHashSet();
创建集合&Map:推荐使用guava的静态方法,创建集合。
字符串操作:优先使用:StringUtils(org.apache.commons.lang3.StringUtils)常用方法:isBlank、isNotBlank。
数组操作:优先使用:ArrayUtils(org.apache.commons.lang3.ArrayUtils)。常用方法:isEmpty、isNotEmpty、toString(final Object array)。
集合操作:优先使用:CollectionUtils(org.apache.commons.collections4.CollectionUtils)常用方法:isEmpty、isNotEmpty、size。
Map操作:优先使用:MapUtils(org.apache.commons.collections4.MapUtils)常用方法:isEmpty、isNotEmpty。
除上面以外还有NumberUtils、DateFormatUtils、DateUtils等优先使用org.apache.commons.lang3这个包下的,不要使用org.apache.commons.lang包下面的。原因是commons.lang这个包是从jdk1.2开始支持的所以很多1.5/1.6的特性是不支持的,例如:泛型。
import org.apache.commons.lang3.builder.ToStringB
import org.apache.commons.lang3.builder.ToStringS
class User {
private User(String name) {
this.name =
public String toString() {
return ToStringBuilder.reflectionToString(this, ToStringStyle.SHORT_PREFIX_STYLE);
public static void main(String[] args) {
System.out.println(new User("testname"));
输出:User[name=testname]
重载toString方法:优先使用:ToStringBuilder(org.apache.commons.lang3.builder.ToStringBuilder)。
相关第三方库依赖如下:
&dependency&
  &groupId&org.apache.commons&/groupId&
  &artifactId&commons-lang3&/artifactId&
  &version&3.3.2&/version&
&/dependency&
&dependency&
  &groupId&org.apache.commons&/groupId&
  &artifactId&commons-collections4&/artifactId&
  &version&4.0&/version&
&/dependency&
&dependency&
  &groupId&com.google.guava&/groupId&
  &artifactId&guava&/artifactId&
  &version&18.0&/version&
&/dependency&
十、消灭警告规范
  消灭警告:警告本来就是可能有问题的代码,还是有可能会影响正常功能。或者至少去掉会让代码更简洁,PS:警告eclipse左侧会显示屎黄色的小标。
用findbugs扫一下:好处:帮助我们发现很多问题和优化意见(貌似最多的就是空指针)。首先装个findbugs插件,装好了右键执行,完成后在Bug Explorer视图里面看结果。
十一、codereview规范
  codereview:发布代码前在aone指定codereview的人,进行代码审查。但是代码审查并不是说只找一个人,这可以是团队多人一起做。进行reivew的人也不一定必须是老人,有时我们可能觉得&经验比较浅,不能对别人codereivew&,其实并不一定,俗话说:三个臭皮匠,顶个诸葛亮。即使是经验欠缺,多个人review,也能完成高质量的代码。
  怎么做codereivew呢?
codereivew的人要做那些事情,简单来说就是看代码,具体看什么下面是一些建议:
实现正确吗(如果能看出来最好,看不出来,那也没办法,reivew的人不是测试)
代码实现清晰易读吗 (优美的代码,会让人看得入迷的)
是不是最好的实现,有没有重构的空间
有没有没有考虑到的点,特别是对其他部分代码会否造成影响(例如:发布没兼容老业务,会不会对线上造成影响)
测试代码同样需要审查(有空的话,测试用例也过一下)
阅读(...) 评论()

我要回帖

更多关于 java编码规范 的文章

 

随机推荐