1. Минимизируйте область действия локальных переменных
-
вопрос
Минимизация области действия локальных переменных повышает удобочитаемость и ремонтопригодность кода, а также снижает вероятность ошибок. Итак, каковы наиболее часто используемые способы минимизации области видимости локальных переменных?
-
решать
- Чтобы локальные переменные не расширяли область действия и не загрязняли другие области. Область действия локальной переменной должна быть минимизирована, **то есть она должна быть объявлена там, где она впервые используется, и по возможности инициализирована. ** Типичный пример: использование
for
Для циклов переменная область видимости находится внутри цикла и не распространяется. Итак, если содержимое переменной цикла больше не нужно после завершения цикла,for
цикл лучше, чемwhile
цикл; - Держите методы небольшими и сфокусированными. Если две операции объединены в один и тот же метод, возможно, что локальные переменные, связанные с одной операцией, появятся в области действия кода, выполняющего другую операцию. Чтобы этого не произошло, просто разбейте метод на два, каждый из которых выполняет операцию;
- почтиОбъявление каждой локальной переменной должно включать выражение инициализации, если для осмысленной инициализации переменной недостаточно информации, объявление следует отложить до ее инициализации, за исключением try..catch.
- Чтобы локальные переменные не расширяли область действия и не загрязняли другие области. Область действия локальной переменной должна быть минимизирована, **то есть она должна быть объявлена там, где она впервые используется, и по возможности инициализирована. ** Типичный пример: использование
-
В заключение
Чтобы загрязнить область действия локальной переменной метода другими областями, необходимо максимально уменьшить область действия локальной переменной, что может повысить читабельность и удобство сопровождения кода.
2. For-Each из-за цикла for
-
вопрос
До Java 1.5 было принято обходить коллекцию следующим образом:
for (Iterator i = c.iterator(); i.hasNext(); ) {
скопировать кодdoSomething((Element) i.next()); // (No generics before 1.5)
}
Для обхода массива принято использовать следующий метод:
for (int i = 0; i < a.length; i++) {
скопировать кодdoSomething(a[i]);
}
Эти идиомы лучше, чем циклы while, но не идеальны. Итераторы и индексы немного сбивают с толку. Кроме того, они могут вызывать ошибки. В приведенном выше цикле и итератор, и индекс появляются три раза.Есть два места, где могут возникнуть ошибки.Если такие ошибки все-таки возникают, нет гарантии, что компилятор их поймает. Итак, какой способ обхода коллекций и массивов предпочтительнее?
-
решать
-
При обходе коллекций и массивов предпочтительнее использовать метод обхода для каждого, например следующий пример кода:
for (Element e : elements) {
скопировать кодdoSomething(e);
}
-
for-each
Производительность цикла выше, чем у традиционного цикла for, и может уменьшить возникновение исключений.for-each
Циклы могут проходить не только по коллекциям и массивам, но и по любой реализации.Iterable
объект интерфейса. использовать одновременноfor-each
Циклы также имеют следующие ограничения:- Фильтрация: если вам нужно удалить определенные элементы во время обхода, вам нужно использовать явный итератор, вызывая
remove
метод удаления; - Преобразование: если вам нужно преобразовать некоторые элементы в процессе обхода, вам нужно использовать итератор или индекс, чтобы установить определенный элемент за один проход;
- Параллельная итерация: если вам нужно пройти несколько коллекций параллельно, вам нужно явно управлять переменными итератора и индекса, чтобы все итераторы и индексы могли продвигаться синхронно.
- Фильтрация: если вам нужно удалить определенные элементы во время обхода, вам нужно использовать явный итератор, вызывая
-
-
В заключение
В большинстве случаев для обхода коллекций и массивов следует использовать циклы for-each Только при параллельной фильтрации, преобразовании и итерации вам нужно использовать традиционные итераторы и индексы для обхода.
3. Избегайте использования поплавка
-
вопрос
Поплавковый и двойной типы в основном предназначены для научных и инженерных расчетов, они не дают абсолютно точных результатов,Поэтому его не следует использовать там, где требуются точные результаты.. Например:
System.out.println(1.0-0.42) //输出 0.580000000000001
Итак, что же делать, когда требуются точные результаты?
-
решать
- Используйте, когда требуются точные результатыBigDecimal, то, что создает BigDecimal, является объектом, мы не можем использовать традиционные +, -, *, / и другие арифметические операторы для непосредственного выполнения математических операций над своим объектом, но должны вызывать соответствующий метод, и параметры в методе также должны быть объектом BigDecimal ;
-
Не используйте float и double для любых вычислительных задач, требующих точных ответов.,можно использовать
int、long或者BigDecimal
. С помощью BigDecimal можно легко выбрать метод округления, всего доступно 8 методов; - Если диапазон значений не более 9 знаков после запятой, используйте int, если он превышает 9 знаков, но не более 18 знаков, можно использовать long, если возможно превышение 18 знаков, необходимо использовать BigDecimal.
-
В заключение
В заключение, не используйте float или double для любой вычислительной задачи, требующей точных ответов, если вы хотите, чтобы система записывала десятичные точки, и не возражаете против неудобства неиспользования примитивных типов, вы можете использоватьBigDecimal.
4. Примитивные типы лучше коробочных
-
вопрос
Java имеет тип данных, состоящий из двух частей, в том числебазовый тип(примитивные), такие как int, double и boolean, итип ссылки(ссылочный тип), например String и List. Каждый примитивный тип имеет соответствующий ссылочный тип, называемый упакованным примитивом. Из-за автоматического механизма упаковки и распаковки в Java базовые и упакованные типы смешиваются в фактической разработке, так в чем же между ними разница?
-
решать
-
Есть 3 основных различия между примитивными типами и типами в штучной упаковке:
- Примитивные типы имеют только значения, в то время как коробочные типы имеют другую однородность, чем их значения, т.е.
new Integer(42)==new Integer(42)
, хотя оба типа бокса представляют число 42, суждение об идентичности будет возвращатьсяfalse
; - Примитивные типы имеют только конкретные функциональные значения, такие как числовые значения и т. д., в то время как коробочные типы также имеют нефункциональные значения.
null
; - Примитивные типы, как правило, более эффективны с точки зрения пространства и времени выполнения, чем упакованные типы.
Примечание: Если базовый тип и упакованный тип смешаны, упакованный тип будет распакован в базовый тип.В настоящее время, если упакованный тип имеет значение null, он легко сообщит об исключении NullPointException.
- Примитивные типы имеют только значения, в то время как коробочные типы имеют другую однородность, чем их значения, т.е.
-
Когда использовать коробочные типы
- При использовании коллекций ключи и значения могут использовать только коробочные типы;
- При использовании параметризованных типов, таких как класс ThreadLocal, можно использовать только упакованные типы.
-
-
В заключение
Когда они доступны, примитивные типы предпочтительнее коробочных типов.. Базовые типы удобнее, проще и работают лучше. Если нет способа избежать использования коробочных типов, обратите внимание на сравнение идентичности между типами и NullPointException.
5. Правильное использование строк
-
вопрос
Строки часто используются в реальной разработке, а также бывают случаи злоупотреблений, так в каких же ситуациях не следует использовать строки?
-
решать
-
Строки не подходят для замены других значений: когда исходный тип — int, float и другие типы, не используйте подстановку строк;
-
Строки не подходят вместо типов enum: перечисляемые типы больше подходят для представления констант перечисления, чем строк;
-
Строки не подходят вместо агрегатных типов.: Если сущность состоит из нескольких компонентов, обычно нецелесообразно представлять эту сущность в виде строки.
String compundKey = className + "#" + i.next()
, лучше написать класс для описания этого набора данных, обычно частный статический класс-член; -
Строка не подходит в качестве ключа авторизации: Иногда строки используются для авторизации доступа к функции. Рассмотрите возможность разработки механизма для предоставления локальных переменных потока, которые имеют свои собственные значения в каждом потоке. Пример кода:
public class ThreadLocal { private ThreadLocal() {} public static void set(String key, Object value); public static Object get(String key); }
Проблема с этим подходом заключается в том, чтоСтроковые ключи представляют общее глобальное пространство имен, чтобы это работало, строки, предоставленные клиентом, должны быть уникальными, если используется одна и та же строка, переменная фактически является общей.. Его можно исправить следующим образом:
public class ThreadLocal { private ThreadLocal() {} public static class Key { Key() {} } public static Key getKey() { return new Key(); } public static void set(Key key, Object value); public static Object get(Key key); }
Такое использование экземпляров объектов в качестве ключей авторизации может обеспечить глобальную уникальность. Фактически, ThreadLocal также принимает этот метод, используя экземпляр ThreadLocal в качестве ключа ThreadLocalMap.
-
-
В заключение
Короче,Вам следует избегать использования строк для представления объектов, если можно использовать более подходящий тип данных или если можно записать более подходящий тип данных.. Строки могут быть громоздкими и медленнее, чем другие типы, если они используются неправильно. Строки часто неправильно используются вместо примитивов и перечислений.
6. Будьте осторожны с механизмами отражения
-
вопрос
Механизм отражения обеспечивает возможность программного доступа к информации о загруженных классах.Конструктор, Метод, Полеэкземпляры, эти объекты предоставляютКонструктор класса, доступ к именам членов класса, типам полей, сигнатурам методови другая информация. Механизм отражения очень мощный, но каковы меры предосторожности при его использовании?
-
решать
При использовании механизма отражения необходимо обратить внимание на следующие моменты:
- Потерять преимущества проверки типов во время компиляции: если программа попытается использовать отражение для доступа к несуществующему методу, во время выполнения произойдет сбой;
- Код метода, который выполняет отражающий доступ, является подробным: из-за использования отражения будет много исключений, требующих try catch;
- потеря производительности: Отраженные вызовы методов намного медленнее, чем вызовы обычных методов.
-
В заключение
Нельзя отрицать мощный функциональный механизм отражения.Для конкретных сложных задач системного программирования механизм отражения очень удобен, но он также имеет много недостатков.Для обычных вызовов методов не рекомендуется использовать механизм отражения.
7. Тщательно оптимизируйте
-
вопрос
Есть три пословицы, связанные с оптимизацией, которые должен знать каждый:
1. Во многих вычислительных ошибках обвиняют эффективность (эффективность, которую не нужно достигать), а не по какой-либо другой причине — даже вслепую делая глупости. — Уильям А. Вульф [Wulf72] 2. Не считать каких-то мелких выигрышей и проигрышей в эффективности школы, в 97% случаев. Незрелая оптимизация — корень всех проблем. — Дональд Э. Кнут [Knuth74] 3. Когда дело доходит до оптимизации, мы должны следовать двум правилам: Правило 1: Не оптимизируйте. Правило 2 (только для экспертов): Пока не оптимизируйте — то есть не оптимизируйте, пока не получите абсолютно четких неоптимизированных решений. — М. А. Джексон [Jackson75]
В большинстве случаев незрелые оптимизации вызовут более серьезные проблемы.На что следует обратить внимание при оптимизации производительности?
-
Отвечать
- Не жертвуйте разумной структурой ради производительности. ** Старайтесь писать хорошие программы, а не быстрые последовательности столбцов. ** Если хорошая программа недостаточно быстра, ее структура позволит оптимизировать ее. В хороших программах реализован принцип сокрытия информации: по возможности они концентрируют проектные решения в одном модуле, поэтому одно решение можно изменить, не затрагивая остальную часть системы;
- ** Старайтесь избегать проектных решений, ограничивающих производительность. **При проектировании системы сложнее всего изменить компоненты, определяющие взаимодействие между модулями и взаимодействие между модулями и внешним миром. Главными среди этих компонентов дизайна являются протоколы API и постоянные форматы данных. Мало того, что эти компоненты дизайна трудно или даже невозможно изменить постфактум, но все они могут серьезно ограничить производительность, которую должна достичь система;
- ** Помните о последствиях для производительности решений по проектированию API. ** Сделать общедоступные типы изменяемыми. Это может привести к созданию большого количества ненужных защитных копий (см. статью 39: Защитное копирование, когда это необходимо). Аналогичным образом, использование наследования в общедоступном классе, который соответствует шаблону композиции, навсегда привязывает класс к его суперклассу, искусственно ограничивая производительность подклассов.
-
В заключение
В заключение, не утруждайте себя написанием быстрых программ — старайтесь писать хорошие программы, и скорость естественным образом приложится. При проектировании системы, особенно при разработке API, протоколов проводного уровня и постоянных форматов данных, необходимо учитывать соображения производительности. После построения системы измерьте ее производительность. Если это достаточно быстро, ваша работа сделана. Если это не достаточно быстро, вы можете с помощью профилировщика найти источник проблемы и попытаться оптимизировать соответствующие части системы. Первый шаг — проверка выбранного алгоритма: никакая низкоуровневая оптимизация не может компенсировать неудачный выбор алгоритма. Повторяйте этот процесс по мере необходимости, измеряя производительность после каждого изменения, пока не будете удовлетворены.
8. Используйте абстракции для объявлений
-
вопрос
Рассмотрим встречный пример:
Vector<User> list= new Vector<User>();
В большинстве случаев нам нравится объявлять переменные с определенными типами, но здесь есть один недостаток: если мы захотим в будущем заменить Vector на ArrayList, это может повлиять на другие коды. Как лучше всего объявлять переменные?
-
решать
Более уместно объявлять переменные в виде интерфейса, как в приведенном выше примере, например:
List<User> list= new ArrayList<User>();
Преимущества:Программа более гибкая, если другой код использует методы в интерфейсе List, когда вы хотите изменить конкретный класс реализации, например, заменить здесь Vector на ArrayList, вам нужно только изменить конструктор, который не знает кода в других местах, и не повлияет на работу в других местах.
- Когда конкретные классы должны объявлять переменные?
- Классы могут использоваться для ссылки на объекты, если не существует подходящего интерфейса.. Например, учтите, что классы значений (String, BigInteger) редко пишутся с несколькими реализациями, они обычно являются окончательными и редко имеют соответствующие интерфейсы. Целесообразно использовать этот класс значений в качестве параметра, переменной, поля или типа возвращаемого значения;
- Случай, когда класс верхнего уровня является абстрактным классом, например абстрактный класс java.util.TimerTask, для ссылки на объект следует использовать соответствующий базовый класс (часто абстрактный класс), а не класс его реализации;
- Код основан на специальных свойствах конкретных классов.Например, в приведенном выше примере предполагается, что в программе необходимо использовать функцию безопасности потоков Vector.Если интерфейс используется для объявления переменных, случайное изменение класса реализации на ArrayList вызовет большие ошибки.
- Когда конкретные классы должны объявлять переменные?
-
В заключение
Параметры, возвращаемые значения, переменные и поля должны быть объявлены с типом интерфейса, если существует подходящий тип интерфейса. Это делает программу более гибкой, и если вы измените конкретный класс реализации интерфейса, другой код сможет продолжать работать.