悬挂缩进什么意思(论文参考文献悬挂缩进什么意思)

一.最佳做法注释应该陈述代码的高级意图,而不是显而易见的细节。反例 /** * generate signature by code, the algorith

一.最佳做法

注释应该陈述代码的高级意图,而不是显而易见的细节。

反例

/** * generate signature by code, the algorithm is as follows: * 1.sort the http params, if you use java, you can easily use treeMap data structure * 2.join the param k-v * 3.use hmac-sha1 encrypt the specified string * * @param params request params * @param secret auth secret * @return secret sign * @throws Exception exception */ public static String generateSignature(Map<String, Object> params, String secret) throws Exception { final StringBuilder paramStr = new StringBuilder(); final Map<String, Object> sortedMap = new TreeMap<>(params); for (Map.Entry<String, Object> entry : sortedMap.entrySet()) { paramStr.append(entry.getKey()); paramStr.append(entry.getValue()); } Mac hmac = Mac.getInstance("HmacSHA1"); SecretKeySpec sec = new SecretKeySpec(secret.getBytes(), "HmacSHA1"); hmac.init(sec); byte[] digest = hmac.doFinal(paramStr.toString().getBytes()); return new String(new Hex().encode(digest), "UTF-8"); }

解释

上面的方法是用来根据参数生成签名的,评论里详细描述了签名算法的实现步骤,实际上是过度描述了代码明显的细节。

正面例子

/** * generate signature by params and secret, used for computing signature for http request. * * @param params request params * @param secret auth secret * @return secret sign * @throws Exception exception */ public static String generateSignature(Map<String, Object> params, String secret) throws Exception { final StringBuilder paramStr = new StringBuilder(); final Map<String, Object> sortedMap = new TreeMap<>(params); for (Map.Entry<String, Object> entry : sortedMap.entrySet()) { paramStr.append(entry.getKey()); paramStr.append(entry.getValue()); } Mac hmac = Mac.getInstance("HmacSHA1"); SecretKeySpec sec = new SecretKeySpec(secret.getBytes(), "HmacSHA1"); hmac.init(sec); byte[] digest = hmac.doFinal(paramStr.toString().getBytes()); return new String(new Hex().encode(digest), "UTF-8"); }

摘要

注释一定是表达代码之外的东西,代码可以包含的内容,注释中一定不要出现如果有必要注释,请注释意图(why),而不要去注释实现(how),大家都会看代码

在文件/类级别使用全局注释来解释所有部分是如何工作的。

正面例子

/** * <p> * Helpers for {@code java.lang.System}. * </p> * <p> * If a system property cannot be read due to security restrictions, the corresponding field in this class will be set * to {@code null} and a message will be written to {@code System.err}. * </p> * <p> * #ThreadSafe# * </p> * * @since 1.0 * @version $Id: SystemUtils.java 1583482 2014-03-31 22:54:57Z niallp $ */public class SystemUtils {}

摘要

通常,每个文件或类都应该有一个全局注释来概括该类的角色。

公共api需要添加注释,其他代码慎用注释。

反例

/** * * @author yzq * @date 2017 */public interface KeyPairService { PlainResult<KeyPairInfoModel> createKeyPair(KeyPairCreateParam createParam);}

解释

上述接口提供的Dubbo rpc服务属于公共api,以双方包的形式提供给调用者,虽然代码简单,缺乏接口大纲描述、方法注释等基本信息。

正面例子

/** * dubbo service: key pair rpc service api. * * @author yzq * @date 2017/02/22 */public interface KeyPairService { /** * create key pair info. * * @param createParam key pair create param * @return BaseResult */ PlainResult<KeyPairInfoModel> createKeyPair(KeyPairCreateParam createParam);}

摘要

公共api必须有注释,类文件使用类注释,公共接口方法使用方法注释。

在评论中用精心挑选的输入和输出例子来解释。

正面例子

/** * <p>Checks if CharSequence contains a search character, handling {@code null}. * This method uses {@link String#indexOf(int)} if possible.</p> * * <p>A {@code null} or empty ("") CharSequence will return {@code false}.</p> * * <pre> * StringUtils.contains(null, *) = false * StringUtils.contains("", *) = false * StringUtils.contains("abc", 'a') = true * StringUtils.contains("abc", 'z') = false * </pre> * * @param seq the CharSequence to check, may be null * @param searchChar the character to find * @return true if the CharSequence contains the search character, * false if not or {@code null} string input * @since 2.0 * @since 3.0 Changed signature from contains(String, int) to contains(CharSequence, int) */ public static boolean contains(final CharSequence seq, final int searchChar) { if (isEmpty(seq)) { return false; } return CharSequenceUtils.indexOf(seq, searchChar, 0) >= 0; }

