Отладчики - это костыль.
Это настолько противоречиво, что даже я не верю в это так, как раньше.
Con: Я трачу больше времени на то, чтобы быстро освоить объемный код других людей, поэтому все, что поможет с «как я сюда попал» и «что происходит», может быть полезным до или после смерти.
Pro: Тем не менее, я с радостью поддерживаю идею, что если вы не понимаете ответы на эти вопросы для кода, который вы разработали сами или с которым вы знакомы, то все ваше время в отладчике не является Решение, это часть проблемы.
Прежде чем нажать «Опубликовать свой ответ», я быстро проверил в Google эту точную фразу, оказалось, что я не единственный, кто придерживался этого мнения или использовал эту фразу. Я поднял долгое обсуждение этого самого вопроса на форуме по программному обеспечению Fog Creek, на котором в качестве заметных сторонников упоминались разные светила, в том числе Линус Торвальдс
.
В байт-коде есть две формы переключателя: tablewitch
и lookupswitch
. Один предполагает плотный набор ключей, другой - редкий. См. Описание переключателя компиляции в спецификации JVM . Для перечислений находится порядковый номер, а затем код продолжается как случай int
. Я не совсем уверен, как будет реализована предлагаемая переключение
на String
небольшую функцию в JDK7.
Однако часто используемый код обычно компилируется в любой разумной JVM. Оптимизатор не совсем тупой. Не беспокойтесь об этом и следуйте обычной эвристике для оптимизации.
Не беспокойтесь о производительности; используйте синтаксис, который лучше всего выражает то, что вы делаете. Только после того, как вы: (а) продемонстрировали недостаточную производительность; и (б) локализовал его для рассматриваемой процедуры, только тогда вы можете беспокоиться о производительности. За мои деньги здесь более уместен синтаксис case.
Похоже, вы перечислили значения, поэтому, возможно, перечисление в порядке?
enum BRANCH {
A,B, ... Y,Z;
}
Затем в вашем коде:
BRANCH branch = BRANCH.valueOf( WORD[ INDEX ] );
Кроме того, в вашем коде есть возможная ошибка, где "A" == " "
может быть ложным в зависимости от идентичности объекта" A ".
Не совсем ответ на ваш вопрос, но на самом деле в вашем коде есть ошибка , у вас должен быть перерыв после каждого случая:
switch ( WORD[ INDEX ] ) {
case 'A' : branch = BRANCH.A; break;
/* B through to Y */
case 'Z' : branch = BRANCH.Z; break;
}
Я не думаю, что разница в производительности здесь будет слишком значительной, но если вы действительно заботитесь о производительности и если этот код выполняется очень часто, вот другой вариант:
// Warning, untested code.
BRANCH[] branchLookUp = {BRANCH.A, BRANCH.B, ..., BRANCH.Z};
branch = branchLookUp[WORD[INDEX] - 'A'];
Обязательно инкапсулируйте это и хорошо задокументируйте.
Честно говоря, я не думаю, что в данном случае производительность имеет значение. Это действительно зависит от компилятора и его оптимизации.
Вот способ избежать всех операторов case.
import java.util.HashMap;
public class Dictionary {
private static Dictionary ROOT;
private boolean terminus;
private final HashMap<Character, Dictionary> dictionaries = new HashMap<Character, Dictionary>();
private void ensureBranch(char c) {
if (getBranch(c) != null)
return;
dictionaries.put(c, new Dictionary());
}
private Dictionary getBranch(char c) {
return dictionaries.get(c);
}
public static boolean is(final String string) {
ensureRoot();
return is(chars(string), ROOT, 0, string.length() - 1);
}
public static void add(final String... strings) {
ensureRoot();
for (final String string : strings)
add(chars(string), ROOT, 0, string.length() - 1);
}
private static void ensureRoot() {
if (ROOT == null)
ROOT = new Dictionary();
}
private static char[] chars(final String string) {
return string.toUpperCase().toCharArray();
}
private Dictionary() {
this.terminus = false;
}
private static void add(final char[] word, final Dictionary dictionary, final int index, final int limit) {
Dictionary branch = getBranch(word, dictionary, index);
if (index == limit)
branch.terminus = true;
else
add(word, branch, index + 1, limit);
}
private static Dictionary getBranch(final char[] word, final Dictionary dictionary, final int index) {
final char c = word[index];
dictionary.ensureBranch(c);
return dictionary.getBranch(c);
}
private static boolean is(final char[] word, final Dictionary dictionary, final int index, final int limit) {
Dictionary branch = dictionary.getBranch(word[index]);
if (branch == null)
return false;
if (index == limit)
return branch.terminus;
return is(word, branch, index + 1, limit);
}
}
Если у вас есть оператор switch с последовательными целыми значениями, в зависимости от языка, он может быть оптимизирован до ветки стол, что очень быстро. Во всяком случае, он не медленнее!
Кроме того, использование if / else if было бы улучшением по сравнению с if для таких случаев, как этот, когда ваши случаи являются взаимоисключающими. Нет смысла делать еще 25 проверок после сопоставления A.
Но в основном любая разница в производительности незначительна, и вам следует использовать наиболее правильный синтаксис, которым в данном случае является оператор switch. Однако не забудьте разделить дела с перерывами.
Оператор switch
должен использовать хэш, чтобы выбрать, к какому случаю перейти. Оттуда каждый последующий case также будет запускаться, если нет операторов break
. Например, с вашим кодом, если вы включите X, он немедленно перейдет к X, затем Y, затем Z. См. Руководство по Java .
Я думаю, что это больше вопрос стиля, а не производительности. Я думаю, что в этом случае оператор switch более уместен, чем if. Не уверен, что есть большая разница в производительности.
Переключатель
должен быть логарифмическим, а if
линейным, если компилятор не может найти ничего умного. Но длинные переключатели
сложны для чтения, а также подвержены ошибкам - как уже отмечалось, переключатель, который у вас выше, не имеет разрывов, и он будет проваливаться во всех случаях.
Почему бы вместо этого не предварительно заполнить Map
, а просто использовать Map.get ()
?
private static final Map<Char, Whatever> BRANCHES = Collections.unmodifiableMap(new HashMap<Char, Whatever>() {{
put('A', BRANCH.A);
...
put('Z', BRANCH.Z);
}}
public void getBranch(char[] WORD, int INDEX) {
return BRANCHES.get(WORD[INDEX]);
}
Как отмечалось выше, если BRANCH
является Enum
, это поведение должно быть правильно в Enum
.
(Что такое WORD
, ИНДЕКС
и ФИЛИАЛ
все равно здесь? Судя по именам, они должны быть константами, но у вас не может быть постоянных массивов - содержимое всегда можно изменять; не было бы особого смысла создавать постоянную «структуру»; и, конечно, не было бы особого смысла в iffing или переключении на основе констант ....)
Я знаю, что вы совсем не об этом спрашиваете, но разве вы не делаете это просто так?
public class Dictionary {
private static final Set<String> WORDS = new HashSet<String>();
public static void add(final String... STRINGS) {
for (String str : STRINGS) {
WORDS.add(str.toUpperCase());
}
}
public static boolean is(final String STRING) {
return WORDS.contains(STRING.toUpperCase());
}
}
Вы просто ищете что-то более эффективное с точки зрения памяти?