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

Эффективная Java! Сделайте Защитные Копии При Необходимости

Погружение в главу 50 Эффективной Java. Помеченный java, эффективная, неизменяемая архитектура.

Эффективный обзор Java (Серия из 78 частей)

Одним из преимуществ Java как языка является то, что он может обеспечить некоторые меры безопасности, которых не обеспечивают другие языки более низкого уровня. Безопасность от таких вещей, как переполнение буфера, неуместные указатели и другие проблемы с повреждением памяти в таких языках, как C и C++. Тем не менее, Java не застрахована от проблем безопасности, и мы все равно должны быть бдительными.

Давайте рассмотрим пример того, где это может нам навредить. Давайте взглянем на класс с именем Period , который стремится быть неизменяемым классом, имеющим начало и конец Данные объект.

public final class Period {
  private final Date start;
  private final Date end;

  public Period(Date start, Date end) {
    if (start.compareTo(end) > 0) {
      throw new IllegalArgumentException("Start is after end");
    }
    this.start = start;
    this.end = end;
  }

  public Date start() {
    return start;
  }

  public Date end() {
    return end;
  }
}

На первый взгляд это может показаться разумной реализацией и тем, что она обеспечивает соблюдение инварианта начала, предшествующего концу. При этом, как говорится, довольно легко сломать этот инвариант. Это делает следующий код:

Date start = new Date()
Date end = new Date();
Period p = new Period(start, end);
end.setYear(50);

Последняя строка этого кода изменяет внутренности нашего объекта Period . Итак, какими способами мы можем это исправить? Вероятно, лучшим способом в Java 8 и более поздних версиях является использование одного из улучшенных объектов данных, которые были представлены в этой версии, таких как Instant или LocalDateTime . Это будет ваш лучший вариант. А как насчет случаев, когда у нас нет такой возможности? Давайте посмотрим на конструктор, который может помочь нам частично решить нашу проблему.

public Period(Date start, Date end) {
    this.start = new Date(start.getTime());
    this.end = new Date(end.getTime());
    if (start.compareTo(end) > 0) {
      throw new IllegalArgumentException("Start is after end");
    }
  }

С помощью только этого кода предыдущая атака была предотвращена. Следует отметить, что мы удаляем наши авторские права в конструкторе, не считывая значение, чтобы предотвратить временные атаки, когда значение изменяется между проверкой и сохранением. Наконец, мы не используем метод clone , чтобы избежать обхода подразумеваемой безопасности путем переопределения метода clone и придания ему небезопасной реализации.

Есть еще одно последнее место, которое нам нужно защитить, это добытчики, которых мы разоблачили. С тем, как они были реализованы выше, приемник объекта мог изменить внутреннее состояние.

  public Date start() {
    return new Date(start.getTime());
  }

  public Date end() {
    return new Date(end.getTime());
  }

С помощью этого простого изменения мы теперь действительно сделали этот класс неизменяемым.

Итак, каковы же недостатки создания этих защитных копий. Главной проблемой может быть нехватка памяти, которая может возникнуть из-за этого. Если эти копии выполняются в тесном, большом цикле, это может оказать значительное влияние на ваш код. Это не причина избегать использования защитных копий, но об этом следует помнить.

Так действительно ли все это того стоит? Неужели люди действительно так сильно хотят получить наш код? Как и многие части Эффективной Java Я считаю, что защитная копия для предотвращения атак в значительной степени применима для авторов библиотек, а не для тех из нас, кто пишет внутренний код. То, что защитные копии дают нам помимо защиты от атак, – это защита от случайных изменений нашего внутреннего состояния. Может быть легко случайно изменить это состояние, когда мы не делаем защитные копии, и ошибки может быть чрезвычайно трудно отследить.

Таким образом, защитные копии могут защитить наш код от плохих участников, а также от наших собственных ошибок без слишком большого количества дополнительного кода и усилий.

Эффективный обзор Java (Серия из 78 частей)

Оригинал: “https://dev.to/kylec32/effective-java-make-defensive-copies-when-necessary-4bd6”