Неизменные объекты в Java и данных доступа

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

Если вы не воспроизвели ошибку, вы ее не понимаете. Возможно, вы обнаружили ошибку в системе, но это не гарантирует, что вы нашли ошибку , которую видел клиент.

Если вы не можете воспроизвести ошибку, вы не можете быть уверены, что она действительно исправлена. Вы можете лечить только симптом проблемы, а не основную проблему. У клиента может быть другой вектор для той же основной проблемы, и его проблема не будет исправлена.

5
задан 11 June 2009 в 02:58
поделиться

4 ответа

Вы можете использовать Collections.unmodifiableList и изменить метод данных.

public List<Double> data() { return Collections.unmodifiableList(getList()); }

Из javadoc:

Возвращает неизменяемое представление указанный список. Этот метод позволяет модули для предоставления пользователям доступ «только для чтения» к внутренним спискам. Операции запроса в возвращенном списке "прочитать" до указанного списка, и пытается изменить возвращенный список, будь то прямой или через его итератор, результат UnsupportedOperationException.

23
ответ дан 18 December 2019 в 05:23
поделиться

В Java нет синтаксической концепции неизменяемого класса. Вы, как программист, должны предоставить доступ к операциям, но всегда должны предполагать, что кто-то будет злоупотреблять этим.

По-настоящему неизменяемый объект не предлагает людям способа изменить состояние или получить доступ к переменным состояния, которые можно использовать для изменения состояния. Ваш класс не является неизменным, как сейчас.

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

Другой вариант - использовать коллекцию-оболочку, которая будет генерировать исключения во время выполнения, если кто-то попытается изменить значение (не рекомендуется, но возможно, см. Пример apache-collections). Я думаю, что и в стандартной библиотеке он есть (посмотрите под классом Collections).

Третий вариант, если одни клиенты изменяют данные, а другие нет, - это предоставить различные интерфейсы для вашего класса. Допустим, у вас есть IMyX и IMyImmutableX. Последний просто определяет «безопасные» операции, а первый расширяет его и добавляет небезопасные.

Вот несколько советов по созданию неизменяемых классов. http://java.sun.com/docs/books/tutorial/essential/concurrency/imstrat.html

5
ответ дан 18 December 2019 в 05:23
поделиться

Можете ли вы использовать Collections.unmodifiableList ?

Согласно документации, он вернет неизменяемое (неизменяемое) представление списка List . Это предотвратит использование таких методов, как remove и add , выбрасывая исключение UnsupportedOperationException .

Однако я не вижу, что этого не произойдет. предотвратить изменение фактических элементов в самом списке, поэтому я не совсем уверен, достаточно ли это неизменяемо. По крайней мере, сам список не может быть изменен.

Вот пример, в котором внутренние значения List , возвращаемые unmodifiableList , все еще могут быть изменены:

class MyValue {
    public int value;

    public MyValue(int i) { value = i; }

    public String toString() {
        return Integer.toString(value);
    }
}

List<MyValue> l = new ArrayList<MyValue>();
l.add(new MyValue(10));
l.add(new MyValue(42));
System.out.println(l);

List<MyValue> ul = Collections.unmodifiableList(l);
ul.get(0).value = 33;
System.out.println(l);

Вывод:

5
ответ дан 18 December 2019 в 05:23
поделиться

Есть несколько вещей, чтобы сделать ваш класс правильно неизменяемым. Я считаю, что это обсуждается в Эффективной Java.

Как упоминалось в ряде других ответов, чтобы остановить модификацию списка через возвращенный итератор, Collections.unmodifiableList предлагает чтение - только интерфейс. Если это был изменяемый класс, вы можете захотеть скопировать данные, чтобы возвращаемый список не изменился, даже если этот объект изменится.

Список, который передается конструктору, может быть позже изменен, поэтому его необходимо скопировать .

Класс является подклассом, поэтому методы можно переопределить. Так что сделайте класс окончательным . Лучше предоставить статический метод создания вместо конструктора.

public final class Wrapper implements Iterable<Double> {
    private final List<Double> list;

    private Wrapper(List<Double> list) {
        this.list = Collections.unmodifiableList(new ArrayList<Double>(list));
    }

    public static Wrapper of(List<Double> list) {
         return new Wrapper(list);
    }

    public Iterator<Double> iterator() {
        return list.iterator();
    }

    public List<Double> data() {
        return list;
    }
}

Также было бы полезно избегать табуляции и помещать фигурные скобки в правильное положение для Java.

5
ответ дан 18 December 2019 в 05:23
поделиться
Другие вопросы по тегам:

Похожие вопросы: