public方法类的public方法是以“自动贩卖机的接口”为目标的。设计成易懂,就算使用方法错了,也不会影响内部的整合性。还有,可能的话,实行按合同进行的设计,把类的不变条件和方法的事前事后条件一起用代码表现出来。
状态取得和状态变更的分离方法是被设计成(只)做“一件事”。特别的,状态变更和状态取得这两服务不能用一个方法来实现。负责状态变更的方法return值为void。Stack的例子中,top()和removeTop()这两步要比pop()要好。理由1:只做一件事的方法容易懂。(Stack的例子中,惯用pop()方法)。理由2:并行性的控制,容易做到对异常安全的保护(参考:在C++中,pop()方法不能做到异常安全,所以pop()被作成了不能返回值的式样)。理由3:容易做子类化地扩展。
this的return即使假装考虑了方便客户,也应该避免return this。理由:叫做 a.meth1().meth2().meth3() 的连锁一般会成为synchronization上的问题之源。
方法的多重定义
避免过多使用根据引数类型来区分的方法(引数数量不同的可以)。特别是和继承一起使用的话较麻烦。如:× : draw(Line), draw(Rectangle)○ : drawLine(Line), drawRectangle(Rectangle)○ : draw(Shape)equals()和hashCode()由于重载Object.equals()方法,同是hashCode()方法也能重载。反之亦然。理由:因为对应Container类(Hashtable)等。clone()如果使用clone()方法,需要封装Cloneable并清楚标明。如: class Foo implements Cloneable ... { // ... public Object clone() ...{ try ...{ Foo foo = (Foo) super.clone(); // Foo 类属性的克隆 // ... } catch (CloneNotSupportedException e) ...{ // 因为implements Cloneable, 所以不能发生 throw new InternalError(); } }} 理由:shallow copy中不好的例子很多。 缺省构造方法 如果有可能,无论什么时候都要准备缺省的构造函数(没有参数的那种)。理由:在Class.newInstance()里,可以根据类名的字符串来创建类。abstract method in abstract classes在abstract类中写no-op的方法,明确声明为abstract方法。并且,如果可以准备可公用的缺省的封装,将其声明为protected,使子类可以在一行写处理。理由:java编译器能检查出没有被封装的abstract方法,可以避免所谓忘记单个被封装的bug。Object的同值比较使用equals()方法对Object进行比较,而不使用“==”。特别的,String 的比较中必须使用“==”。理由:如果封装者准备了equals()这个方法,就是希望使用这个封装。equals()的缺省封装,仅仅是“==”而已。理由:单元测试使用的是assertEquals中的equals(),所以可以简单地写同值测试。 声明和初始化局部变量与初始值一起声明。理由:最小化变量的假定值。反例: void f( int start) ... { int i, j; // 无初始值声明 // 更多的代码 // ... i = start + 1; j = i + 1; // 使用i, j } 正例: void f( int start) ... { // 更多的代码 // ... // 使用前进行声明和初始化 int i = start + 1; int j = i + 1; // 使用i, j } 局部变量的重复利用不好 与其重复印使用某局部变量,不如新声明并初始化一个。理由:最小化变量的假定值。理由:有利于编译程序的最优化。反例: void f( int N, int delta) ... { int i; // 无初始值声明 for (i = 0; i < N; i++) ...{// 使用 i } for (i = 0; i < N; i++) ...{// 还使用i if (...) ...{ break; } } if (i != N) ...{ // 判断是否回到最后时使用了i// ... } i = N – delta*2; // 再使 用// ... } 正例: void f( int N, int delta) ... { for (int i = 0; i < N; i++) ...{// 使用i } for (int i = 0; i < N; i++) ...{// 使用其他的i if (...) ...{ found = true; break; } } if (found) ...{// ... } int total = N – delta*2; // 有其他含义的变量// ... } if/ while条件中的“=”if, while的条件中,必须使用代入符号“=” 。理由:一般情况下都是bug。只要不是boolean类型的,java编译都能捕捉这种bug。比较大小的运算符尽量使用“<”,“<=”,尽量避免使用“>”,“>=”。理由:统一大小方向,右边的值大于左边的值,以避免混乱。CastCast尽可能用instanceof的条件文包围。 C cx = null ; if (x instanceof C) cx = (C) x; else evasiveAction(); 理由:在这里,经常会习惯性地考虑:“如果不是这个对象的实例呢?”。不过,如果可以判断不能进行类型转换(Cast)的时候就有bug,这种情况不在此限制以内。异常类?--异常类有使用泛围大的特点,难以读取多次使用的程序流。--?对于异常类,如果可以使用JDK标准包中已有的内容,尽量加以利用,而不是新创建一个异常类。如:IOException, NoSuchFileException, IllegalArgumentException,等,都是常用的异常类。如果要创建新的异常类,要把它作为对应包的全体接口来讨论。方法参数的变更是不好的原则上方法参数需要输入, 不用返回。即在方法内部不调用改变参数状态的方法。不在返回参数中代入新的对象(如果可能的话设为final)。反例: void moveX(Point p, int dx) ... { p.setX(p.getX() + dx); // 参数变更(尽量避免) } void moveX(Point p, int dx) ... { p = new Point(p.getX() + dx, p.getY()); // 这里不传递给调用程序 } 例外:需要注意性参的情况下方法参数的名字应使方法参数容易读取。特别是在与实例变量重复时,活用this,可以使参数的读取较为容易。反例: void reset( int x_, int y_) ... { x = x_; y = y_; } 正例: void reset( int x, int y) ... { // 不要将参数名取为 x_, y_ 等 this.x = x; this.y = y; } toString()toString()方法如果可能要随时封装。理由1:用System.out.println(object)可随时打印。理由2:如果在单元测试等(过程)中失败了,其显示容易被区分。switch, if/else的循环处理是不好的在用switch文进行分支处理的时候,要考虑到这是否为不良设计的征兆,同时还要考虑是否可以用多态性来实现。特别是有2个以上相同的switch时,一定要用多态性、FactoryMethod(工厂方法)、Prototype(原型)等来实现。if/else也是一样的。并且,如果同样的用于检查null的if很多,考虑采用NullObject类型。String和基本类型的变换从int到String的互逆变换,如下(其它基本类型也一样)String s = String.valueOf(i);int i = Integer.parseInt(s);理由:虽然有其它的方法,但上面的方法最易懂最有效。其它方法:(不推荐)String s = “” + i;String s = new Integer(i).toString();String s = Integer.toString(i); // 这样不好int i = new Integer(s).intValue();int i = Integer.valueOf(s).intValue(); collection如果环境允许,请使用JDK1.2以后的collection类。也就是说,不用Vector、Hashtable,Enumeration,而用List(ArrayList),Map(HashMap),Iterator。理由1:可以简洁地使用有逻辑、有连贯性的方法名。理由2:通运List,Set,Map接口,或不改变接口就能实现替换。理由3:由于有同步化的操作,可以写成高速的代码(有这样的可能性)。参考:JDK1.2 collection使用指南 http://www.objectclub.jp/technicaldoc/java/jdk 注释 javadoc的活用多用“/**注释*/”的注释。这样的注释,由与javadoc同样的工具可以变为HTML形式的文档。java的注释有3种类型。/** ... */ javadoc注释。输出为html形式的文档/* ... */ 一般的注释。内部的// 一般的注释。内部的public类,方法,域必须要加“/** ... */ ”的注释。长注释注释要跨多行时,应在最初用一句话概括,然后后面加长注释。javadoc标签(tag)“/** ... */ ”注释中,从“@”开始是关键字(javadoc标签)。@author author-name@param paramName description@return description of return value@exception exceptionName description@see string@see URL@see classname#methodnameparam, return有特别要注意之处,要进行主旨注释。如,用于输出的参数,被变更时。例1: /** */ /*** 取得边界框.** @param b 边界框(用于内存与速度效率,输出参数)*/ void getBBox(BBox b) ... { b.min = this.min; b.max = this.max; } 类注释“/** ... */ ”用于功能概要,也就是外部规格的描述,写在类方法的定义开始之前。这个注释的第一行有特别处理。即,被html的Method Index(方法目录)使用。因此,最开始的第一行是注释对象的外部功能的简短说明。这行以半角“.”或<br>HTML标签结束。接着第一行进行功能说明。如: /** */ /** * 表现堆的类. 堆为先进后出的数据结构. * <p> * 元素总数保存到count中,元素保存到Vector中. * * @see util.Vector * @author yourNameHere */ public class Stack ... { /** *//** * 当前的元素总数. 非负且小于capacity . */ protected int count; /** *//** * 取出上面的一个元素. 元素总数减1. * * <pre> * 使用例子: * Stack s = new Stack(10); * s.push(99); * int i = pop(); // i必须是99 * </pre> * * @return 上面的元素 */ public int pop() ...{ ... }} 在注释中,写“使用例子”等的时候,也可用<pre> </pre>围住自动进行缩排,以避免改行。// 和 /* */方法和类的内部的注释,是用“ /* */ ”还是“ // ”,可以根据注释的长度来判断。一行注释最好用“ // ”。例1: /**/ /** 戦略:* 1. まずnode を探す* 2. clone する* 3. inserter にclone を追加要請* 4. 成功したら,node を削除*/ 例2: int index = - 1 ; // -1 表示不合法 参考:这个方法最好。 static final int INVALID = - 1 ; int index = INVALID; Design by Contract (根据合同进行设计)因为要按照合同进行设计,所以在工程中添加Assert类。用Assert类来表现合同。如: class Stack ... { private int capacity; private int itemCount; public void push(Object o) ...{ Assert.require(o != null); // 事前条件 // ... // ... Assert.ensure(this.contains(o)); // 事后条件 } public boolean invariant() ...{ // 不变条件 Assert.invariant(0 <= capacity); Assert.invariant(0 <= itemCount); Assert.invariant(itemCount <= capacity); return true; }} 注意:用户输入检查等 不能进行assert。捕捉bug进行assert补充:在J2SE1.4以后,assert为关键字。 性能 首先进行检测性能的改善从检测开始。不能乱猜。new在java中new费时间。多重循环中调用new的时候,如需要,使用输出参数。 X getX() ... { return new X(this.value); } 上面代码比较慢时,让调用程序new,如下, void getX(X x) ... { x.setValue(this.value); } synchronizedsynchronized(同步的)费时间。不要同步化所有类,而只对必要的部分进行同步。再有,Vector, Hashtable有默认的同步化重载。最好使用ArrayList,HashMap对必要的部分进行同步。(用Collections.synchronizedCollection进行外部同步)为变量赋null值当有大量不使用的变量时,积极把它们设为null。特别是,数组的元素(对性能有严格要求的情况下)。理由:有利于垃圾回收处理(ガベージコレクション)。 其它 在自己重新编制前进行讨论别人创建的类中有时需要新的方法,若要自己继承(extends)该类来创创建新的类,或将该类作为实例变量作成类时,首先要与该类的作者商谈。如通用形式满足其要求,则可使用原来的类。复杂的设计不好设计有迷惑时,多数情况是注重‘Simplicyty’方法,或要与java语言的特性良好一致。java语言的设计原理是KISS(Keep It Small and Simple)。同时,在后面的维护中,“Simplicyty”也很重要。性能调整应在测试后没有编码从一开始就注意性能的。要优先保证易读、易维护。性能应在测试后进行改善。过于精巧的代码不好要写一般的java程序员都能理解的代码。要假定对于运算符的顺序、初始化的规则等,谁都不能肯定有自信,要用()明确运算顺序,进行明确的初始化,这样才易读。反例:return cond == 0 ? a < b && b < c : d == 1;正例:return (cond == 0) ? ((a < b) && (b < c)) : (d == 1);反例:// 写成单位行列,但费时间,谁也不好读。for (int i = 1; i <= N; i++) for (int j = 1; j <= N; j++) M[i-1][j-1] = (i/j)* (j/i);没有100%的正确这里所写的,并是100%作为标准。如有困惑要进行整理、讨论。常会有有充分理由不用规则的情况。本编码标准的目的是希望能对团结协作的团对有所帮助。 謝辞このコーディング標準をまとめるにあたって,太田健一郎さん,栗原哲也さん,高橋徹さん,小藪隆史さん,牛尾剛さん,井芹義博,山崎貴弘さんから有用なコメントを頂きました.ありがとうございました.参考資料Kenji Hiranabe, Java コーディング標準(オリジナル)http://www.objectclub.jp/community/codingstandard/CodingStd.docJeff Langr, Essential JAVA STYLE – Patterns for Implementation1999, Prentice HallDoug Lea’s Draft Java Coding Standardhttp://gee.cs.oswego.edu/dl/html/javaCodingStd.htmlMark Fussell’s Java Development Standardshttp://www.chimu.com/publications/javaStandards/index.htmlMacadamian Technology coding conventions for C++ and Javahttp://www.macadamian.com/codingconventions.htmAmbySoft Inc. Java Coding Standards, Elements of Java Stylehttp://www.ambysoft.com/essays/javaCodingStandards.htmlhttp://www.ambysoft.com/books/elementsJavaStyle.htmlJavasoft coding standardshttp://java.sun.com/docs/codeconv/html/CodeConvTOC.doc.html以上------------------------------------
以上为自己学习时译,仅供参考学习。如有译得不妥或解释不妥的地方,望您指出,以学习。其中红色部分为不理解或不会译的地方,有待学习。
谢谢!
——xiaohuaidan717