如何命名作为参数副本的变量?

2022-09-04 19:33:19

我有一个方法,它将处理作为参数传入的a。这将被修改,因此我认为最好先复制它。如何命名参数和局部变量,例如 在下面的例子中?Collection<Nodes>Collectionnodes

List<Nodes> process(Collection<Nodes> nodes) {
  List<Nodes> nodes2 = new ArrayList<>(nodes);
  ...
}

作为另一个示例,请考虑以下变量,其中变量是从参数解析而来的:intString

public void processUser(final String userId) {
  final int userId2 = Integer.parseInt(userId);
  ...

答案 1

解决名称变量问题的一个好方法是使用表明变量实际含义的名称。在您的示例中,您使用的名称没有说明方法功能或变量的含义,这就是为什么很难选择名称的原因。

在JDK中有很多像你这样的情况,例如Arrays#copyOf

public static <T,U> T[] copyOf(U[] original, int newLength, Class<? extends T[]> newType) {
    @SuppressWarnings("unchecked")
    T[] copy = ((Object)newType == (Object)Object[].class)
        ? (T[]) new Object[newLength]
        : (T[]) Array.newInstance(newType.getComponentType(), newLength);
    System.arraycopy(original, 0, copy, 0,
                     Math.min(original.length, newLength));
    return copy;
}

在这种情况下,他们调用参数和局部变量,这完美地表示返回的值是参数的副本。准确地说,复制是这种方法的作用,并相应地命名。originalcopy

对于您的情况使用相同的推理(考虑重构以为您的方法和变量提供更有意义的名称),我会将类似的东西命名为 本地副本,以表达该变量是什么,并与方法的名称保持一致。nodesprocessedNodes

编辑:

您在编辑中添加的新方法的名称也不会提供有关其功能的提示。我假设它修改了其id通过参数传递的用户的某些属性(可能在数据库中)。

如果是这种情况(或类似),我认为您可以应用的适当方法是每种方法都应该有一个单一的责任。根据方法的名称,它应该处理用户,为此您需要一个.解析 的责任应该不在此方法的范围之内。int userIdString userId

使用所提出的方法具有以下优点:

  • 如果您必须向输入添加其他验证,您的类不会更改。

  • 您的类将不负责处理这必须是应用程序的责任。NumberFormatException

  • 如果您必须处理不同类型的输入(例如),您的方法不会更改。processUserfloat userId


答案 2

它最终归结为你想与未来的程序员沟通什么。计算机显然不在乎;这是你正在与之交谈的其他人。因此,最大的因素将是那些人需要知道的:

  • 这个变量的逻辑(抽象,概念)含义是什么?
  • 如何使用此变量的哪些方面可能会让程序员感到困惑?
  • 这个变量最重要的事情是什么?

看看你的第一个例子,很难对你的程序有足够的了解来真正选择一个好的名字。该方法称为 ;但是方法一般来说实现了计算过程,所以这个名字真的没有告诉我任何事情。你们在处理什么?流程是怎样的?您正在为谁处理它,为什么?了解该方法的作用以及它所在的类将有助于告知您的变量名称。process

让我们添加一些假设。假设您正在构建一个应用程序,用于在建筑物中定位 Wi-Fi 接入点。有问题的是一个无线节点,具有子类 、 和 。假设它是一个在线处理的数据集,因此给定的节点集合可能随时更改,以响应接收当前可见节点更新的后台线程。在方法的开头复制集合的原因是,在本地处理期间,将自己与这些更改隔离开来。最后,假设您的方法按 ping 时间对节点进行排序(解释为什么该方法采用泛型但返回更具体的类型)。NodeRepeaterAccessPointClientCollectionList

现在我们已经更好地了解了您的系统,让我们利用这种理解来选择一些名称,这些名称可以向未来的开发人员传达系统的逻辑意图

class NetworkScanner {
    List<Node> sortByPingTime(Collection<Node> networkNodes) {
        final ArrayList<Node> unsortedSnapshot;

        synchronized(networkNodes) {
            unsortedSnapshot = new ArrayList<>(networkNodes);
        }

        return Utils.sort(unsortedSnapshot, (x,y) -> x.ping < y.ping);
    }
}

所以方法是定义它的作用;争论是描述我们正在看的节点类型。调用该变量来表示有关它的两件事,仅通过阅读代码是不可见的:sortByPingTimenetworkNodesunsortedSnapshot

  • 它是某物的快照(暗示原始内容在某种程度上是不稳定的);和
  • 它没有对我们重要的顺序(这表明在我们完成它时,它可能有)。

我们可以放在那里,但这从输入参数中立即可见。我们也可以称之为,但这可以从我们将其传递给紧挨着下面的例程中可见一斑。nodessnapshotToSortsort

这个例子仍然是人为的。该方法确实太短,变量名称无关紧要。在现实生活中,我可能只是称之为,因为选择一个好名字会比任何人都浪费弄清楚这种方法是如何工作的要花更长的时间。out

其他相关注意事项:

  • 命名本身就有点主观。我的名字永远不会对每个人都有用,特别是当考虑到多种人类语言时。
  • 我发现最好的名字往往是根本没有名字。如果我能侥幸做出一些匿名的东西,我会的 - 这最大限度地降低了重用变量的风险,并减少了IDE“查找”框中的符号。总的来说,这也促使我编写更紧凑,功能更强大的代码,我认为这是一件好事。
  • 有些人喜欢在其名称中包含变量的类型;我总是发现这有点奇怪,因为类型通常很明显,如果我弄错了,编译器通常会抓住我。
  • “保持简单”在这里和任何地方一样,都得到了充分的体现。大多数时候,你的变量名称不会帮助某人避免未来的工作。我的经验法则是,给它起个哑巴,如果我最终挠挠头,说什么意味着什么,选择那个场合给它起个名字。