Dec 27, 2008

New CV

Получил новый сертификат и обновил свое CV. http://docs.google.com/View?docID=dmsrn2h_65c5qj8jwm&revision=_latest

Jun 24, 2008

Java Puzzlers

После прочтения сего замечательного труда Джошуа Блоха (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()