@ZeroGeek
2016-08-18T09:40:28.000000Z
字数 9343
阅读 796
原则:保证命名后能准确表达业务。
// 示例
public class Person {
public static final int MAX_VALUE = 1000;
private static double sShareMoney;
private int mAge;
// ...
private void cost(double money) {
double localMoney = money;
// ...
}
// ...
}
类名和接口使用类意义完整的英文描述,每个英文单词的首字母使用大写、其余字母使用小写的大小写混合法
public class UploadNickNameTask {
// ...
}
public interface OnItemClickListener {
// ...
}
方法名使用类意义完整的英文描述:第一个单词的字母使用小写、剩余单词首字母大写其余字母小写的大小写混合法
public String getType();
public boolean isFinished();
public void setVisible(boolean isVisible);
public void show();
public void addKeyListener(Listener listener);
程序块要采用缩进风格编写,缩进的空格数为4个。
分界符(如大括号‘{’和‘}’)应各独占一行,同时与引用它们的语句左对齐。在函数体的开始、类和接口的定义、以及if、for、do、while、switch、case语句中的程序或者static、,synchronized等语句块中都要采用如上的缩进方式。
if (a > b) {
doStart();
}
较长的语句、表达式或参数(>80字符)要分成多行书写,长表达式要在低优先级操作符处划分新行,操作符放在新行之首(sql语句字符串拼接为了可读性除外),划分出的新行要进行适当的缩进,使排版整齐,语句可读。
if (logger.isDebugEnabled()){
logger.debug("Session destroyed,call-id"
+ event.getSession().getCallId());
}
不允许把多个短语句写在一行中,即一行只写一条语句,包括声明变量。
// 不规范
int a,b;
a = b++;
// 规范
int a;
int b;
a = b;
b++;
if, for, do, while, case, switch, default 等语句自占一行,且if, for, do, while,switch等语句的执行语句无论多少都要加括号{},case 的执行语句中如果定义变量必须加括号{}。
if (isShow()) {
return true;
}
switch (type) {
case 0: {
a = b;
b++;
// ...
}
break;
// ...
}
在两个以上的关键字、变量、常量进行对等操作时,它们之间的操作符之前、之后或者前后要加空格;进行非对等操作时,如果是关系密切的立即操作符(如.),后不应加空格。
if (a == b) {
objectA.doStart();
}
a *= 2;
某类 {
类的公有属性定义
类的保护属性定义
类的私有属性定义
类的公有方法定义
类的保护方法定义
类的私有方法定义
}
修饰词按照指定顺序书写:
public/protected/private abstract static final transient volatile synchronized native
// While语句的规则如下:
while (condition) {
statements;
}
// 禁用这种do while语句
do {
statements;
} while (condition);
Switch语句风格如下。需要注意的是不要忘了default,break。另外分支和分支之间以空行隔开。
switch (condition) {
case ABC:
case DEF:
statements;
break;
case XYZ: {
statements;
}
break;
default:
statements;
break;
}
if (condition1) {
statements;
} else if (condition2) {
statements;
} else {
statements;
}
对于数组、list等的遍历,如果不是特殊要求(比如在循环遍历中删除某个元素,for中边循环边删除会ConcurrentModificationException异常,这种应该使用Iterator迭代器),使用for-each方式。
for (Item item:items) {
statements;
}
//禁止方式
while (index < products.getCount()) {
//每此都会执行一次getCount()方法,
//若此方法耗时则会影响执行效率
//而且可能带来同步问题,若有同步需求,请使用同步块或同步方法
}
for (int i = 0; i < products.getCount(); i++) {
// ...
}
//推荐方式,将操作结构保存在临时变量里,减少方法调用次数
final int count = products.getCount();
while (index < count) {
}
// 或者
for (int i = 0; i < count; i++) {
// ...
}
不要catch异常而不做任何处理,要么不catch异常(让异常抛出去),要么catch作特殊处理,或者生成一个新的异常抛出去。
这里有两个异常需要特别注意,NullPointerException原则上是不允许catch的,OutOfMemoryError在解码图片时或者经常出现内存使用紧张的字符串拼接时可catch,其他地方尽量不要catch。
以下这种方式是不规范的:
void setServerPort(String value) {
try {
serverPort = Integer.parseInt(value);
} catch (NumberFormatException e) {
//等于直接吃掉了异常
}
}
对所有异常做特殊处理,最起码在遇到异常的地方打印异常日志:
void setServerPort(String value) {
try {
serverPort = Integer.parseInt(value);
} catch (NumberFormatException e) {
Debug.exception(TAG, e);
}
}
不建议catch普通的异常,比如Exception、Throwable。而应catch具体的异常类型,比如IllegalArgumentException等。
下面的做法是不推荐的:
try {
FileOutputStream outStream = new FileOutputStream(new File("tmp.txt"));
outStream.write(bytes);
} catch (Exception e) {
statements;
}
应该捕获特定的异常:
try {
FileOutputStream outStream = new FileOutputStream(new File("tmp.txt"));
outStream.write(bytes);
} catch (FileNotFoundException e) {
statements;
} catch (IOException e) {
statements;
}
数组声明的时候使用 int[] index,而不要使用 int index[]。
尽量使变量的作用域降到最小范围,如果不是特殊要求,不要过早创建不需要的对象。
// 建议使用:
String s = "Hello";
// 而不是下面这样的形式:
String s;
// …
s = "Hello";
如果一个包含二元运算符的表达式出现在三元运算符" ? : "的"?"之前,那么应该给表达式添上一对圆括号。
a = (x >= 0) ? x : -x
String str = "";
if(TextUtil.isEmpty(str)){
// ...
}
if("rect".equals(str)) {
// ...
}
防止溢出
// 不规范 结果值:
float twoThirds = 2/3; // 0.0
long millisInYear = 1000*3600*24*365; // 1471228928
long bigNum = Integer.MAX_VALUE + 2; // -2147483647
long bigNegNum = Integer.MIN_VALUE - 1; // 2147483647
// 规范 期望值:
float twoThirds = 2f/3; // 0.6666667
long millisInYear = 1000L*3600*24*365; // 31536000000
long bigNum = Integer.MAX_VALUE + 2L; // 2147483649
long bigNegNum = Integer.MIN_VALUE - 1L; // -2147483649
// 或者
float twoThirds = (float)2/3;
long millisInYear = (long)1000*3600*24*365;
long bigNum = (long)Integer.MAX_VALUE + 2;
long bigNegNum = (long)Integer.MIN_VALUE - 1;
游标获取字符串的问题: String result = c.getString(c.getColumnIndex(columnName); 如果数据库表名字为
columnName的字段的值是null,则result不是null而是一个字符串”null”,在做服务器开发的时候jdbc驱动是会返回空串的.
统一使用CollectionUtil工具类
public class CollectionUtil {
public static boolean isEmpty(Collection<?> collection){
return collection == null || collection.isEmpty();
}
public static boolean isEmpty(Map map){
return map == null || map.isEmpty();
}
}
可以使用IDE自动生成。如果不这样做,可能导致该类无法结合所有基于散列的集合一起正常运作,包括HashMap,HashSet和Hashtable。否则违反的Object.hashCode的约定:相等的对象必须具有相等的hashcode。
// 不规范
public static void main( String[] args ) {
String argStr = args.toString();
int argHash = args.hashCode();
// 规范
public static void main( String[] args ) {
String argStr = Arrays.toString(args);
int argHash = Arrays.hashCode(args);
使用BigDecimal.valueOf(double)而不是new BigDecimal(double),使数据更加精确
public static void main(String[] args) {
BigDecimal d1 = new BigDecimal(0.1); // 不推荐,可能导致某种错误
BigDecimal d2 = BigDecimal.valueOf(0.1); // 规范
// 打印出来的值
// d1:0.1000000000000000055511151231257827021181583404541015625
// d2:0.1
}
public BigDecimal(double val) {
this(val, MathContext.UNLIMITED); // 得到的是近似值
}
public static BigDecimal valueOf(double val) {
return new BigDecimal(Double.toString(val));
}
public BigDecimal(String val) {
this(val.toCharArray(), 0, val.length()); // 精确值
}
执行效率更高。
public static native void arraycopy(Object src, int srcPos, Object dst, int dstPos, int length);
使用Integer.parseInt(String) 而不是Integer.valueOf(String)。
// 不规范
String myNum = "12.2";
float f = new Float(myNum).floatValue(); // 增加了开销
// 规范
String myNum = "12.2";
float f = Float.parseFloat(myNum);
// 返回的是装箱基本类型,进行一次装箱和一次拆箱,导致高开销
public static Integer valueOf(String string) throws NumberFormatException {
return valueOf(parseInt(string));
}
// 直接返回基本类型
public static int parseInt(String string) throws NumberFormatException {
return parseInt(string, 10);
}
优点:可读性,效率更高。
基本类型与装箱基本类型的主要区别:
1. 基本类型只有值,装箱基本类型具有与它们的值不用的同一性。
2. 装箱基本类型有非功能值null(类类型)。
3. 基本类型通常比装箱基本类型更节省时间和空间。
// 不规范
int myInt = 4;
String myIntString = new Integer(myInt).toString(); // 多创建了一个Integer对象
myIntString = Integer.valueOf(myInt).toString();
myIntString = 4 + "";
// 规范
int myInt = 4;
String myIntString = Integer.toString(myInt);
用lastIndexOf(int c)替换lastIndexOf(String string),效率更高。
private static String getFileName(String url) {
// 如果只有一个字符,使用 url.lastIndexOf('/')
int index = url.lastIndexOf("/");
String fileName = url;
if (index > 0) {
fileName = url.substring(index + 1);
}
return fileName;
}
应该在编程中尽量避免些“坏味道”。
代码重复几乎是最常见的异味了。他也是Refactoring 的主要目标之一。代码重复往
往来自于copy-and-paste 的编程风格。
它是传统结构化的“遗毒“。一个方法应当具有自我独立的意图,不要把几个意图
放在一起。
大类就是你把太多的责任交给了一个类。这里的规则是One Class One Responsibility。
一个类里面的内容变化率不同。某些状态一个小时变一次,某些则几个月一年才变一次;某些状态因为这方面的原因发生变化,而另一些则因为其他方面的原因变一次。面向对象的抽象就是把相对不变的和相对变化相隔离。把问题变化的一方面和另一方面相隔离。这使得这些相对不变的可以重用。问题变化的每个方面都可以单独重用。这种相异变化的共存使得重用非常困难。
这正好和上面相反。对系统一个地方的改变涉及到其他许多地方的相关改变。这些变化率和变化内容相似的状态和行为通常应当放在同一个类中。
对象的目的就是封装状态以及与这些状态紧密相关的行为。如果一个类的方法频繁用get 方法存取其他类的状态进行计算,那么你要考虑把行为移到涉及状态数目最多的那个类。
某些数据通常像孩子一样成群玩耍:一起出现在很多类的成员变量中,一起出现在许多方法的参数中…..,这些数据或许应该自己独立形成对象。
面向对象的新手通常习惯使用几个原始类型的数据来表示一个概念。譬如对于范围,他们会使用两个数字。对于Money,他们会用一个浮点数来表示。因为你没有使用对象来表达问题中存在的概念,这使得代码变的难以理解,解决问题的难度大大增加。好的习惯是扩充语言所能提供原始类型,用小对象来表示范围、金额、转化率、邮政编码等等。
基于常量的开关语句是OO 的大敌,你应当把他变为子类、state 或strategy。
并行的继承层次是shotgun surgery 的特殊情况。因为当你改变一个层次中的某一个类时,你必须同时改变另外一个层次的并行子类。
一个干活不多的类。类的维护需要额外的开销,如果一个类承担了太少的责任,应当消除它。
一个类实现了从未用到的功能和通用性。通常这样的类或方法唯一的用户是testcase。不要犹豫,删除它。
一个对象的属性可能只在某些情况下才有意义。这样的代码将难以理解。专门建立一个对象来持有这样的孤儿属性,把只和他相关的行为移到该类。最常见的是一个特定的算法需要某些只有该算法才有用的变量。
消息链发生于当一个客户向一个对象要求另一个对象,然后客户又向这另一对象要求另一个对象,再向这另一个对象要求另一个对象,如此如此。这时,你需要隐藏分派。
对象的基本特性之一就是封装,而你经常会通过分派去实现封装。但是这一步不能走得太远,如果你发现一个类接口的一大半方法都在做分派,你可能需要移去这个中间人。
某些类相互之间太亲密,它们花费了太多的时间去砖研别人的私有部分。对人类而言,我们也许不应该太假正经,但我们应当让自己的类严格遵守禁欲主义。
做相同事情的方法有不同的函数signature,一致把它们往类层次上移,直至协议一致。
要建立一个好的类库非常困难。我们大量的程序工作都基于类库实现。然而,如此广泛而又相异的目标对库构建者提出了苛刻的要求。库构建者也不是万能的。有时候我们会发现库类无法实现我们需要的功能。而直接对库类的修改有非常困难。这时候就需要用各种手段进行Refactoring。
对象包括状态和行为。如果一个类只有状态没有行为,那么肯定有什么地方出问题了。
超类传下来很多行为和状态,而子类只是用了其中的很小一部分。这通常意味着你的类层次有问题。
经常觉得要写很多注释表示你的代码难以理解。如果这种感觉太多,表示你需要Refactoring。