为什么有很多非 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,这些警告实际上不适用。
  • 它抛出一个可能永远不会发生的已检查异常,这总是不好的(显然不要强制调用代码捕获不可能的异常!)-如果 forcetrueDiskInUseException不可能发生。
  • 如果我调用它:detachDisk(computer, disk, true) 并且我在代码中看到它,我可以猜测 computer 是一个引用 virtualPC 的变量,与 disk 相同,但无论如何 true 大约是?我可能猜想这是关于强制的事情,但也许在我的脑海中,第三个参数是 safelyforce 的反面)。

我们可以通过使用枚举而不是布尔值来解决一些问题,但剩下的就剩下了。这是非常优越的 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) { .. }

Mu​​uuch 更好,但很可能这 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 同名方法(末尾没有零)调用以零结尾的私有方法。

但是无论如何,这种私有方法的命名约定不是一个很好的例子,也不应该复制。