什么是java注释
要回答这个问题,先提出一个说法:我们写的代码是给人看的,不是给机器看的. 如果你不认可这个说法,下面关于代码注释的一些总结想必对你也没啥帮助. 如果你认可这个说法, 那么下面的文章希望会给你一些帮助.
回到本段的主题,什么是java注释呢?
首先,注释是面向代码维护者的: 注释是对代码逻辑的一段说明, 方便后续的代码维护者能够快速的了解这段代码的含义,并依次为基础能够在现有代码的基础上做修改与维护.
其次,注释是面向系统使用者的: 要知道类似于java,或者spring这样偏向于底层,框架类的代码.全世界有数以万计的使用者的,这些人没精力也没有必要在调用api的时候去了解这段代码的底层实现逻辑,所以这段代码的api说明文档就显得很重要了.而代码上的注释就是相关api文档的主要来源.
通过javadoc命令,可以将注释抽离生成html文档,比如官方的java16API文档
如何写好java注释
想要写好代码的注释,我们要从注释的面向用户来考虑.不同的用户关注点还是有点差异的.
面向代码维护者
作为一名代码的维护者,当我们拿到一份没有任何注释的代码的时候,相信大家内心的感受是相同的.毕竟人类的悲欢并不相通, 除非看到没有注释的代码.
如果有了解设计模式的朋友,相信一定听说过一个设计原则:开闭原则, 对扩展开发,对修改关闭. 那么大家有没有想过为啥会有这个原则呢?
翻译一下: 修改现有的代码是有风险的,但是如果是扩展写新代码的话,作为开发者的你,是了解当前功能的前后背景的,而且你无论怎么写都不会对历史功能产生影响.所以对我们的代码设计能力提出来要求.
再翻译一下: 原来的代码既然跑的好好的,为啥要修改它呢, 改出问题来算谁的?
再翻译一下: 为啥我们不敢改以前的代码呢?谁知道当时为啥要写这段逻辑,谁知道这段逻辑有谁在用?改好了没有夸, 改崩了有锅背.
这就是我们维护老代码的困境!
作为一名程序员,我们要有一个概念,我们的代码是我们某个时刻的思维逻辑的固化. 如果是一个比较简单的逻辑,注释可以简单写写. 如果是一段比较复杂的逻辑,那么我们的注释要能够描述清楚我们当时的这段逻辑的背景(为什么要写这段逻辑), 意图(这段逻辑要实现什么效果), 用法(这段逻辑改如何使用,以及谁在用), 最好能有修改建议.
在业界开源的代码里有很多比较好的例子,来个spring的:
/**
* AOP Alliance MethodInterceptor for declarative transaction
* management using the common Spring transaction infrastructure
* ({@link org.springframework.transaction.PlatformTransactionManager}/
* {@link org.springframework.transaction.ReactiveTransactionManager}).
*
* <p>Derives from the {@link TransactionAspectSupport} class which
* contains the integration with Spring's underlying transaction API.
* TransactionInterceptor simply calls the relevant superclass methods
* such as {@link #invokeWithinTransaction} in the correct order.
*
* <p>TransactionInterceptors are thread-safe.
*
* @author Rod Johnson
* @author Juergen Hoeller
* @see TransactionProxyFactoryBean
* @see org.springframework.aop.framework.ProxyFactoryBean
* @see org.springframework.aop.framework.ProxyFactory
*/
面向api使用者
对于api的使用者,注释文档的要求相对简单些.
他们只关心这个方法的功能是什么, 以及入参有哪些,出参会有哪些, 会不会抛异常等, 会不会返回null等. 他们不关心这个方法的内部实现逻辑是啥, 比如一个排序方法, 使用者不关心这个方法内部使用冒泡排序,还是快排, 只要能完成诉求就行.
所以,面向api的使用者的注释,原则就是让他知道这个方法怎么使用就行了.
/**
* Returns an Image object that can then be painted on the screen.
* The url argument must specify an absolute <a href="#{@link}">{@link URL}</a>. The name
* argument is a specifier that is relative to the url argument.
* <p>
* This method always returns immediately, whether or not the
* image exists. When this applet attempts to draw the image on
* the screen, the data will be loaded. The graphics primitives
* that draw the image will incrementally paint on the screen.
*
* @param url an absolute URL giving the base location of the image
* @param name the location of the image, relative to the url argument
* @return the image at the specified URL
* @see Image
*/
public Image getImage(URL url, String name) {
try {
return getImage(new URL(url, name));
} catch (MalformedURLException e) {
return null;
}
}
写好java注释常用的技巧
常用的注释tag
- @param 方法参数
- @return 方法返回值
- @throws 方法抛出的异常, java1.2后添加
- @exception 同@throws
- @see 查看参考代码
- @author 标识作者
- @version 代码版本
- @since 从某个版本开始引入
- @serial( @serialField @serialData)
- @deprecated 废弃某个版本的代码
常用的内联tag
- {@code} : 代码高亮,等同于
{@literal}
<code>{@literal}</code>
- {@docRoot} : 标记文档的根路径,用来实现相对路径
/** * See the <ahref="{@docRoot}/copyright.html">Copyright</a>. */
- {@inheritDoc} : 继承某个文档,嵌套文档使用
- {@link url} : 在注释文本区域内, 内联一个链接 ``` Use the {@link #getComponentAt(int, int) getComponentAt} method.
5. {@linkplain url label} 相对于{@link}, 支持自定义label文案来代指这段url
Refer to {@linkplain add() the overridden method}. 会显示为 Refer to ‘the overridden method’.
6. {@literal} 转义用, 方便显示一些特殊字符
7. {@value} 常量时, 会直接显示标注代码的值
### 注释语句中的小技巧
#### @param @return @throws
一个正常方法必然会用到的注释tag,
@param 代表方法的入参,
@return 代表方法的返回值.
@throws 代表可能引发方法中断的异常. 等同与 @exception
这里需要特别说明一下, 有些人可能觉得只有那些受检异常(也就是必须在方法签名里声明的异常)才需要在注释里声明@throws. 其实不是的. 所有引发程序中断的异常, 包括运行时异常都可以在注释里说明, 也可以在方法签名里添加. 尤其是自定义的异常.
举个例子:
```java
/**
* Return the underlying ThreadPoolExecutor for native access.
* @return the underlying ThreadPoolExecutor (never {@code null})
* @throws IllegalStateException if the ThreadPoolTaskExecutor hasn't been initialized yet
*/
public ThreadPoolExecutor getThreadPoolExecutor() throws IllegalStateException {
Assert.state(this.threadPoolExecutor != null, "ThreadPoolTaskExecutor not initialized");
return this.threadPoolExecutor;
}
这里的IllegalStateException 是一个RuntimeException异常, 我们在方法里可能抛出这个异常, 最好是在方法签名里声明一下, 然后在代码注释里说明一下.
@see
当前代码可以参考的其他代码, 后面跟代码的全路径,可以是类,方法,属性等.具体参考如下:
@see #field
@see #Constructor(Type, Type...)
@see #Constructor(Type id, Type id...)
@see #method(Type, Type,...)
@see #method(Type id, Type, id...)
@see Class
@see Class#field
@see Class#Constructor(Type, Type...)
@see Class#Constructor(Type id, Type id)
@see Class#method(Type, Type,...)
@see Class#method(Type id, Type id,...)
@see package.Class
@see package.Class#field
@see package.Class#Constructor(Type, Type...)
@see package.Class#Constructor(Type id, Type id)
@see package.Class#method(Type, Type,...)
@see package.Class#method(Type id, Type, id)
@see package
@author
标识当前代码的作者是谁, 可以一个,也可以有多个.
@version @since
都是版本相关的tag @version 标识当前版本好, 编译的时候会用到. 符合SCCS规范. @since 标识这段代码的引入版本
@serial @serialField @serialData
序列化相关的属性, 标识哪些字段可以序列化,哪些不行.
@deprecated
废弃某段代码,表示不再维护,并在一段时间后会被删除. 标记后, 相关的引用位置会被标记为删除线. 个人认为这个tag还是很有用的:
- 创建代码容易删除难, 这个tag能够很好的帮忙我们去下线不再维护的代码,减轻维护压力.(愿世界上屎山越来越少)
- 方便我们代码升级. 如果我们要升级一段代码,先将老代码废弃,然后通过@see,引导用户使用新的方法.
/**
* @deprecated As of JDK 1.1, replaced by
*
setBounds
* @see #setBounds(int,int,int,int)
*/
html标签来排版
<p> : 新起一段
<br> : 换行
代码块样式
想在JAVA的注释中添加一段代码,并且可以优雅的编译出来还是挺麻烦的.下面提供一种方法
/**
* 下面的代码注释可以按代码格式编译
* <pre class=code>
* citys : [
* beijing,
* shanghai
* ]
* </pre>
*
*/
private List<String>> citys;
参考
官方文档 javadoc - The Java API Documentation Generator How and When To Deprecate APIs
文档信息
- 本文作者:寒澈
- 本文链接:https://www.hancher.top/2022/09/01/java_doc_skill/
- 版权声明:自由转载-非商用-非衍生-保持署名(创意共享3.0许可证)