Соответствующий раздел спецификации C# 3.0 7.13, условный оператор:
вторые и третьи операнды?: управление оператором тип условного выражения. Позвольте X и Y быть типами вторых и третьих операндов. Затем
, Если X и Y являются тем же типом, то это - тип условного выражения Иначе, если неявное преобразование (В§6.1) существует от X до Y, но не от Y до X, то Y является типом условного выражения. Иначе, если неявное преобразование (В§6.1) существует от Y до X, но не от X до Y, то X тип условного выражения. Иначе никакой тип выражения не может быть определен, и ошибка времени компиляции происходит.
Вы можете вручную перебирать элементы набора:
Iterator<Integer> iterator = set.iterator();
while (iterator.hasNext()) {
Integer element = iterator.next();
if (element % 2 == 0) {
iterator.remove();
}
}
Вы часто будете видеть этот шаблон, используя цикл for
, а не while
loop:
for (Iterator<Integer> i = set.iterator(); i.hasNext();) {
Integer element = i.next();
if (element % 2 == 0) {
i.remove();
}
}
Как уже отмечалось, использование цикла for
предпочтительнее, потому что он сохраняет переменную итератора ( i
в данном случае) ограниченной областью меньшего размера.
Причина, по которой вы получаете исключение ConcurrentModificationException
, заключается в том, что запись удаляется с помощью Set.remove () в отличие от Iterator.remove ( ) . Если запись удалена с помощью Set.remove () во время итерации, вы получите исключение ConcurrentModificationException. С другой стороны, удаление записей с помощью Iterator.remove () в этом случае поддерживается итерация.
Новый цикл for хорош, но, к сожалению, в этом случае он не работает, потому что вы не может использовать ссылку на итератор.
Если вам нужно удалить запись во время итерации, вам нужно использовать длинную форму, которая напрямую использует итератор.
for (Iterator<Integer> it = set.iterator(); it.hasNext();) {
Integer element = it.next();
if (element % 2 == 0) {
it.remove();
}
}
Должен ли он быть во время итерации? Если все, что вы делаете, это фильтруете или выбираете, я бы предложил использовать Apache Commons CollectionUtils . Там есть несколько мощных инструментов, и это делает ваш код «круче».
Здесь ' s реализация, которая должна предоставить то, что вам нужно:
Set<Integer> myIntegerSet = new HashSet<Integer>();
// Integers loaded here
CollectionUtils.filter( myIntegerSet, new Predicate() {
public boolean evaluate(Object input) {
return (((Integer) input) % 2 == 0);
}});
Если вы обнаружите, что часто используете один и тот же тип предиката, вы можете вытащить его в статическую переменную для повторного использования ... назовите это как-то вроде EVEN_NUMBER_PREDICATE
. Некоторые могут увидеть этот код и объявить его «трудным для чтения», но он выглядит чище, когда вы вытаскиваете предикат в статический. Тогда легко увидеть, что мы делаем CollectionUtils.filter (...)
, и он кажется более читаемым (для меня), чем куча циклов на всем протяжении создания.
CollectionUtils.filter (...)
, и он кажется более читаемым (для меня), чем куча циклов на всем протяжении создания. но он выглядит чище, если вытащить Predicate в статический. Тогда легко увидеть, что мы делаем CollectionUtils.filter (...)
, и он кажется более читаемым (для меня), чем куча циклов на всем протяжении создания. вы также можете реорганизовать свое решение, удалив первый цикл:
Set<Integer> set = new HashSet<Integer>();
Collection<Integer> removeCandidates = new LinkedList<Integer>(set);
for(Integer element : set)
if(element % 2 == 0)
removeCandidates.add(element);
set.removeAll(removeCandidates);
Другое возможное решение:
for(Object it : set.toArray()) { /* Create a copy */
Integer element = (Integer)it;
if(element % 2 == 0)
set.remove(element);
}
Или:
Integer[] copy = new Integer[set.size()];
set.toArray(copy);
for(Integer element : copy) {
if(element % 2 == 0)
set.remove(element);
}