Рубрики
Без рубрики

Эффективная Java — Главы 6-9

Вступление Это часть 2 моего краткого изложения “Эффективной Java”. Для первой части этого… Помеченный java.

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