Как назвать переменную, являющуюся копией параметра?
У меня есть метод, который будет обрабатывать Collection<Nodes>
, который передается как параметр. Этот Collection
будет изменен, поэтому я подумал, что было бы хорошо сделать его копию. Как указать параметр и локальную переменную, например. nodes
в приведенном ниже примере?
List<Nodes> process(Collection<Nodes> nodes) {
List<Nodes> nodes2 = new ArrayList<>(nodes);
...
}
В качестве другого примера рассмотрим следующее, где переменная int
анализируется по параметру String
:
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;
}
В этом случае они вызывают параметр original
и локальную переменную copy
, которая прекрасно выражает, что возвращаемое значение является копией параметра. Точно, копирование - это то, что делает этот метод, и оно называется соответствующим образом.
Используя те же рассуждения для вашего случая (подумайте о том, чтобы рефакторинг дал более значимые имена вашему методу и переменным), я бы назвал вашу локальную копию nodes
чем-то вроде processedNodes
, чтобы выразить, что это за переменная, и быть последовательной с именем вашего метода.
Edit:
Имя нового метода, добавленного в вашем редактировании, не содержит подсказок о том, что он делает. Я предполагаю, что он изменяет некоторые свойства (возможно, в базе данных) пользователя, чей идентификатор передается через параметр.
Если это так (или подобное), я считаю, что подходящий подход вы
может применяться, так это то, что каждый метод должен иметь одну ответственность. Согласно имени вашего метода, он должен обработать пользователя, для этого вам понадобится int userId
. Ответ на разбор String userId
должен быть вне сферы действия этого метода.
Использование предлагаемого подхода имеет, среди прочего, следующие преимущества:
-
Ваш класс не изменится, если вам нужно добавить дополнительную проверку на свой вклад.
-
Ваш класс не будет нести ответственность за обработку NumberFormatException
, которая должна отвечать требованиям приложения.
-
Ваш метод processUser
не изменится, если вам нужно обрабатывать разные типы входов (например, float userId
).
Ответ 2
В конечном итоге это сводится к тому, что вы хотите сообщить будущим программистам. На компьютере, очевидно, все равно. это другие люди, с которыми вы разговариваете. Поэтому самым важным фактором будет то, что эти люди должны знать:
- Что такое логическое (абстрактное, концептуальное) значение этой переменной?
- Какие аспекты использования этой переменной могут смущать программистов?
- Что самое важное в этой переменной?
Глядя на ваш первый пример, вам сложно понять, что ваша программа действительно выбирает хорошее имя. Метод называется process
; но методы, вообще говоря, реализуют вычислительные процессы, поэтому это имя действительно ничего мне не говорит. Что вы обрабатываете? Каков процесс? Для кого вы его обрабатываете и почему? Знание того, что делает этот метод, и его класс, поможет сообщить имя переменной.
Добавьте некоторые предположения. Скажем, вы создаете приложение, которое находит точки доступа Wi-Fi в здании. Рассматриваемый Node
- это беспроводной node, с подклассами Repeater
, AccessPoint
и Client
. Позвольте также сказать, что это набор данных, обработанный онлайн, поэтому набор данных узлов может измениться в любой момент в ответ на фоновый поток, получающий обновления в том, какие узлы в настоящее время видны. Ваша причина для копирования коллекции во главе метода заключается в том, чтобы изолировать себя от этих изменений на время локальной обработки. Наконец, предположим, что ваш метод сортирует узлы по времени ping (объясняя, почему метод принимает общий Collection
, но возвращает более специфичный тип List
).
Теперь, когда мы лучше понимаем вашу систему, позвольте использовать это понимание, чтобы выбрать некоторые имена, которые сообщают логическое намерение вашей системы будущим разработчикам:
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);
}
}
Таким образом, метод sortByPingTime
определяет, что он делает; аргумент networkNodes
для описания того, что мы рассматриваем node. И переменная называется unsortedSnapshot
, чтобы выразить две вещи об этом, которые не видны, просто прочитав код:
- Это снимок чего-то (подразумевающий, что оригинал каким-то образом нестабилен); и
- У нас нет порядка, который имеет для нас значение (предполагая, что он может быть к тому моменту, когда мы закончим).
Мы могли бы разместить там nodes
, но это сразу видно из входного аргумента. Мы могли бы также назвать это snapshotToSort
, но это видно в том, что мы передаем его в подпрограмму sort
сразу же.
Этот пример остается своего рода надуманным. Метод действительно слишком короткий, поскольку имя переменной имеет большое значение. В реальной жизни я бы просто назвал его out
, потому что выбор хорошего имени займет больше времени, чем кто-либо будет тратить время на выяснение того, как этот метод работает.
Другие связанные примечания:
- Именование по своей сути немного субъективно. Мое имя никогда не будет работать для всех, особенно когда учитываются несколько человеческих языков.
- Я нахожу, что лучшее имя часто не является именем. Если мне удастся сделать что-то анонимное, я это сделаю - это минимизирует риск повторного использования переменной и уменьшает символы в ячейках IDE "найти". Как правило, это также подталкивает меня писать более строгий, более функциональный код, который я считаю хорошим.
- Некоторым людям нравится включать тип переменной в свое имя; Я всегда считал, что это немного странно, потому что тип обычно очевиден, и компилятор обычно поймает меня, если я все равно ошибаюсь.
- "Keep it Simple" находится в полной силе здесь, как и везде. В большинстве случаев ваше имя переменной не поможет кому-то избежать будущей работы. Мое эмпирическое правило, назовите его чем-то немым, и если я когда-нибудь в конце концов почесываю голову о том, что что-то значит, выберите этот случай, чтобы назвать его чем-то хорошим.
Ответ 3
Я использовал имена, которые отражают и подчеркивают основные вещи. Поэтому потенциальный читатель (включая меня через пару месяцев) может сразу получить то, что делается внутри метода только по его подписи.
API в обсуждении получает ввод, выполняет некоторую обработку и возвращает вывод. Это три основные вещи здесь.
Если это не важно, какая обработка выполняется и какой тип ввода, наиболее общей является эта форма:
List<Nodes> process(Collection<Nodes> input) {
List<Nodes> output = new ArrayList<>(input);
...
}
и
public void process(final String input) {
final int output = Integer.parseInt(input);
...
Если важно предоставить больше информации о обработке и типе ввода, имена, такие как: processCollection, inputCollection и processUser, inputUserId более подходят, но локальная переменная по-прежнему является результатом - это ясное и самоочевидное имя
List<Nodes> processCollection(Collection<Nodes> inputCollection) {
List<Nodes> output = new ArrayList<>(inputCollection);
...
}
и
public void processUser(final String inputUserId) {
final int output = Integer.parseInt(inputUserId);
...
Это зависит от варианта использования, и иногда даже более целесообразно разрабатывать обработку, которая выполняется: asArray или asFilteredArray и т.д. вместо processCollection.
Кто-то может предпочесть терминологию source-destination для ввода-вывода. Я не вижу существенной разницы между ними. Если это объясняет историю метода с его названием, это достаточно хорошо.
Ответ 4
Это зависит от того, что вы собираетесь делать с локальной переменной.
Например, в первом примере кажется, что, вероятно, переменная nodes2
будет фактически значением, возвращаемым в конце. Мой совет - просто называть его result
или output
.
Во втором примере... менее понятно, чего вы можете достичь... Я думаю, что userIdAsInt
должно быть хорошо для локального. Однако, если здесь всегда ожидается int
, и вы все равно хотите сохранить параметр как строку (возможно, вы хотите вывести эту проверку из метода), я думаю, что более целесообразно сделать локальную переменную userId
и параметр userIdAsString
или userIdString
, который намекает, что String
, хотя и принят здесь, не является каноническим представлением userId, которое является int
.
Ответ 5
Конечно, это зависит от фактического контекста. Я бы не использовал подходы с других языков программирования, таких как _
, который хорош, например, для именования скриптов bash, IMO my
тоже не является хорошим выбором - это похоже на фрагмент кода, скопированный из учебника (по крайней мере в Java).
Самое простое решение - назвать параметр метода nodesParam
или nodesBackup
, а затем вы можете просто пойти с nodes
в качестве копии или, если быть более конкретным, вы можете назвать его nodesCopy
.
В любом случае, ваш метод process
выполняет некоторые задачи, и, возможно, это не лучшее место для создания копий списка узлов. Вы можете сделать копию в том месте, где вы вызываете метод, тогда вы можете просто использовать nodes
как имя вашего объекта:
List<Nodes> process(Collection<Nodes> nodes) {
// do amazing things here
// ...
}
// ...
process(new ArrayList<>(nodes))
// ...
Просто я предполагаю, что у вас есть коллекция, и вы хотите сохранить оригинальную версию и изменить копию, может быть, для вас действительно нужно использовать java.util.stream.Stream.
Ответ 6
Проще говоря, при указании переменной я считаю несколько вещей.
- Как создается копия? (Преобразуется ли он из одного типа в другой?...)
- Что я буду делать с переменной?
- Является ли имя коротким, но/и значимым?
Учитывая те же примеры, которые вы указали в вопросе, я назову такие переменные:
List<Nodes> process(Collection<Nodes> nodes) {
List<Nodes> nodesCopy = new ArrayList<>(nodes);
...
}
Это, вероятно, просто копия коллекции, отсюда и название nodesCopy
. Значительный и короткий. Если вы используете nodesList
, это может означать, что это не просто Collection
; но и List
(более конкретный).
public void processUser(final String userId) {
final int userIdInt = Integer.parseInt(userId);
...
Анализируется String
userId
, а результат - целое число (int
)! Это не просто копия. Чтобы подчеркнуть это, я бы назвал это как userIdInt
.
Лучше не использовать символ подчеркивания _
, потому что он часто указывает переменные экземпляра. И префикс my
: здесь не так много смысла, и это nooby (local
будет лучше).
Ответ 7
Когда речь идет о соглашениях об именах параметров метода, если вещь, представленная параметром метода, не будет представлена какой-либо другой переменной, используйте имя параметра метода, которая очень четко определяет, что этот параметр метода находится в контексте тела метода, Например, primaryTelephoneNumber
может быть допустимым именем параметра метода в методе setBean для JavaBean.
Если в контексте метода есть несколько представлений о вещи (включая параметры метода и локальные переменные), используйте имена, которые дают понять людям, что это за вещь и как ее использовать. Например, для имени параметра метода могут использоваться providedPrimaryTelephoneNumber
, requestedPrimaryTelephoneNumber
, dirtyPrimaryTelephoneNumber
и parsedPrimaryTelephoneNumber
, cleanPrimaryTelephoneNumber
, massagedPrimaryTelephoneNumber
для локального имени переменной в методе, предоставил первичный номер телефона.
Основная цель - использовать имена, которые дают понять людям, читающим исходный код сегодня и завтра, о том, что происходит. Избегайте имен типа var1
, var2
, a
, b
и т.д.; эти имена добавляют дополнительные усилия и сложность в чтении и понимании исходного кода.
Не слишком зацикливайтесь на использовании имен параметров длинных методов или локальных переменных; исходный код предназначен для чтения человеком, а когда класс компилируется, имена параметров метода и имена локальных переменных не имеют отношения к машине.