摘要

为公共方法提供输入和输出的例子,尤其是通用工具方法,往往比任何语言都强大。

注释必须描述最接近它的代码。

反例

private Map<String, String> buildInstanceDocumentMap(String version, String instanceId) { Map<String, String> instanceDocumentMap = Maps.newLinkedHashMap(); Map<String, String> instanceDocumentMapMetadataPart = metaDataService.getInstanceDocument(instanceId, version, instanceDocumentMetaKeys); instanceDocumentMap.putAll(instanceDocumentMapMetadataPart); //the map must remove the old key for instance type instanceDocumentMap.put("instance-type", instanceDocumentMap.get("instance/instance-type")); instanceDocumentMap.remove("instance/instance-type"); return instanceDocumentMap; }

解释

该方法有一行从地图中删除数据的代码,注释放在put调用之前,但不直接放在remove之前。

正面例子

private Map<String, String> buildInstanceDocumentMap(String version, String instanceId) { Map<String, String> instanceDocumentMap = Maps.newLinkedHashMap(); Map<String, String> instanceDocumentMapMetadataPart = metaDataService.getInstanceDocument(instanceId, version, instanceDocumentMetaKeys); instanceDocumentMap.putAll(instanceDocumentMapMetadataPart); instanceDocumentMap.put("instance-type", instanceDocumentMap.get("instance/instance-type")); //the map must remove the old key for instance type instanceDocumentMap.remove("instance/instance-type"); return instanceDocumentMap; }

摘要

注释应放在离其描述代码最近的位置。

注释必须与代码相对应。

反例

/** * 根据hash过后的id生成指定长度的随机字符串, 且长度不能超过16个字符 * * @param len length of string * @param id id * @return String */ public static String randomStringWithId(int len, long id) { if (len < 1 || len > 32) { throw new UnsupportedOperationException("can't support to generate 1-32 length random string"); } //use default random seed StringBuffer sb = new StringBuffer(); long genid = id; for (int i = 0; i < len; i++) { long pos = genid%32 ; genid = genid>>6; sb.append(RANDOM_CHAR[(int) pos]); } return sb.toString(); }

解释

注释中写明生成的随机字符串长度不能超过16个字符,但实际代码已经修改为32个字符。这里的注释会产生误导读者的副作用。

正面例子

/** * 根据hash过后的id生成指定长度的随机字符串 * * @param len length of string * @param id id * @return String */ public static String randomStringWithId(int len, long id) { if (len < 1 || len > 32) { throw new UnsupportedOperationException("can't support to generate 1-32 length random string"); } //use default random seed StringBuffer sb = new StringBuffer(); long genid = id; for (int i = 0; i < len; i++) { long pos = genid%32 ; genid = genid>>6; sb.append(RANDOM_CHAR[(int) pos]); } return sb.toString(); }

摘要

注释一定要与代码对应,通常代码变化对应的注释也要随之改变若非必要慎用注释,注释同代码一样需要维护更新

一定要注释常量。

反例

/** * define common constants for ebs common component. * * Author: yzq Date: 16/7/12 Time: 17:44 */public final class CommonConstants { /** * keep singleton */ private CommonConstants() {} public static final String BILLING_BID = "26842"; public static final int BILLING_DOMAIN_INTEGRITY_VALID = 1; public static final int BILLING_READYFLAG_START = 0;}

正面例子

/** * define common constants for ebs common component. * * Author: yzq Date: 16/7/12 Time: 17:44 */public final class CommonConstants { /** * keep singleton */ private CommonConstants() {} /** * oms client bid. */ public static final String BILLING_BID = "26842"; /** * oms billing domain integrity true. */ public static final int BILLING_DOMAIN_INTEGRITY_VALID = 1; /** * oms billing readyflag start. */ public static final int BILLING_READYFLAG_START = 0;}

摘要

给每一个常量加一个有效的注释

用聪明的标记(TODO,FIXME,HACK)

TODO 有未完成的事项FIXME 代码有已知问题待修复HACK 表示代码有hack逻辑

例子

public static String randomStringWithId(int len, long id) { // TODO: 2018/6/11 需要将len的合法范围抽象 if (len < 1 || len > 32) { throw new UnsupportedOperationException("can't support to generate 1-32 length random string"); } //use default random seed StringBuffer sb = new StringBuffer(); long genid = id; for (int i = 0; i < len; i++) { long pos = genid%32 ; genid = genid>>6; sb.append(RANDOM_CHAR[(int) pos]); } return sb.toString(); }

配置标记

您可以扩展IDE来修改标记的配置,例如添加诸如解算器和相关缺陷之类的信息。以IDEA为例,修改条目如下:

代码整洁之道——优雅注释之道

摘要

巧用TODO、FIXME、HACK等注解标识代码及时处理所有标识代码,忌滥用

添加适当的警告注释。

正面例子

private BaseResult putReadyFlag(BillingDataContext context, Integer readyFlag) { // warn! oms data format require List<Map<String,String>> and the size of it must be one. List<Map<String, String>> dataList = Lists.newArrayListWithExpectedSize(1); }

解释

该方法创建固定大小1和类型的地图

摘要

代码中偶尔会出现一些非常黑的逻辑,修改会造成很高的风险。这时候就需要添加评论来强调了。

注释代码

反例

private Object buildParamMap(Object request) throws Exception { if (List.class.isAssignableFrom(request.getClass())) { List<Object> input = (List<Object>)request; List<Object> result = new ArrayList<Object>(); for (Object obj : input) { result.add(buildParamMap(obj)); } return result; } Map<String, Object> result = new LinkedHashMap<String, Object>(); Field[] fields = FieldUtils.getAllFields(request.getClass()); for (Field field : fields) { if (IGNORE_FIELD_LIST.contains(field.getName())) { continue; } String fieldAnnotationName = field.getAnnotation(ProxyParam.class) != null ? field.getAnnotation( ProxyParam.class).paramName() : HttpParamUtil.convertParamName(field.getName()); //Object paramValue = FieldUtils.readField(field, request, true); //if (paramValue == null) { // continue; //} // //if (BASIC_TYPE_LIST.contains(field.getGenericType().getTypeName())) { // result.put(fieldAnnotationName, String.valueOf(paramValue)); //} else { // result.put(fieldAnnotationName, this.buildParamMap(paramValue)); //} } return result; }

解释

常用的例程,为了方便重用废弃的代码,直接注释掉。

正面例子

同上,删除评论代码。

摘要

不要在代码中留下任何注释代码,不要把Git等版本管理软件能做的事情放到代码中。

常规注释

反例

/** * 类EcsOperateLogDO.java的实现描述:TODO 类实现描述 * * @author xxx 2012-12-6 上午10:53:21 */public class DemoDO implements Serializable { private static final long serialVersionUID = -3517141301031994021L; /** * 主键id */ private Long id; /** * 用户uid */ private Long aliUid; /** * @return the id */ public Long getId() { return id; } /** * @param id the id to set */ public void setId(Long id) { this.id = id; } /** * @return the aliUid */ public Long getAliUid() { return aliUid; } /** * @param aliUid the aliUid to set */ public void setAliUid(Long aliUid) { this.aliUid = aliUid; }}

解释

对上述代码的分析表明,有两个注释是笨拙和多余的:

类注释使用了默认模版, 填充了无效信息IDE为Getter及Setter方法生成了大量的无效注释

正面例子

/** * Demo model. * @author xxx 2012-12-6 上午10:53:21 */public class DemoDO implements Serializable { private static final long serialVersionUID = -3517141301031994021L; /** * 主键id */ private Long id; /** * 用户uid */ private Long aliUid; public Long getId() { return id; } public void setId(Long id) { this.id = id; } public Long getAliUid() { return aliUid; } public void setAliUid(Long aliUid) { this.aliUid = aliUid; }}

摘要

不要保留任何循规蹈矩式注释,比如IDE自动生成的冗余注释不要产生任何该类注释,可以统一配置IDE达到该效果,推荐使用灵狐插件

日志注释

反例

/** 支持xxx code by xxx 2015/10/11 */ String countryCode = param.getCountyCode(); if(StringUtils.isNotBlank(countryCode) && !"CN".equals(countryCode)){ imageOrderParam.setCountyCode(param.getCountyCode()); imageOrderParam.setCurrency(param.getCurrency()); }

解释

修改已有代码,很多人会手动添加注释,说明修改日期、修改人、修改描述等信息,大多是多余的。

正面例子

代码同上,删除此评论。

摘要

不要在代码中加入代码的文字信息,不要在代码中做版本管理能完成的事情。

“拐杖上的笔记”

反例

/** * update config map, if the config map is not exist, create it then put the specified key and value, then return it * @param key config key * @param value config value * @return config map */ public Map<String, String> updateConfigWithSpecifiedKV(final String key, final String value) { if (StringUtils.isNotBlank(key) || StringUtils.isNotBlank(value)) { return Maps.newHashMap(); } Map<String, String> config = queryConfigMap(); if (MapUtils.isEmpty(config)) { return new HashMap<String, String>() {{ put(key, value); }}; } config.put(key, value); return config; }

解释

该代码简单地实现了更新指定的map k-v的函数。如果目标map不存在,它用指定的k-v初始化map并返回它。方法名为updateConfigWithSpecifiedKV。为了说明该方法的完整意图,注释描述了该方法的实现逻辑。

正面例子

/** * create or update config map with specified k-v. * * @param value config value * @return config map */ public Map<String, String> createOrUpdateConfigWithSpecifiedKV(final String key, final String value) { if (StringUtils.isNotBlank(key) || StringUtils.isNotBlank(value)) { return Maps.newHashMap(); } Map<String, String> config = queryConfigMap(); if (MapUtils.isEmpty(config)) { return new HashMap<String, String>() {{ put(key, value); }}; } config.put(key, value); return config; }

摘要

抛弃“拐杖笔记”,不要给不好的名字加笔记。好名字比好笔记更重要。

过多的html注释

反例

/** * used for indicate the field will be used as a http param, the http request methods include as follows: * <li>Get</li> * <li>Post</li> * <li>Connect</li> * * the proxy param will be parsed, see {@link ProxyParamBuilder}. * * @author yzq * @date 2017/12/08 */@Target(ElementType.FIELD)@Retention(RetentionPolicy.RUNTIME)@Documentedpublic @interface ProxyParam { /** * the value indicate the proxy app name, such as houyi. * * @return proxy app name */ String proxyApp() default "houyi"; /** * proxy request mapping http param. * * @return http param */ String paramName(); /** * the value indicate if the param is required. * * @return if this param is required */ boolean isRequired() default true;}

解释

类标注用了很多html标签来描述,实际效果并没有带来好处反而增加了阅读难度。

正面例子

/** * used for indicate the field will be used as a http param. * * @author yzq * @date 2017/12/08 */@Target(ElementType.FIELD)@Retention(RetentionPolicy.RUNTIME)@Documentedpublic @interface ProxyParam { /** * the value indicate the proxy app name, such as houyi. * * @return proxy app name */ String proxyApp() default "houyi"; /** * proxy request mapping http param. * * @return http param */ String paramName(); /** * the value indicate if the param is required. * * @return if this param is required */ boolean isRequired() default true;}

摘要

普通业务注释谨慎使用html标签,它不会给你带来明显收益,只会徒增阅读难度如果是公共api且用于生成javadoc可以考虑加入必要的html标签,比如链接,锚点等

二、编程语言注释练习

爪哇

文件/类注释规范

目前,安装令狐后,IDE会自动将IDE的文件模板配置成以下格式:

/** * @author ${USER} * @date ${YEAR}/${MONTH}/${DAY} */

_ _强烈建议使用上述配置。统一简洁是最好的。_ _如果有特殊需求,需要自定义班级评论,请参考下图:

代码整洁之道——优雅注释之道

方法注释

/** * xxx * * @param * @param * @return * @throws */

IDE提供统一的方法注释模板,无需手动配置。一个好的方法注释应该包括以下内容:

方法的描述,重点描述该方法用来做什么,有必要可以加一个输入输出的例子参数描述返回值描述异常描述

例如:

/** * Converts a <code>byte[]</code> to a String using the specified character encoding. * * @param bytes * the byte array to read from * @param charsetName * the encoding to use, if null then use the platform default * @return a new String * @throws UnsupportedEncodingException * If the named charset is not supported * @throws NullPointerException * if the input is null * @deprecated use {@link StringUtils#toEncodedString(byte[], Charset)} instead of String constants in your code * @since 3.1 */ @Deprecated public static String toString(final byte[] bytes, final String charsetName) throws UnsupportedEncodingException { return charsetName != null ? new String(bytes, charsetName) : new String(bytes, Charset.defaultCharset()); }

块注释和行注释

单行代码注释使用行注释 //多行代码注释使用块注释 /* */

计算机编程语言

文件注释

重点描述文件的作用及使用方式#!/usr/bin/python# -*- coding: UTF-8 -*-"""bazaar script collection.init_resource_entry, used for init bazaar resource such as vpc, vsw, sg, proxy ecs and so on.user manual:1. modify ecs.conf config your key, secret, and region.2. run bazaar_tools.py script, this process will last a few minutes,then it will generate a init.sql file.3. use idb4 submit your ddl changes."""

类注释

""" ecs sdk client, used for xxx. Attributes: client: access_key: access_secret: region: """类应该在其定义下有一个用于描述该类的文档字符串类公共属性应该加以描述

函数注释

def fetch_bigtable_rows(big_table, keys, other_silly_variable=None): """Fetches rows from a Bigtable. Retrieves rows pertaining to the given keys from the Table instance represented by big_table. Silly things may happen if other_silly_variable is not None. Args: big_table: An open Bigtable Table instance. keys: A sequence of strings representing the key of each table row to fetch. other_silly_variable: Another optional variable, that has a much longer name than the other args, and which does nothing. Returns: A dict mapping keys to the corresponding table row data fetched. Each row is represented as a tuple of strings. For example: {'Serak': ('Rigel VII', 'Preparer'), 'Zim': ('Irk', 'Invader'), 'Lrrr': ('Omicron Persei 8', 'Emperor')} If a key from the keys argument is missing from the dictionary, then that row was not found in the table. Raises: IOError: An error occurred accessing the bigtable.Table object. """ passArgs:列出每个参数的名字, 并在名字后使用一个冒号和一个空格, 分隔对该参数的描述.如果描述太长超过了单行80字符,使用2或者4个空格的悬挂缩进(与文件其他部分保持一致). 描述应该包括所需的类型和含义. 如果一个函数接受*foo(可变长度参数列表)或者**bar (任意关键字参数), 应该详细列出*foo和**bar.Returns: 描述返回值的类型和语义. 如果函数返回None, 这一部分可以省略Raises:列出与接口有关的所有异常

多行注释和行尾注释

# We use a weighted dictionary search to find out where i is in# the array. We extrapolate position based on the largest num# in the array and the array size and then do binary search to# get the exact number.if i & (i-1) == 0: # true iff i is a power of 2复杂操作多行注释描述比较晦涩的代码使用行尾注释

开发

行注释

常见注释样式

包注释

/* */通常用于包注释,以整体提供该包的相应信息。每个包应该包含一个doc.go来描述它的信息。

/* ecs OpenApi demo,use aliyun ecs sdk manage ecs, this package will provide you function list as follows: DescribeInstances, query your account ecs. CreateInstance, create a ecs vm with specified params. */package ecsproxy

Java Script语言

常用的/* */和//,用法基本和Java一样。

仅支持#号,并且每个文件包含一个顶级注释来解释版权和摘要信息。

其他的

有待完善

总结

本文首先总结了编程中注释的最佳实践场景并举例说明,然后提供了一些注释模板和与不同编程语言规范相关的实践技巧。我个人对注释的理解是,注释是代码,注释是文档,写好注释是一个工程师必备的素质之一。在代码整洁的前提下,较少的注释是跟上高标准的追求。注释的做法暂时写到这里,以后会继续完善。也欢迎大家提供好的提示。本文中的大部分代码来自日常的业务项目,也有一部分摘自开源库。有不对的地方请指正。

免责声明:本站所有文章内容,图片,视频等均是来源于用户投稿和互联网及文摘转载整编而成,不代表本站观点,不承担相关法律责任。其著作权各归其原作者或其出版社所有。如发现本站有涉嫌抄袭侵权/违法违规的内容,侵犯到您的权益,请在线联系站长,一经查实,本站将立刻删除。

作者:美站资讯,如若转载,请注明出处:https://www.meizw.com/n/54100.html

发表回复

登录后才能评论