JEP 467:Markdown 文档注释
概括
允许以 Markdown 格式编写 JavaDoc 文 档注释,而不是仅以 HTML 和 JavaDoc@
标签的混合格式编写。
目标
-
通过引入在文档注释中使用 Markdown 语法以及 HTML 元素和 JavaDoc 标记的功能,使 API 文档注释以源代码形式更易于编写和阅读。
-
不要对现有文档注释的解释产生不利影响。
-
扩展编译器树 API,以启用其他分析文档注释的工具来处理这些注释中的 Markdown 内容。
非目标
- 实现现有文档注释自动转换为 Markdown 语法并不是我们的目标。
动机
文档注释是出现在源代码中的程式化注释,靠近它们用于记录的声明。 Java 源代码中的文档注释使用 HTML 和自定义 JavaDoc标记的组合来标记文本。
1995 年选择 HTML 作为标记语言是合理的。HTML 功能强大、标准化,并且在当时非常流行。但是,尽管如今作为 Web 浏览器使用的标记语言,HTML 的受欢迎程度丝毫不减,但自 1995 年以来,HTML 作为人类手动生成的标记已经变得不那么受欢迎了,因为它编写起来乏味且难以阅读。如今,它更常 见的是从其他一些更适合人类的标记语言生成的。因为 HTML 写起来很乏味,所以格式良好的文档注释写起来也很乏味,甚至更乏味,因为许多新开发人员由于 HTML 作为人类生成的格式的衰落而不能流利地使用 HTML。
内联JavaDoc标签,例如{@link}
和{@code}
,也很麻烦,开发人员更不熟悉,常常需要作者查阅文档来了解它们的用法。最近对 JDK 源代码中的文档注释的分析表明,超过 95% 的内联标记用于代码片段和文档中其他位置的链接,这表明这些结构的更简单形式将受到欢迎。
Markdown是一种流行的简单文档标记语言,易于阅读、易于编写并且易于转换为 HTML。文档注释通常不是复杂的结构化文档,对于文档注释中通常出现的结构(例如段落、列表、样式文本和链接),Markdown 提供了比 HTML 更简单的形式。对于 Markdown 不直接支持的那些结构,Markdown 也允许使用 HTML。
引入在文档注释中使用 Markdown 的功能将结合两个世界的优点。它将允许最常见结构的简洁语法,并减少对 HTML 标记和 JavaDoc 标签的需求,同时保留使用专用标签来实现 Markdown 中不可用的功能的能力。它将使源代码中的文档注释更容易编写和阅读,同时保留生成与以前相同类型的生成 API 文档的能力。
描述
作为在文档注释中使用 Markdown 的示例,请考虑java.lang.Object.hashCode的注释:
/**
* Returns a hash code value for the object. This method is
* supported for the benefit of hash tables such as those provided by
* {@link java.util.HashMap}.
* <p>
* The general contract of {@code hashCode} is:
* <ul>
* <li>Whenever it is invoked on the same object more than once during
* an execution of a Java application, the {@code hashCode} method
* must consistently return the same integer, provided no information
* used in {@code equals} comparisons on the object is modified.
* This integer need not remain consistent from one execution of an
* application to another execution of the same application.
* <li>If two objects are equal according to the {@link
* #equals(Object) equals} method, then calling the {@code
* hashCode} method on each of the two objects must produce the
* same integer result.
* <li>It is <em>not</em> required that if two objects are unequal
* according to the {@link #equals(Object) equals} method, then
* calling the {@code hashCode} method on each of the two objects
* must produce distinct integer results. However, the programmer
* should be aware that producing distinct integer results for
* unequal objects may improve the performance of hash tables.
* </ul>
*
* @implSpec
* As far as is reasonably practical, the {@code hashCode} method defined
* by class {@code Object} returns distinct integers for distinct objects.
*
* @return a hash code value for this object.
* @see java.lang.Object#equals(java.lang.Object)
* @see java.lang.System#identityHashCode
*/
可以通过在 Markdown 中表达其结构和样式来编写相同的注释,而不使用 HTML,仅使用一些 JavaDoc 内联标记:
/// Returns a hash code value for the object. This method is
/// supported for the benefit of hash tables such as those provided by
/// [java.util.HashMap].
///
/// The general contract of `hashCode` is:
///
/// - Whenever it is invoked on the same object more than once during
/// an execution of a Java application, the `hashCode` method
/// must consistently return the same integer, provided no information
/// used in `equals` comparisons on the object is modified.
/// This integer need not remain consistent from one execution of an
/// application to another execution of the same application.
/// - If two objects are equal according to the
/// [equals][#equals(Object)] method, then calling the
/// `hashCode` method on each of the two objects must produce the
/// same integer result.
/// - It is _not_ required that if two objects are unequal
/// according to the [equals][#equals(Object)] method, then
/// calling the `hashCode` method on each of the two objects
/// must produce distinct integer results. However, the programmer
/// should be aware that producing distinct integer results for
/// unequal objects may improve the performance of hash tables.
///
/// @implSpec
/// As far as is reasonably practical, the `hashCode` method defined
/// by class `Object` returns distinct integers for distinct objects.
///
/// @return a hash code value for this object.
/// @see java.lang.Object#equals(java.lang.Object)
/// @see java.lang.System#identityHashCode
(出于本示例的目的,故意避免了诸如重排文本之类的外观更改,以帮助进行前后比较。)
需要观察的主要差异:
-
Markdown 的使用是通过一种新形式的文档注释来表示的,其中每行都以 开头,
///
而不是传统的/**
...
*/
语法。 -
HTML
<p>
元素不是必需的;空行表示段落分隔符。 -
HTML
<ul>
和<li>
元素被 Markdown 项目符号列表标记替换,用于-
指示列表中每个项目的开头。 -
HTML
<em>
元素被替换为使用下划线 (_
) 来指示字体更改。 -
标记的实例
{@code ...}
由反引号 ( ) 替换`...`
以指示等宽字体。 -
{@link ...}
链接到其他程序元素的实例被 Markdown参考链接的扩展形式所取代。 -
块标签的实例,例如
@implSpec
、@return
和@see
,通常不受影响,只是这些标签的内容现在也在 Markdown 中,例如这里在标签内容的反引号中@implSpec
。
下面的屏幕截图并排突出显示了两个版本之间的差异:
用于///
Markdown 文档注释
我们使用///
Markdown 注释是为了克服传统/**
注释的两个问题。
-
以 开头的块注释
/*
不能包含字符序列*/
( JLS §3.7 )。将代码示例放在文档注释中变得越来越普遍。此限制排除了包含嵌入/*...*/
注释的示例或包含字符 的表达式*/
,而无需使用破坏性的解决方法。在
//
注释中,对该行其余部分可能出现的字符没有限制。 -
在传统的文档注释中,从 开始,每行是否
/**
可以使用前导空格并后跟一个或多个星号。当注释行中省略此类星号时,本身以星号开头的 Markdown 结构就会产生歧义,例如强调、列表项和主题分隔。在
///
评论中,从来没有任何这样的歧义。
无法通过更改 Java 语言的语法来允许新的注释形式。因此,任何新样式的文档注释都必须采用传统的/* ... */
块注释或一系列//
行尾注释的形式。
上述几点证明了使用行尾注释而不是传统注释的合理性,但问题仍然是如何区分文档注释和其他行尾注释。我们使用additional ,这与传统文档注释开头的/
additional 的使用相呼应。*
此外,虽然不是主要考虑因素,但支持行尾文档注释的其他语言(例如C#、Dart和Rust)现在已经成功用于///
文档注释一段时间了。
句法
Markdown 文档注释是用Markdown 的CommonMark变体编写的。链接的增强功能可以方便地链接到其他程序元素。支持简单的GFM 管道表,以及所有 JavaDoc 标记。
链接
您可以使用 Markdown参考链接的扩展形式创建指向在 API 中其他地方声明的元素的链接,其中引用的标签源自对元素本身的标准 JavaDoc引用。
要创建一个其文本源自元素标识的简单链接,只需将对元素的引用括在方括号中即可。例如,要链接到java.util.List
,您可以编写[java.util.List]
,或者只要代码中[List]
有import
for 语句即可。java.util.List
链接的文本将以等宽字体显示。该链接相当于使用标准 JavaDoc{@link ...}
标记。
您可以链接到任何类型的程序元素:
/// - a module [java.base/]
/// - a package [java.util]
/// - a class [String]
/// - a field [String#CASE_INSENSITIVE_ORDER]
/// - a method [String#chars()]
要创建带有替代文本的链接,请使用表单[text][element]
。例如,要创建java.util.List
指向文本 的链接a list
,您可以编写[a list][List]
。尽管您可以在文本中使用格式标记,但链接将以当前字体显示。该链接相当于使用标准 JavaDoc{@linkplain ...}
标记。
例如:
/// - [the `java.base` module][java.base/]
/// - [the `java.util` package][java.util]
/// - [a class][String]
/// - [a field][String#CASE_INSENSITIVE_ORDER]
/// - [a method][String#chars()]
在参考链接中,您必须避免使用方括号。这可能发生在 对带有数组参数的方法的引用中;例如,您可以编写一个指向String.copyValueOf(char[])
as的链接[String#copyValueOf(char\[\])]
。
您可以使用所有其他形式的 Markdown 链接,包括 URL 链接,但其他程序元素的链接可能是最常见的。
表格
支持简单的表格,使用GitHub Flavored Markdown的语法。例如:
/// | Latin | Greek |
/// |-------|-------|
/// | a | alpha |
/// | b | beta |
/// | c | gamma |
不支持辅助功能可能需要的字幕和其他功能。在这种情况下,仍然建议使用 HTML 表格。
JavaDoc 标签
JavaDoc 标签,包括内联标签(如 ){@inheritDoc}
和块标签(如@param
和 )@return
,都可以在 Markdown 文档注释中使用:
/// {@inheritDoc}
/// In addition, this methods calls [#wait()].
///
/// @param i the index
public void m(int i) ...
JavaDoc 标签不得在文字文本中使用,例如代码跨度( `...`
) 或代码块,即缩进或包含在栅栏(例如```
或 )内的文本块~~~
。换句话说,字符序列@...
和{@...}
在代码范围和代码块中没有特殊含义:
/// The following code span contains literal text, and not a JavaDoc tag:
/// `{@inheritDoc}`
///
/// In the following indented code block, `@Override` is an annotation,
/// and not a JavaDoc tag:
///
/// @Override
/// public void m() ...
///
/// Likewise, in the following fenced code block, `@Override` is an annotation,
/// and not a JavaDoc tag:
///
/// ```
/// @Override
/// public void m() ...
/// ```
对于那些可能包含带有标记的文本的标签,在 Markdown 文档注释中,标记也在 Markdown 中:
/// @param l the list, or `null` if no list is available
该{@inheritDoc}
标签包含一个或多个超类型的方法的文档。包含标签的注释的格式不需要与包含要继承的文档的注释的格式相同:
interface Base {
/** A method. */
void m()
}
class Derived implements Base {
/// {@inheritDoc}
public void m() { }
}
用户定义的 JavaDoc 标签可以在 Markdown 文档注释中使用。例如,在 JDK 文档中,我们定义并使用{@jls ...}
Java 语言规范链接的缩写形式,以及诸如@implSpec
和 之类的块标签@implNote
来介绍特定信息的部分:
/// For more information on comments, see {@jls 3.7 Comments}.
///
/// @implSpec
/// This implementation does nothing.
public void doSomething() { }
独立 Markdown 文件
子目录中的 Markdown 文件doc-files
会得到适当的处理,处理方式与此类目录中的 HTML 文件类似。处理此类文件中的 JavaDoc 标记。页面标题是从第一个标题推断出来的。不支持YAML 元数据,例如Pandoc Markdown 处理器支持的元数据。
包含生成的顶级概述页面的内容的文件也可以是 Markdown 文件。