为什么有很多非 public 低级 Java 方法以 0 结尾?
Why are there a lot of non-public low-level Java methods ending in 0?
我喜欢用 IntelliJ 浏览 Java 源代码。但是,我注意到了一些奇怪的事情。一些非 public 方法,尤其是低级 类 中的方法,以 0
结尾。本地方法最常出现这种情况,但我也观察到一些具有此名称的非本地方法。例如,java.lang.reflect.Executable#getAnnotatedReturnType0(Type)
和 java.lang.reflect.AccessibleObject#setAccessible0(boolean)
。前者简单地设置了两个布尔标志!这种奇怪约定背后的原因是什么?
这是辅助方法的一种常见约定。
Java 不允许 methods-in-methods(尽管添加它们会产生一些流量)。有时你有一个重复的任务,但它并不适合循环结构(例如 while 或 for 循环)并且不容易适合 lambda(因为它的参数 + 检查异常要求不符合方便的类型,或者代码早于 JDK8).
JDK 本身,以及其他一些项目,使用以下约定:helper 方法与它作为 helper 的名称相同,带有单个数字后缀,通常为 0(如果有更多 helper,他们会是 1、2 等)。
这在重载时尤其常见。假设您有以下方法签名:
/**
* Detaches a disk from a virtual computer.
* The disk must have been unmounted already on the virtual PC, unless
* the {@code force} parmater is true, but note that (long story
* about the perils of force disconnecting here).
*
* @param computerId computer to detach the disk from.
* @param diskId ID of disk to detach
* @param force Force the issue even if the disk is in use.
* @throws DiskInUseException If the disk is in use. Never thrown if
* {@code force} is {@code true}.
*/
public void detachDisk(
String computerId, String diskId, boolean force) throws DiskInUseException { ... }
不好API。它上面有各种丑陋的疣:
- 文档指定了很多警告,如果我将
force
设置为 false
,这些警告实际上不适用。
- 它抛出一个可能永远不会发生的已检查异常,这总是不好的(显然不要强制调用代码捕获不可能的异常!)-如果
force
是 true
,DiskInUseException
不可能发生。
- 如果我调用它:
detachDisk(computer, disk, true)
并且我在代码中看到它,我可以猜测 computer
是一个引用 virtualPC 的变量,与 disk
相同,但无论如何 true
大约是?我可能猜想这是关于强制的事情,但也许在我的脑海中,第三个参数是 safely
(force
的反面)。
我们可以通过使用枚举而不是布尔值来解决一些问题,但剩下的就剩下了。这是非常优越的 API 设计:
/**
* Same text, but leave out all the stuff about the dangers of forcing.
* @see #forceDetachDisk(String, String)
*/
public void detachDisk(String computerId, String diskId)
throws DiskInUseException {..}
/**
* Same, but now highlight the dangers of forcing.
* @see #detachDisk(String, String)
*/
void forceDetachDisk(String computerId, String diskId) { .. }
Muuuch 更好,但很可能这 2 个方法共享大部分实现。这自然会导致制作这个东西:
private void detachDisk0(String computerId, String diskId,
boolean force) throws DiskInUseException { .. }
它是私有的,因此它的混乱和瑕疵并不重要,public detachDisk 方法将简单地调用私有方法。但是,某些 auto-complete 对话框,当然还有大多数 java 编译器,包括 javac
本身,确实可以识别对私有方法的调用,并且会 'helpfully' 提醒您它确实存在的事实,您是否想更改其访问器关键字(如果它是源文件而不是 class dep)? - 这不太好。将 0 扔在那里以减轻影响,并更清楚地表明私有方法意味着 仅 由 0-less 方法而不是其他方法调用;您仅使用 detachDisk
方法中的用法来编写它,而不是任何其他方法,甚至不在同一源文件中。
这是一个 API 设计,更多的项目应该使用。
此“约定”不仅用于 Java。我记得在 C# 中看到过相同的内容。通常你会看到一个 public 同名方法(末尾没有零)调用以零结尾的私有方法。
但是无论如何,这种私有方法的命名约定不是一个很好的例子,也不应该复制。
我喜欢用 IntelliJ 浏览 Java 源代码。但是,我注意到了一些奇怪的事情。一些非 public 方法,尤其是低级 类 中的方法,以 0
结尾。本地方法最常出现这种情况,但我也观察到一些具有此名称的非本地方法。例如,java.lang.reflect.Executable#getAnnotatedReturnType0(Type)
和 java.lang.reflect.AccessibleObject#setAccessible0(boolean)
。前者简单地设置了两个布尔标志!这种奇怪约定背后的原因是什么?
这是辅助方法的一种常见约定。
Java 不允许 methods-in-methods(尽管添加它们会产生一些流量)。有时你有一个重复的任务,但它并不适合循环结构(例如 while 或 for 循环)并且不容易适合 lambda(因为它的参数 + 检查异常要求不符合方便的类型,或者代码早于 JDK8).
JDK 本身,以及其他一些项目,使用以下约定:helper 方法与它作为 helper 的名称相同,带有单个数字后缀,通常为 0(如果有更多 helper,他们会是 1、2 等)。
这在重载时尤其常见。假设您有以下方法签名:
/**
* Detaches a disk from a virtual computer.
* The disk must have been unmounted already on the virtual PC, unless
* the {@code force} parmater is true, but note that (long story
* about the perils of force disconnecting here).
*
* @param computerId computer to detach the disk from.
* @param diskId ID of disk to detach
* @param force Force the issue even if the disk is in use.
* @throws DiskInUseException If the disk is in use. Never thrown if
* {@code force} is {@code true}.
*/
public void detachDisk(
String computerId, String diskId, boolean force) throws DiskInUseException { ... }
不好API。它上面有各种丑陋的疣:
- 文档指定了很多警告,如果我将
force
设置为false
,这些警告实际上不适用。 - 它抛出一个可能永远不会发生的已检查异常,这总是不好的(显然不要强制调用代码捕获不可能的异常!)-如果
force
是true
,DiskInUseException
不可能发生。 - 如果我调用它:
detachDisk(computer, disk, true)
并且我在代码中看到它,我可以猜测computer
是一个引用 virtualPC 的变量,与disk
相同,但无论如何true
大约是?我可能猜想这是关于强制的事情,但也许在我的脑海中,第三个参数是safely
(force
的反面)。
我们可以通过使用枚举而不是布尔值来解决一些问题,但剩下的就剩下了。这是非常优越的 API 设计:
/**
* Same text, but leave out all the stuff about the dangers of forcing.
* @see #forceDetachDisk(String, String)
*/
public void detachDisk(String computerId, String diskId)
throws DiskInUseException {..}
/**
* Same, but now highlight the dangers of forcing.
* @see #detachDisk(String, String)
*/
void forceDetachDisk(String computerId, String diskId) { .. }
Muuuch 更好,但很可能这 2 个方法共享大部分实现。这自然会导致制作这个东西:
private void detachDisk0(String computerId, String diskId,
boolean force) throws DiskInUseException { .. }
它是私有的,因此它的混乱和瑕疵并不重要,public detachDisk 方法将简单地调用私有方法。但是,某些 auto-complete 对话框,当然还有大多数 java 编译器,包括 javac
本身,确实可以识别对私有方法的调用,并且会 'helpfully' 提醒您它确实存在的事实,您是否想更改其访问器关键字(如果它是源文件而不是 class dep)? - 这不太好。将 0 扔在那里以减轻影响,并更清楚地表明私有方法意味着 仅 由 0-less 方法而不是其他方法调用;您仅使用 detachDisk
方法中的用法来编写它,而不是任何其他方法,甚至不在同一源文件中。
这是一个 API 设计,更多的项目应该使用。
此“约定”不仅用于 Java。我记得在 C# 中看到过相同的内容。通常你会看到一个 public 同名方法(末尾没有零)调用以零结尾的私有方法。
但是无论如何,这种私有方法的命名约定不是一个很好的例子,也不应该复制。