只有代码能告诉你它做的事,那是唯一真正准确的信息来源。
注释是弥补在用代码表达意图时遭遇的失败。
尽管有时也需要注释,我们也该多花心思尽量减少注释量。
好注释
有些注释是必须的,也是有利的。不过要记住,唯一真正好的注释是想办法不去写的注释
1、法律信息
// Copyright (C) 2003,2004,2005 by Object Mentor, Inc. All rights reserved. // Released under the terms of the GNU General Public License version 2 or later.
公司代码规范要求编写与法律有关的注释。
2、提供信息的注释
//Returns an instance of the Responder being tested. protected abstact Responder responderInstance();
这类注释有时管用,但是更好的方式是尽量利用函数名称传达信息。比如,把函数重命名为responderBeingTested。
3、对意图的解释
//we are greater because we are the right type.
//This is our best attempt to get a race condition by creating large number of threads.
不仅提供了有关实现的有用信息,而且还提供了某个决定后面的意图。
4、阐释
assertTrue(a.compareTo(a) == 0); //a == a assertTrue(a.compareTo(b) != 0); //a != b assertTrue(ab.compareTo(ab) == 0); //ab == ab assertTrue(a.compareTo(b) == -1); //a < b assertTrue(aa.compareTo(ab) == -1); //aa < ab assertTrue(ba.compareTo(bb) == -1); //ba < bb assertTrue(b.compareTo(a) == 1); //b > a assertTrue(ab.compareTo(aa) == 0); //a == a assertTrue(bb.compareTo(ba) == 0); //a == a
把某些晦涩难明的参数或返回值的意义翻译为某种可读形式。这也会冒阐释性注释本身就不正确的风险。
5、警示
//Don't run unless you have some time to kiill.
//SimpleDateFormat is not thread safe, so we need to create each instance independently.
警告其他程序员会出现某种后果
6、TODO注释
//TODO-MdM these are not needed We expect this to go away when we do the checkout model.
//TODO形式在源代码中放置要做的工作列表
7、放大
// the trim is real important. It removes the starting spaces that could cause the item to be recognized as another list.
用来放大某种看来不合理之物的重要性。
坏注释
是糟糕的代码的支撑或借口,或者对错误决策的修正,基本上等于程序员自说自话。
1、喃喃自语
try { ... } catch (IOException e) { // No properties files means all defaults are loaded }
这段注释是什么意思?或许只有作者知道。
2、多余的注释
对于一些简单函数,其头部位置的注释全属多余。读这些注释花的时间没准比读代码花的时间还要长。
3、误导性注释
细微的误导信息,放在比代码本身更难阅读的注释里面,有可能导致其他程序员快活地调用并使自己陷于调试困境之中。
4、循规式注释
不要公式化的给每个函数或每个变量添加注释。
5、日志式注释
很久以前,在模块开始处创建并维护这些记录还算有道理。那时,我们还没有源代码控制系统可用。
* Changes (from 11-Oct-2001) * -------------------------------- * 11-Oct-2001 : Re-organised the class and moved it to new package; * 05-Nov-2001 : Added a getDescription() method, and eliminated NotableDate class; * 12-Nov-2001 : IBD requires setDescription() method, now that NotableDate class is gone;
/* Added by Rick */
如今,这种冗长的记录只会让模块变得凌乱不堪,应当全部删除。修改日志、作者这类注释就应该交给源代码控制系统。
6、废话注释
/** * Default constructor. */ protected AnnualDateRule() { }
/** The name. */ private String name; /** The version. */ private String version; /** The licenceName. */ private String licenceName; /** The version. */ private String info;
这类注释,我们会视而不见,更可怕的是剪切-粘贴错误,作者在写注释时都没花心思,怎么能指望读者从中获益呢?
7、能用函数或变量时就别用注释
// does the module from the global list <mod> depend on the subsystem we are part of? if (smodule.getDependSubsystems().contains(subSysMod.getSubSystem()))
可以改成以下没有注释的版本
ArrayList moduleDependees = smodule.getDependSubsystems(); String ourSubSystem = subSysMod.getSubSystem(); if (moduleDependees.contains(ourSubSystem))
先写注释再写代码,然后经过一次重构把注释去掉。
8、位置标记
// Actions //
在源代码中标记某个特别位置,如果标记栏不多,效果还是显而易见。如果滥用标记栏,就会沉没在背景噪音中,被忽略掉。
9、括号后面的注释
public class wc { public static void main(String[] args) { ... try { while ((line = in.readLine()) != null) { ... } // while ... } // try catch (IOException e) { ... } // catch } // main }
在括号后面放置特殊的注释,尽管这对于含有深度嵌套结构的长函数可能有意义。如果发现自己想标记右括号,其实应该做的是缩短函数。
10、注释掉的代码
有源代码控制系统,无需再用注释来标记,删掉即可,它们丢不了。
11、非本地信息
假如一定要写注释,请确保它描述了离它最近的代码。别在本地注释的上下文环境中给出系统级的信息。
12、信息过多
别在注释中添加有趣的历史性话题或者无关的细节描述
13、不明显的联系
注释及其描述的代码之间的联系应该显而易见。如果不嫌麻烦要写注释,至少让读者能看着注释和代码,并且理解注释所谈何物
/* * start with an array that is big enough to hold all the pixels * (plus filter bytes), and an extra 200 bytes for header info */ this.pngBytes = new byte[((this.width + 1) * this.height * 3) + 200];
过滤器字节是什么?与那个+1有关系吗?或与*3有关?还是与两者皆有关?为什么用200?注释的作用是解释未能自行解释的代码。如果注释本身还需要解释,就太遗憾了。