2013-02-20 1 views
2

Я создаю неизменяемое представление «события» в своей системе, и, таким образом, для списков владельцев, переданных в конструкторе, я хотел бы просмотреть их только для чтения. Кроме того, если они переходят в список null, я хотел бы сделать в этом случае пустой список для чтения.Лучший способ создания только для чтения, пустой список?

Теперь, так как Collections.unmodifiableList брусьев в null, я в настоящее время это:

userOwners_ = Collections.unmodifiableList(userOwners != null 
              ? userOwners 
              : new ArrayList<String>(0)); 

Но это кажется немного некрасиво и неэффективно. Есть ли более элегантный способ сделать это на Java?

+1

Пустой немодифицируемый список должен быть окончательным статическим (например, ENUM), я бы никогда не создавал новый объект неизменяемого пустого списка каждый раз. – Shivam

+2

Возможно, я не понимаю вашу проблему, но есть ли причина не использовать [Collections.emptyList()] (http://docs.oracle.com/javase/6/docs/api/java/util/Collections.html# emptyList())? –

+0

Спасибо всем за ваш вход, я прихожу с земли C# и пытаюсь перейти в стиль Java/практики, поэтому все входные данные были замечательными, и я попытался проголосовать за всех и хотел бы выбрать несколько ответов. .. –

ответ

2

Столь же некрасиво, но немного более эффективным ответом будет

userOwners_ = userOwners != null ? 
        Collections.unmodifiableList(userOwners) : 
        Collections.emptyList(); 

Однако есть несколько других вещей, чтобы наблюдать.

  1. Оказывается, что в какой-то момент, кто-то решил использовать null представлять пустой список. Это плохой дизайн ... и приводит к необходимости специальной обработки. Лучше установить его либо в новый список, либо в emptyList(), если вы знаете, что список всегда пуст.

  2. Если вы сознательно не решили, что null является способ представления пустого списка, то, что null является «неожиданным», и вы должны торчит пусть бросить NPE, так что вы можете отследить и устранить причину. (Это может быть переменная, которую вы предположили, инициализируется в другом месте ... но это не так. Это ошибка.)

  3. Существует некоторая путаница в отношении того, хотите ли вы «список только для чтения» или «неизменный» ":

    • Метод unmodifiableList() дает вам список, который вы не можете изменить; то есть «только для чтения». Но исходный список все еще может быть изменен, и эти изменения будут видны через оболочку «только для чтения».
    • Если вам нужен «неизменный» список (т. Е. Тот, который не может быть вообще изменен), вам необходимо указать clone() исходный список, а затем завернуть его, используя unmodifiableList().
    • Ни один из них не сделает элементы списка (объекты «владелец») неизменяемыми (если они еще не являются неизменяемыми).
  4. Идентификатор userOwners_ является нарушением стиля кода в наиболее распространенном/используемом руководстве по стилю Java.

+0

Hey Stephen, 1) часть оригинального дизайна, я просто обновляю код. 3) Я не знал, что о unmodifiableList(), я предположил (неправильно), что это была мелкая копия, а не только оболочка. 4) К сожалению, это устаревший код, который я модифицирую, и это стиль. –

+0

Мне понравились все ответы, но я думаю, что ваш казался самым полным, Стивен, спасибо всем! –

+0

@JamesMichaelHare - Re 1) и 4) ... вы можете исправить это. Тот факт, что код является устаревшим, не означает, что вы не можете его убрать/улучшить, и если вы ожидаете, что код прослужит дольше, есть твердый случай, который вы должны * исправить. ОК, 1) и 4) качественно отличаются друг от друга, но даже в этом случае ... И в случае 1) важно переработать то, что предназначалось первоначальному автору в отношении «нулевой» обработки. В противном случае вы рискуете * скрывать * ошибки с помощью «создания хороших» значений «null», которых не должно было быть. –

1

В результате пользователь userOwners_ по-прежнему будет изменен - ​​любые изменения в userOwners будут частью userOwners_.

Правильный способ сделать это, если вы действительно хотите, чтобы переменная-член будет неизменен:

private final List<String> userOwners; 

public MyObject(List<String> userOwners){ 
    this.userOwners = userOwners != null ? Collections.unmodifiableList(new ArrayList<String>(userOwners)) : Collections.emptyList(); 
} 

Как мелочью, член вашей переменной именование не следует руководящим принципам стиля Java (userOwners_ странно для тех, из нас, кто регулярно читает Java-код)

Чтобы развернуть то, что написал другой плакат: Подумайте, действительно, очень тяжело, прежде чем вы примете нулевой ввод публичному методу (без бросания NPE). Такое поведение может скрыть ошибки - гораздо лучше быстро выйти из строя и заставить вызывающего думать о том, что они делают.

+0

Но OP хочет список только для чтения, а не неизменный. Теперь это прекрасное различие ... но тем не менее, поэтому есть два разных термина. –

+0

@ StephenC На самом деле автор писал, что они создают «создание неизменяемого представления« события ». Я думаю, что мой совет по этому вопросу все еще стоит, b/c, что они сделали до сих пор, абсолютно * не * неизменяемо. –

+0

Да, у меня было плохое предположение о том, что unmodifiableList является мелкой копией, а не только оболочкой. Спасибо за разъяснения! –

5

Collections.emptyList(). Но серьезно, null должен NPE.

+0

Это модификация устаревшего кода, поэтому я не уверен, был ли исходный автор службы, в которой он находился, предполагал, что «null» является допустимым вводом. Но ваш вопрос хорошо принят. В ситуациях, подобных этому, считается ли он лучшим стилем на Java (извините, что я пришел из мира C#, так что пытаюсь сменить парадигму), чтобы выбросить исключение аргумента или позволить NPE пробиваться самостоятельно? Я бы хотел сделать первый, если Java-стиль не предпочитает более позднего ... –

+0

@JamesMichaelHare 'null' имеет тенденцию указывать на наличие некоторой ошибки. В Java обычная (хотя и не исключая) проблема заключается в том, чтобы уловить ошибки как можно раньше. Я собирался дать ссылку Effective Java, но все, что я вижу, - это элемент 43, не возвращающий null для коллекций и пример кода в Item 39. –

1

Мой предпочтительный способ будет использовать Guava:

this.userOwners = ImmutableList.copyOf(Preconditions.checkNotNull(userOwners)); 

Как ответ tackline, это также бросает исключение, а не молча перевод нуль в пустой список.

В отличие от других ответов здесь, использование ImmutableList.copyOf() гарантирует, что вызывающий абонент не сможет передать вам список, который они могут позже изменить.