Это часть 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”