Проверьте, существует ли только один элемент с использованием Guava - PullRequest
5 голосов
/ 03 апреля 2012

Недавно мне нужно было создать сценарий «особого случая», если в коллекции существует только один элемент.Проверка на ...size() == 1 и получение с использованием ...iterator.next() выглядело ужасно, поэтому я создал два метода в классе коллекций home brew:

public class Collections {
    public static <T> boolean isSingleValue(Collection<T> values) {
        return values.size() == 1;
    }

    public static <T> T singleValue(Collection<T> values) {
        Assert.isTrue(isSingleValue(values));
        return values.iterator().next();
    }
}

Несколько дней назад я обнаружил, что в Гуаве есть метод с именем Iterables.getOnlyElement .Он покрывает мои потребности и заменяет singleValue, но я не могу найти соответствие для isSingleValue.Это по замыслу?Стоит ли ставить запрос на добавление метода Iterables.isOnlyElement?

РЕДАКТИРОВАТЬ: Поскольку было несколько голосов, я решил открыть улучшение на гуаве - выпуск 957 .Окончательное решение - «WontFix».Аргументы очень похожи на то, что предоставил Томас / Xaerxess.

Ответы [ 3 ]

10 голосов
/ 03 апреля 2012

Что ж, вы не получите много, если замените values.size() == 1 на метод, за исключением того, что вы можете проверить на ноль.Однако в Apache Commons Collections есть методы (а также в Guava, я полагаю) для этого.

Я бы лучше написал if( values.size() == 1 ) или if( SomeHelper.size(values) == 1 )
, чем if( SomeHelper.isSingleValue(values) ) - намерение гораздо яснее в первых двух подходах, и написать столько же кода, сколько и в третьем.

6 голосов
/ 03 апреля 2012

Просто в дополнение к другим ответам (я собирался написать что-то вроде @daveb, который удалил свой: Если нет точно одного элемента, то Iterables#getOnlyElement выдаст IllegalArgumentException или NoSuchElementException) - ответ на вопрос, почему в Гуаве нет Iterables.isSingleValue(Iterable).

Я думаю, ты ошибаешься. Если:

  • вызов метода не изменяет состояние (в отличие от next() в итераторе, поэтому существует hasNext())
  • и вы можете ясно и явно сказать, что возвращаемое значение не является исключительным случаем (в отличие от null, возвращаемого из Map#get(Object) - это может быть нулевое значение или это может означать, что ключ не был найден в карте)

нет необходимости проверять метод, если условие истинно, а затем выполнять некоторую операцию (с утверждением в нем!), Как в вашем примере кода.

Если вы абсолютно уверены, что итерация в этом месте не может иметь размер, отличный от 1, тогда проверка условий является излишней (исключение выдается в других случаях).
Если вы хотите получить только первый элемент в непустой коллекции - collection.iterator.next() совершенно нормально (NoSuchElementException выбрасывается, если коллекция пуста).
Если вы ничего не знаете о размере коллекции, тогда Iterables.getFirst(iterable, default) для вас.

P.S. Если ваш Collections#isSingleValue здесь используется только локально (следовательно, может быть закрытым), то действительно означает, что вам не нужна эта проверка перед вызовом Iterables#getOnlyValue.

P.P.S. Другим ответом на ваш вопрос о дизайне Гуавы может быть пункт 57 из Effective Java Джошуа Блоха - в Гуаве я упомянул несколько различных вспомогательных методов, которые прямо говорят, что является исключительным случаем для каждого; логическая проверка не была добавлена, потому что API был как можно меньше.

0 голосов
/ 27 февраля 2014

Прямо сейчас у меня та же проблема.

Я решу с этим кодом:

public static <T> void hasJustOne(T... values) {
    hasJustOne(Predicates.notNull(), values);
}

public static <T> void hasJustOne(Predicate<T> predicate, T... values) {
    Collection<T> filtred = Collections2.filter(Arrays.asList(values),predicate);
    Preconditions.checkArgument(filtred.size() == 1);
}
...