После прочтения сего замечательного труда Джошуа Блоха (Joshua Bloch), захотелось сделать некоторые заметки себе на память. Захотелось - сделал!
Лексические проблемы
- Не употреблять английскую маленькую букву л в качестве имени переменной, так как она практически неотличима от числа один;
- Избегать восьмеричных констант;
- Аккуратно работать со вставками юникода;
- отрицательные шестнадцатеричные константы становятся положительными;
- Блочные комментарии не могут быть вложенными
Целочисленная арифметика
- Ненулевой результат операции "остаток от деления" возвращает знак левого операнда;
- Переполнение при целочисленных операциях происходит незаметно;
- Знак разницы двух целочисленных значений (int) не всегда определяет их порядок (изза возможного переполнения)
- Составной оператор может производить преобразование типа с потерей точности;
- Интегральные типы - несимметричны, так как Integer.MIN_VALUE и Long.MIN_VALUE равны собственным отрицаниям;
- Операции сдвига используют только младшие биты своих правых операндов;
- При приведении интегральных типов происходит расширение знака, если исходное значение имеет знак
Арифметика с плавающей точкой
- Никогда не используйте числа с плавающей точкой в вычислениях, которые требуют получение точного результата. В этом случае лучше использовать интегральные типы или BigDecimal
- Избегайте использовать числа с плавающей точкой в качестве индексов циклов
- Избегайте использовать унарные операторы типа ++ или -- на переменных, содержищих числа с плавающей точкой. В большинстве случаев они вообще не возымеют эффекта.
- Избегайте сравнений чисел с плавающей точкой на точное равенство.
- Предпочтительнее использовать double вместо float
- NaN не равно ни одному из чисел с плавающей точкой в том числе и самому себе
- Конвертирование из int -> float, long -> float, long -> double приводит к потере точности
- Всегда используйте new BigDecimal(String) вместо new BigDecimal(double)
Вычисление выражений
- Операторы & и | вычисляют оба операнда, даже если используются с булевыми значениями
- При проектировании внешнего API библиотеки в виде констант следует оформлять только те значения, которые действительно не будут меняться.
Управление выполнением программы
- Достаточно трудно остановить выполнение цикла с целочисленным индексом (int) на значении Integer.MAX_VALUE
- Необходимо следить, чтобы выполнение funally-блока завершалось нормально. Следует избегать возникновения исключительной ситуации внутри funally-блока. Никогда не использовать return внутри funally-блока.
- Не следует использовать исключительные ситуации для управления нормальным выполнением программы. Используйте их только для индикации настоящих исключительных ситуаций.
Инициализация классов
- Инициализация класса происходит сверху вниз
- NoClassDefFoundError очень не надежно в использовании. Вообще надо избегать использования исключений типа Error. Если есть необходимость работы с классами на низком уровне, то лучше использовать reflection
Создание и удаление экземпляров классов
- Инициализаторы экземпляра выполняются до конструктора. Тут следует избегать рекурсии
- Избегайте вызовов методов, которые могут быть переопределены, внутри конструктора. Так как в момент их вызова экземпляр объекта еще не инициализирован. Тут лучше использовать ленивую инициализацию.
- Не забывайте обнулять (null) ссылки на ненужные объекты внутри долгоживущих объектов. Иначе могут возникать утечки памяти. "unintended object retention"
- Избегайте использования finalizer. Это опасно, медленно и непредсказуемо!
- Избегайте использования интерфейса Cloneable. Если вы все таки его используете, копируйте все внутренние объекты, чтобы их состояние не было одновременно доступно оригинальному объекту и клону
Объекты и их экземпляры
- Статические методы не поддерживают динамическое связывание. Никогда не используете их с экземплярами - только с классами.
- Никогда не возвращайте null из метода, который должен возвращать массив или коллекцию
Повторное использование имен
- Очень легко ошибиться и перегрузить метод вместо его переопределения. Используйте возможности IDE, чтобы избежать ошибки. Еще лучше - использовать аннотацию Override
- Определение необходимого перегруженного метода не всегда происходит очевидно. Предпочтительно использовать статические фабрики вместо перегруженных конструкторов. Всегда проверяйте, что происходит вызов именно нужного перегруженного метода на реальных аргументах
- Старайтесь на затенять и не скрывать переменные.
- Не используйте в своей программе имена, которые используются в базовых библиотеках JDK/JRE
- Метод с именем как у его класса выглядит как конструктор, но им не является
Стоки
- В массивах не переопределен метод toString(). Поэтому для массивов символов (char) используйте String.valueOf(), а для массивов других типов - Arrays.toString()
- String.replaceAll - принимает регулярное выражение в качестве своего первого аргумента
- Последовательная конкатенация строк в цикле может привести к плохой производительности
- Значения типа char неявно конвертируются в int, а не в String
I/O
- PrintStream.write(int) не сбрасывает поток. (Не происходит неявного вызова flash())
- Явно обрабатывайте выходные потоки созданных внешних процессов, иначе они могут подвисать.
Нити (Threads)
- Никогда не вызывайте Thread.run() напрямую
- Объект сторонней библиотеки может блокировать или оповещать свои экземпляры или классы. Не следует использовать блокировку библиотечных классов или их экземпляров. используйте для блокировки свои объекты
- Thread.interrupted очищает interrupted статус
- Для избежания тупиковых блокировок никогда не ожидайте фонового процесса внутри инициализатора класса
- Вызывайте метод wait() только внутри цикла while
Reflection
- При создании экземпляра внутреннего класса требуется дополнительный аргумент.
- Используйте java.lang.reflect.Constructor.newInstance в случае если конструктор может бросать проверяемые исключения.
Serialization
- Объявление класса Serializable добавляет псевдоконструктор.
- Стандартный формат сериализации делает закрытые поля доступными.
- Чтобы обеспечить инвариантность сущностей необходимо использовать метод readResolve() для Singleton - объектов
- Если методы readObject() или readResolve() вызывают переопределяемые методы - это может случить причиной поврежденного графа объектов
Прочие библиотеки
- Переопределение equals() без переопределения hashCode() может привести к неправильной работе программы
- Некоторые устаревшие методы очень опасны. Избегайте использовать:
- Thread.stop()
- Thread.suspend()
- Runtime.runFinalizersOnExit()
- System.runFinalizersOnExit()
No comments:
Post a Comment