1. Введение
2. Создание и уничтожение объектов
- Замена конструктора статическим фабричным методом - Полезно в случае:- Не понятное имя конструктора;
- Возножность создавать конструкторы с одинаковыми параметрами но разными именами;- Использование созданных членов класса;
- Возможность вернуть тип наследника. Пимер: не модифицируемые Collections;
- Возвращаемый тип может меняться от типа значения параметра;
 
- Можно улучшать реализацию от версии к версии;- Код эеземпляра не обязан существовать намемент вызова фабричного метода.
 
- Недостатки фабричного метода:- Классы только с статическими фабричными методами не могут порождать подклассы;
- Не всегда понятные имена ФМ. Потому нужно использовать принятое именование (pages: 33-34).
 
 
 
- Шаблон Bilder вместо множества параметров (в том числе пример рекурсивного Generic(pages: 40-41)- Плюсы:- Легче расширять;
- Лучше чем подход с JavaBeans (pages: 36-37)- Удобнее расширять в библиотеке.
 
- Минусы: 
- Время на нписание;
- Громоздкость при малом числе параметров.
 
- Синглтон - Рассмотрен вопрос сериализации (pages: 43-45).
- Особенности реализации:- Как поле класса;
- Метод getInstance();
- Enum с одним значением;
 
 
- Передача параметра лучше чем жестко зашитый ресурс (pages: 47-49):- Поддержка разных версий/языков, а также при тестировании;
- Проблема dependencyInjection;
- Разные классы могут использовать один/разные версии этого класса даже не подозревая об этом;
 
- Избегайте создания лишних объектов:- String s = new String("bad");
- long better than Long - не пользуем Bound Boxing где не нужно (яркий пример с циклом pages: 52-53).
 
- Избегайте устаревших ссылок на объекты:- Обнулять все подряд не нужно;
- Лучший вариант: ограничение области видимости переменной и автоматическое ее удаление;
- Случай с массивом объектов, которые не используются(удаленные элементы из стека, листа. page: 54);
- Кеш;
- Обратные вызовы - лучше использовать слабые ссылки.
 
- Финализаторы и очестители:- Не гарантируются;
- Устаревшие методы: System.runFinalizersOnExit(), Runtime.runFinalizersOnExit();
- Игнор исключений;
- Проблемы с производительностью;
- ДЕЛАЙТЕ КЛАСС AutoCloseable (pages: 60-62);
 
- Зачем же тогда они нужны?- Контроль вызова close для подстраховки;
- Удаление платформозавсисемых узлов(С++ и пр.)
 
 
- TRY с ресурсами используем вместо try-finaly.
 
3. Методы общие для всех объектов
- equals()- условия:- Рефлексивнсть x.equals(x) = true;
- Симметричность x.equals(y) , y.equals(x);
- Транзитивность x.equals(y), y.equals(z), z.equals(x);
- Непротиворечивость for(0~100000) x.equals(x)=true/false (always);
 
- x.equals(null) = false.
- Правила написания своего equals(Object o):- this==o;
- if(!(o instanceof MyType)) return fasle;
- Сравниваем значемые поля (начиная с более простых и более изменяемых);
- hashCode!!!!! нужно перекрыть при перекрытии equals (pages: 81-87).
 
 
- Правила написания своего hash:- Для примитивных полей Type.hashCode(f);- Сложные типы: поступайте как поступили для поля в equals, например просто вызовите hash();
- Arrays.hashCode();
 
- null - 0;- result = 31 * result + fieldHashValue.
 
- Низко скоросной, но полезный метод: Objects.hash(value1, object2, value3);
- Рекомендации по hash функции:- Используйте все значимые поля, иначе функция может вызвать неэффективность hashMap;
- Избегаем деталей реализации в описании, чтобы можно было поменять реализацию в будущем.
 
 
- clone & Clonable (see example on pages: 93-94):- Переопределить интерфейс Clonable достаточно, если нет сложных переменных, иначе нужно реализовать метод clone;
- Если сложные переменные final, то их не получится склонировать, но можно рекурсивно вызывать clone (это доделывается вручную в clone); 
 
- В случае если сложные элементы содержат ссылки друг на друга, то их тоже прийдется обновить или скопировать "по умному"(see example on pages: 95-97);- Можно просто не поддерживать клонирование: throw new cloneNotSupportedException() (see page: 98);
 
- Возможно, требуется синхронизация;
- Лучший вариант: написать копирующий конструктор - это понятнее и безопаснее.;- Массивы лучше копировать все же через clone.
 
- Comparable. 
- Метод выполняет сравнение бъекта с указанным:- Взвращает целое отрицательное, 0, целое положительное, если обект меньше, равен или больше указанного;
- Генерирует ClassCastException, если передан не тот тип обьекта.
 
- Свойства и советы:- Позволяет быстро сортировать: Arrays.sort(arr);
 
- Позволяет взаимодействовать с: TreeSet;
- Используйте стандартные static методы Comparator.comparingInt().thenComparingInt(). Они на 10% медлиннее рукописного компаратора, но очень удобны (See for example page: 105).
 
 
4 Классы и интерфейсы
- 1. Минимизируйте доступ к реализации:- Даем всегда минимальный уровень доступа;
- Исключения - static final поля:- Примитивные типы - норм;
- Сложные обекты очень окуратно;
- Массивы (see page: 113):- Преобразуем в неизменяемый список;
 
- Возвращаем клон массива в паблик методе а сам масив закрытым.
- Есть новых 2 типа доступа на уровне пакета, но они не очень полезные(see pages: 113-114).
 
 
- 2. В открытых классах используйте метод доступа а не открытые поля:- можно открытые, то только с пакетной видемостью;
- даже final не желательно но допустимо.
 
- 3. Минимизируйте изменяемость классов:- Как создать:- Все поля final;
- Все закрытое;
- Доступ только по методам;
- ЕСЛИ ЧТО создаем и возвращаем новый экземпляр. Это называется  ФУНКЦИОНАЛЬНЫЙ подход(for example see pages: 118-119).
 
 
- Приимущетва:- Потокобезопасность;
- public static final для часто используемых экземпляров;
- Использование фабоик для кеширования часто используемых объектов;
- Не требуется создавать защищенные копии;
- Не нужно предоставить копирующий конструктор или метод clone();
- Удобный строительный блок для других объектов;
- Кеширование долгоиграющих изменений в не final полях для ускорения.
 
- Поблемы:- Потеря ПРОИЗВОДИТЕЛЬНСОТИ при создании нового эеземпляра при каждой операции (примеры решения: StringBuilder, StringBuffeer).
 
- Особенности создания неизменяемых классов:- Все поля-объекты тоже долдны быть неизменяемые;
- нужно запретить наследование изменяемого класса, чтобы предупредить изменяемость в наследниках. Это можно сделать с помощью фабричных методов и приватных конструкторов;
- нужно делать копию каждого изменяемого объекта, который входит в изменяемый класс.
 
- ВЫВОДЫ: - Классы должны быть неизменяемыми, если нет серьезной причины для их изменяемости;
- Изменяемые классы при возможности должны иметь ограниченное число состояний;
- Все параметры по возможности private final;
- Конструкторы должны создавать полностью инициализированные обекты, все инварианты которых должны быть установлены.
 
- 4. Предпочитайте композицию наследодванию:- Можно использовать наследование после композиции (for example see pages: 128-129);
 
- Решает проблемы изменения унаследованого класса;
- Недостатки:- проблемы с callBack-ами;
- расход памяти и производительнсоть (на практике не оправдываются).
 
- Нвследование уместно только когда один обект всегда является подклассом другого;
- Наследование раскрывает детали реализации.
 
- 5. Проектируйте и документируйте наследование либо запрещайте его:- Класс должен  быть спроектирован для наследования:- Конструкторы не должны вызывать public, protected методы(for example see page: 135);
- Открытые к наследованию методы не должны вызываться в классе напрямую, а через приватные функции-обертки(pages: 137-138).
 
- Документация содержать информацию об наследовании(for example see pages: 132-133);
- Протестировать наследуемость можно написав несколько наследников, при этом:
- Не используемые методы закрыть;
- Открыть те, которые необходимы.
 
 
- 6. Предпочитайте интерфейсы абстрактным классам:- Позволяют создавать mixin-ы - добавочную функциональность (see page: 139);
- Для множественного наследования;
- Возможно реализовать на интерфейс еще абстрактный класс, который перекроет часть методов и упростит использование интерфейса.
 
- 7. Внимательно проектируйте интерфейсы:- Невозможно изменить;
- Методы по умолчанию помогают плохо. (пример с перекрытием removeIf see on pages: 144-146).
 
- 8. Используйте интерфейсы только для опеределения типов;- НЕ используем тлько константные классы:- Необходимость поддерживать их, даже если они уже не нужны;
- Запутывание пользователей.
 
- 9. Предпочитайте иерархию классов дескрипторам классов (когда один клас выполняет разные функции в зависемости от параметров типа TAG)(pages: 149-152)
- Запутанная реализация и нечитаемость;
- Слишком много кода;
- Много switch;
- Необходимость каждый раз запутывать класс еще больше.
 
- 10. Предпочитайте статические классы-члены нестатическим- static inner ckasses:- Не содержат ссылку на родителя;
- Можно создать без родителя.
 
- Анонимные классы имеют ряд ограничений:- Нелья применить instanceof;
- Нельзя операться на имя класса;
- Нельзя неследоваь и имплиментировать интерфейс одновременно.
 
 
- 11. Ограничивайтесь одним классом верхнего уровня на исходный файл.
5. Обобщенное программирование
- 1. Не используйте не сформированные типы: List data = new ArrayList<String>; (правильно так: List<String> data = ...):- Проблема: отсутствие проверки типов при компиляции;- Используйте  List<?> data. В этом случае типы БУДУТ ПРОВЕРЯТЬСЯ, а там где они не важны, они не будут использоваться (for example see page: 163);
 
- Исключения, где без не сформированных типов не обойтись:- List.class (List<String>.class и List<?>.class недопустимы) (page: 164);
- instanceof Set (<String>и <?> являются просто шумом и игнорируются) (page: 164);
- Простой пример как приводить типы <?> (page: 164).
 
 
- Резюме: - Set<Object> - может содержать обьекты любого типа;
- Set<?> - может содержать ТОЛЬКО обьекты некого неизвестного типа;
- Set - не бузопасный способ записи, которы не позволяет компилятору проверять приведение типов.
 
- Термины:- List<String> - Параметризированный тип с фактическим параметром String;
- List<E> - Обобщенный тип с формальным параметром E;
 
- List<?> - Неограниченный тип с символом подстановки;
- List - Несформированный тип;
- <E extends Number> - Ограниченный параметр типа;
- <T extends Comparable<T>> - Рекурсивно граниченный тип;
- <? extends Number> - Ограниченный тип с символом подстановки;
- <? super Number> - Ограниченный тип с символом подстаноEeвки;- <T extends Enum<T> & Operation> (page: 228 или пункт 6.5);
 
- static <E> List<E> asList(E[] a) - Обобщенный метод;
- String.class - Токен типа.
 
 
- 2. Устраняйте предупреждения о непроверяемом коде:- Анотация @SuppressWarnings("unchecked"):- Добавляем, только когда нельзя написать по другому и проверили, что точно работает;- Используем как можно реже и сужаем область видемости насколько можно (for example see pages: 167-168);
 
- Добавляем комментарий: почему мы добавили анотацию.
 
 
- 3. Предпочитайте списки массивам:- Массивы кованиантны(if Sub instanceof Super => Sub[ ] instanceof Super[ ]), а списки инвариантны (List<Type1> =!= List<type2>) (for example see pages: 169-170);
- Изза этих и друих (page: 169) различий массивы и обопщенные типы нельзя смешивать: List<E>[ ], new List<String>[ ], new E[ ] => ОШИБОЧНЫ;
- При сообщениях о проблемах постарайтесь заменть массивы списками (for example see pages: 171-173).
 
 
- 4-5. Предпочитайте обобщенные типы, обобщенные методы:- Пример с добавлением обобщенных типов в код: (pages: 178-180);
- Иногда, для обобщения возможных операций, нужно создать "обобщенную фабрику синглтонов" (page: 180);
- Рекурсивное ограничение типа применяется для Comparable: <E extends Comparable E> и можно прочитать как: "Любой тип Е, который можно сравнивать с самим собой".
 
- 6 используйте ограниченные символы подстановки для повышения гибкости АПИ (pages: 183-188):- Используем как параметры: <? extends Number>, <? super Number>;
- Правило: производитель extends, потребитель super (page: 185);
- Как созвращаемое значение только <E>;
- Символы подстановки должны быть "не видны" пользователям класса. Если пользователь класса должен думать о типах с символьной подстановкой, вероятно что-то не так с АПИ этого клласса.
 
- 7. Аккуратно сочитайте обопщенные типы и переменное число аргументов:- Нельзя использовать массив с переменным числом аргументов вне функции, так как это тот самый массив обобщенных типов, тип которого известен лишь при компиляции  (page: 192);
 
- Аннотацию SafeVarargs следует применять с осторожностью, но все же модно в методах с переменным числом аргументов;- Применение List более предпочтительно, чем переменное число аргументов (for example see page: 195).
 
- 8. Пименяйте безопасные с точки зрени типов гетерогенные контейнеры (for example see pages: 196-198).
 
6. Перечисления и анотации
- 1. Используйте перечисления вместо констант int  (page: 203):- Использовани подкласса для каждого элемента enum, объединение стратегии для групп enum значений (for example see page: 214).
 
- 2. Используйте поля экземпляров вместо порядковых значений;- 3. Используйте EnumSet вместо битовых полей (for example see page: 217-219);
- 4. Используйте EnumMap вместо индексирования порядковыми номерами (for example see page: 219-225);
 
- 5. Имитируйте расширяеміе перечисления с помощью интерфейсов (pages: 225-229):- Достаточно переопределить недастающие значения в другом enum, реализующим тот же интерфейс (pages: 225-227);
- Недостаток тут - возможное копирование похожей реализации. Для исючения копирования нужно выносить этот код в отдельный класс;
 
- 6. Предпочитайте анотации схемам именования:
 
- 7. Последовательно используйте анотацию @Override;- 8. Используйте интерфейсы-маркеры для определения типов (pages: 242-244):- Стоит использовать интерфейсы-маркеры, если мы хотим определить тип, и анотацию, елси мы не хотим определять тип.
 
 
7. Лямбда выражения и потоки
- 1. Предпочитайте лямбда выражения анонимным классам.- Если лямбда выражение длиннее 3 строк или слоджное для чтения, то либо найтдите способ его упростить, либо выполните рефакторинг для его устранения.
 
- 2. Предпочитайте ссылки на методы лямбда выражениям.- Типы ссылок:- Статическая   -   Intager::parseInt   -   str -> Intager.parseInt(str);
- Ограниченная   -   Instant::now()::isAfter   -   Instant then = Instant.now(); t -> then.isAfter(t);
- Неограниченная   -   String::toLowerCase   -   str -> str.toLowerCase();
- Конструктор класса   -   TreeMap<K,V>::new   -   () -> new TreeMap<K,V>;- Конструктор массива   -   int[ ]::new   -   len -> new int[len].
 
 
- 3. Предпочитайте использовать стандартные функциональные интерфейсы: