Это часть 2 моего резюме “Эффективная Java” . Для первой части этого резюме (главы 2-5) вы можете обратиться к этому сообщению .
Напоминание о том, что * Эффективная Java – это книга, похожая на справочник, и я постарался использовать это краткое изложение в качестве краткого ориентира. Я кратко изложил каждый пункт и включил в него свое мнение. Если вы обнаружили проблемы или у вас есть предложения, как сделать их проще и понятнее, пожалуйста, дайте мне знать.
Пункт 34
- Используйте перечисления вместо констант int
- Когда у нас есть перечислимый тип, значения которого представляют собой фиксированный набор констант, мы должны использовать
перечисление
. Плохими альтернативами являются постоянные строки или целые числа, подобные этому:
// bad public static final int APPLE_FUJI = 0; public static final int APPLE_PIPPIN = 1; public static final int ORANGE_NAVEL = 0; public static final int ORANGE_BLOOD = 1;
вместо этого мы можем использовать что-то вроде этого:
public enum Apple { FUJI, PIPPIN, GRANNY_SMITH } public enum Orange { NAVEL, BLOOD, TEMPLE }
- в этом пункте также говорится о различных недостатках использования постоянных целых чисел или строк. Например, в приведенном выше примере значения int используются как для типов апельсина, так и для яблок, позже мы сможем выполнять математические операции с этими целыми числами или потенциально можем сравнить эти целые числа, что математически разрешено, но мы в основном сравниваем яблоки с апельсинами! Они также подробны (длинные префиксы перед каждой константой —
APPLE_
) - перечисления предназначены для этого, и, кроме простого примера выше (что нам нужно в большинстве случаев), мы можем сделать их более продвинутыми с дополнительными функциями:
public enum Planet { MERCURY(3.302e+23, 2.439e5), VENUS(4.859e+24, 6.052e6), EARTH(5.975e+24, 6.378e6), ...; private final double mass; private final double radius; private final double surfaceGravity; // constructor Planet(double mass, double radius) { this.mass = mass; this.radius = radius; surfaceGravity = 6.6e-11 * mass / (radius*radius); } public double mass() {return mass;} public double radius() {return radius;} public double surfaceGravity() {return surfaceGravity;} public double surfaceWeight(double mass) { return mass * surfaceGravity; } }
- в приведенном выше примере кода мы связываем данные с константами перечисления (масса, радиус,..), и для этого мы должны добавить конструктор. мы также добавили общую функциональность, позволяющую легко рассчитать вес поверхности для каждой константы. Посмотрите на эти примеры использования приведенного выше перечисления:
double earthWeight = 158; // or read from input double mass = earthWeight / Planet.EARTH.surfaceGravity();
или
for (Planet planet : Planet.values()) { System.out.println("Weight on " + planet + " is " + planet.surfaceWeight(mass)); }
- обратите внимание, что все перечисления имеют статические
значения()
, которые возвращают массив их значений. у них также есть функция по умолчаниюtoString()
, которая возвращает объявленное имя каждого значения перечисления. Мы можем отменить это, если захотим. - Если перечисления необходимы только в классе, мы должны определить их как класс-член этого класса, но если они полезны в других местах, мы должны объявить их классом верхнего уровня.
- в
Планета
пример перечисления у нас была общая функциональность (вес поверхности ()
), которая была одинаковой для всех ее констант. Если нам нужен метод, который ведет себя по-разному для каждой константы, лучший подход – определить абстрактный метод и реализовать его следующим образом:
public enum Operation { PLUS("+") {public double apply(double x, double y){return x + y;} }, MINUS("-") {public double apply(double x, double y){return x - y;} }, TIMES("*") {public double apply(double x, double y){return x * y;} }, DIVIDE("/") {public double apply(double x, double y){return x / y;} }; public abstract double apply(double x, double y); public final String symbol; Operation(String symbol) { this.symbol = symbol; } }
Пункт 35
- Используйте поля экземпляра вместо ординалов
- перечисления имеют порядковый метод, который возвращает значение int для каждого элемента (в порядке их определения, 0-индекс)
- в некоторых ситуациях у нас может возникнуть соблазн получить значение
порядковый номер()
и использовать его. Не делай этого!! - если вам нужно связать значение с каждым элементом, даже с int, используйте поля экземпляра, как описано в пункт 34 .
Пункт 36
- Используйте набор перечислений вместо битовых полей
- когда элементы перечисления предназначены для использования в наборе, традиционно многие ppl используют шаблон перечисления int, а вместо перечисления для каждого элемента они определяют разную степень 2 и для их передачи используют битовое поле :
public class Text { public static final int STYLE_BOLD = 1 << 0; // 1 public static final int STYLE_ITALIC = 1 << 0; // 2 public static final int STYLE_UNDERLINE = 1 << 0; // 4 // ... public void applyStyles(int styles) {...} }
и чтобы использовать их и передавать по кругу, вместо набора мы можем сделать это: text.apply Стили(STYLE_BOLD | STYLE_ITALIC);
(мы передаем что-то вроде 100101
в котором каждый 1
говорит, что мы должны применить этот стиль)
- Пакет Java.util содержит
EnumSet
, который следует использовать вместо этих битовых полей. он обеспечивает безопасность типов и совместимость наборов и внутренне использует битовый вектор, что делает его производительность сопоставимой с битовыми полями:
public class Text { public enum Style { BOLD, ITALIC, UNDERLINE, STRIKETHROUGH } public void applyStyles(Set
Оригинал: “https://dev.to/ashkanent/effective-java-chapters-6-to-9-5d35”