Java 在迭代期间向集合添加元素
可以在迭代集合时向集合添加元素吗 更具体地说,我想迭代一个集合,如果一个元素满足某个条件,我想向集合中添加一些其他元素,并确保这些添加的元素也被迭代。(我意识到这可能会导致一个未终止的循环,但我很确定在我的情况下不会。) 来自Sun的建议表明这是不可能的:“请注意,Java 在迭代期间向集合添加元素,java,iterator,Java,Iterator,可以在迭代集合时向集合添加元素吗 更具体地说,我想迭代一个集合,如果一个元素满足某个条件,我想向集合中添加一些其他元素,并确保这些添加的元素也被迭代。(我意识到这可能会导致一个未终止的循环,但我很确定在我的情况下不会。) 来自Sun的建议表明这是不可能的:“请注意,Iterator.remove是在迭代过程中修改集合的唯一安全方法;如果在迭代过程中以任何其他方式修改了基础集合,则该行为是未指定的。” 如果我不能用迭代器完成我想做的事情,你建议我怎么做?用你想迭代的元素构建一个队列怎么样;当您想要
Iterator.remove
是在迭代过程中修改集合的唯一安全方法;如果在迭代过程中以任何其他方式修改了基础集合,则该行为是未指定的。”
如果我不能用迭代器完成我想做的事情,你建议我怎么做?用你想迭代的元素构建一个队列怎么样;当您想要添加元素时,请在队列末尾将它们排队,并继续删除元素,直到队列为空。这就是广度优先搜索通常的工作方式。一般来说,它不安全,尽管对于某些收藏可能是。明显的替代方法是使用某种for循环。但是您没有说明您使用的是什么收藏,所以这可能是可能的,也可能是不可能的。这里有两个问题: 第一个问题是,在
迭代器
返回后添加到集合
。如前所述,修改基础集合时没有定义的行为,如迭代器的文档中所述。删除:
。。。迭代器的行为是
未指明是否存在潜在的
集合被修改,而
迭代正在以任何方式进行
而不是通过调用此方法
第二个问题是,即使可以获得迭代器
,然后返回到迭代器
所在的相同元素,也无法保证迭代的顺序,如方法文档中所述:
。。。没有关于这一点的保证
元素的排列顺序
已返回(除非此集合是
提供
担保)
例如,假设我们有一个列表[1,2,3,4]
假设5
是在迭代器
位于3
时添加的,不知何故,我们得到了一个迭代器
,它可以从4
恢复迭代。但是,不能保证5
将在4
之后出现。迭代顺序可能是[5,1,2,3,4]
——那么迭代器仍然会错过元素5
由于没有对行为的保证,人们不能假设事情会以某种方式发生
一种替代方法是,创建一个单独的集合
,将新创建的元素添加到其中,然后迭代这些元素:
Collection<String> list = Arrays.asList(new String[]{"Hello", "World!"});
Collection<String> additionalList = new ArrayList<String>();
for (String s : list) {
// Found a need to add a new element to iterate over,
// so add it to another list that will be iterated later:
additionalList.add(s);
}
for (String s : additionalList) {
// Iterate over the elements that needs to be iterated over:
System.out.println(s);
}
结果如下:
1
2
3
4
42
正如所希望的那样,当我们点击2
时添加的元素42
出现了。您可能还想看看一些更专业的类型,如和(如果您对地图感兴趣)。使用迭代器……不,我不这么认为。你必须把这样的东西拼凑起来:
Collection< String > collection = new ArrayList< String >( Arrays.asList( "foo", "bar", "baz" ) );
int i = 0;
while ( i < collection.size() ) {
String curItem = collection.toArray( new String[ collection.size() ] )[ i ];
if ( curItem.equals( "foo" ) ) {
collection.add( "added-item-1" );
}
if ( curItem.equals( "added-item-1" ) ) {
collection.add( "added-item-2" );
}
i++;
}
System.out.println( collection );
CollectionCollection=newarrayList(Arrays.asList(“foo”、“bar”、“baz”);
int i=0;
而(i
哪种类型:
[foo,bar,baz,added-item-1,added-item-2]我更喜欢从功能上处理集合,而不是就地对它们进行变异。这完全避免了此类问题,以及别名问题和其他棘手的bug来源
因此,我将像这样实施它:
List<Thing> expand(List<Thing> inputs) {
List<Thing> expanded = new ArrayList<Thing>();
for (Thing thing : inputs) {
expanded.add(thing);
if (needsSomeMoreThings(thing)) {
addMoreThingsTo(expanded);
}
}
return expanded;
}
列表展开(列表输入){
展开列表=新建ArrayList();
用于(事物:输入){
扩展。添加(事物);
如果(需要记忆(事物)){
添加更多内容(扩展);
}
}
回报扩大;
}
IMHO更安全的方法是创建一个新集合,迭代给定集合,在新集合中添加每个元素,并根据需要在新集合中添加额外的元素,最后返回新集合。除了使用附加列表和调用addAll在迭代后插入新项的解决方案(如用户Nat的解决方案)之外,您还可以使用并发集合,如
“快照”样式的迭代器方法使用对创建迭代器时数组状态的引用。该数组在迭代器的生命周期内不会更改,因此不可能发生干扰,并且迭代器保证不会抛出ConcurrentModificationException
通过这个特殊的集合(通常用于并发访问),可以在遍历基础列表的同时对其进行操作。但是,迭代器不会反映这些更改
这比其他解决方案好吗?可能不会,我不知道写时拷贝方法带来的开销。实际上这很容易。想想最佳的方法。
我相信最佳的方式是:
for (int i=0; i<list.size(); i++) {
Level obj = list.get(i);
//Here execute yr code that may add / or may not add new element(s)
//...
i=list.indexOf(obj);
}
for(int i=0;ipublicstaticvoidmain(String[]args)
{
//此数组列表模拟要处理的候选对象的源
ArrayList源=新的ArrayList();
//这是您实际保留所有未处理候选项的列表
LinkedList=新建LinkedList();
//在这里,我们在模拟的候选源中添加了一些元素
//只是想找点事做
source.add(“第一个元素
for (int i=0; i<list.size(); i++) {
Level obj = list.get(i);
//Here execute yr code that may add / or may not add new element(s)
//...
i=list.indexOf(obj);
}
public static void main(String[] args)
{
// This array list simulates source of your candidates for processing
ArrayList<String> source = new ArrayList<String>();
// This is the list where you actually keep all unprocessed candidates
LinkedList<String> list = new LinkedList<String>();
// Here we add few elements into our simulated source of candidates
// just to have something to work with
source.add("first element");
source.add("second element");
source.add("third element");
source.add("fourth element");
source.add("The Fifth Element"); // aka Milla Jovovich
// Add first candidate for processing into our main list
list.addLast(source.get(0));
// This is just here so we don't have to have helper index variable
// to go through source elements
source.remove(0);
// We will do this until there are no more candidates for processing
while(!list.isEmpty())
{
// This is how we get next element for processing from our list
// of candidates. Here our candidate is String, in your case it
// will be whatever you work with.
String element = list.pollFirst();
// This is where we process the element, just print it out in this case
System.out.println(element);
// This is simulation of process of adding new candidates for processing
// into our list during this iteration.
if(source.size() > 0) // When simulated source of candidates dries out, we stop
{
// Here you will somehow get your new candidate for processing
// In this case we just get it from our simulation source of candidates.
String newCandidate = source.get(0);
// This is the way to add new elements to your list of candidates for processing
list.addLast(newCandidate);
// In this example we add one candidate per while loop iteration and
// zero candidates when source list dries out. In real life you may happen
// to add more than one candidate here:
// list.addLast(newCandidate2);
// list.addLast(newCandidate3);
// etc.
// This is here so we don't have to use helper index variable for iteration
// through source.
source.remove(0);
}
}
}
while (!list.isEmpty()){
Object obj = list.get(0);
// do whatever you need to
// possibly list.add(new Object obj1);
list.remove(0);
}
List<ZeObj> myList = new ArrayList<ZeObj>();
// populate the list with whatever
........
int noItems = myList.size();
for (int i = 0; i < noItems; i++) {
ZeObj currItem = myList.get(i);
// when you want to add, simply add the new item at last and
// increment the stop condition
if (currItem.asksForMore()) {
myList.add(new ZeObj());
noItems++;
}
}
LinkedList<String> l = new LinkedList<String>();
l.addLast("A");
while(!l.isEmpty()){
String str = l.removeFirst();
if(/* Condition for adding new element*/)
l.addLast("<New Element>");
else
System.out.println(str);
}
Set<T> adds = new HashSet<T>, dels = new HashSet<T>;
for ( T e: target )
if ( <has to be removed> ) dels.add ( e );
else if ( <has to be added> ) adds.add ( <new element> )
target.removeAll ( dels );
target.addAll ( adds );
public static void main(String[] args) {
ArrayList a = new ArrayList(Arrays.asList(new String[]{"a1", "a2", "a3","a4", "a5"}));
ArrayList b = new ArrayList(Arrays.asList(new String[]{"b1", "b2", "b3","b4", "b5"}));
merge(a, b);
a.stream().map( x -> x + " ").forEach(System.out::print);
}
public static void merge(List a, List b){
for (Iterator itb = b.iterator(); itb.hasNext(); ){
for (ListIterator it = a.listIterator() ; it.hasNext() ; ){
it.next();
it.add(itb.next());
}
}
}
List<Integer> intList = new ArrayList<>();
intList.add(1);
intList.add(2);
intList.add(3);
intList = intList.stream().flatMap(i -> {
if (i == 2) return Stream.of(i, i * 10); // condition for adding the extra items
return Stream.of(i);
}).map(i -> i + 1)
.collect(Collectors.toList());
System.out.println(intList);
List<String> l = new ArrayList<>();
l.add("Foo");
ListIterator<String> iter = l.listIterator(l.size());
while(iter.hasPrevious()){
String prev=iter.previous();
if(true /*You condition here*/){
iter.add("Bah");
iter.add("Etc");
}
}
import java.util.ArrayList;
import java.util.List;
import java.util.ListIterator;
public class ModifyWhileIterateQueue<T> {
ListIterator<T> listIterator;
int frontIndex;
List<T> list;
public ModifyWhileIterateQueue() {
frontIndex = 0;
list = new ArrayList<T>();
listIterator = list.listIterator();
}
public boolean hasUnservicedItems () {
return frontIndex < list.size();
}
public T deQueue() {
if (frontIndex >= list.size()) {
return null;
}
return list.get(frontIndex++);
}
public void enQueue(T t) {
listIterator.add(t);
}
public List<T> getUnservicedItems() {
return list.subList(frontIndex, list.size());
}
public List<T> getAllItems() {
return list;
}
}
@Test
public final void testModifyWhileIterate() {
ModifyWhileIterateQueue<String> queue = new ModifyWhileIterateQueue<String>();
queue.enQueue("one");
queue.enQueue("two");
queue.enQueue("three");
for (int i=0; i< queue.getAllItems().size(); i++) {
if (i==1) {
queue.enQueue("four");
}
}
assertEquals(true, queue.hasUnservicedItems());
assertEquals ("[one, two, three, four]", ""+ queue.getUnservicedItems());
assertEquals ("[one, two, three, four]", ""+queue.getAllItems());
assertEquals("one", queue.deQueue());
}