【问题标题】:Using next() to call next iteration of ArrayList使用 next() 调用 ArrayList 的下一次迭代
【发布时间】:2013-04-21 02:04:13
【问题描述】:

迭代器 next() 有点麻烦。似乎无法让它正常工作。我已经在这段代码上工作了一段时间,所以我认为另一双眼睛会有所帮助。

这是我的甲板类,它创建了一个 Card 对象列表,我正在尝试创建一种方法来获取列表中的下一张 Card,从第一个开始:

package blackjack;

import blackjack.Card.Rank;
import blackjack.Card.Suit;
import java.util.*;

public class Deck {

public ArrayList<Card> cards = new ArrayList<>();
int i;
Card next;

public Deck() {
    initializeDeck();

}

public void printDeck() {
    for (Card c: cards)
        System.out.println(c);
}

private void initializeDeck() {
    for (Suit suit : Suit.values()) {
        for (Rank rank : Rank.values()) {
            cards.add(new Card(rank, suit));
        }
    }
}

public Card getNextCard() {
    if (cards.listIterator().hasNext() != true) {
        getNextCard();
    }
    else {
        next = cards.listIterator().next();
    }
      return next; 
}
}

这是我调用 getNextCard() 的主要课程,我认为它应该打印列表中的第一张卡片,然后打印下一张卡片,但它所做的是打印第一张卡片两次。

package blackjack;

import java.util.*;

public class BlackJack {

public static void main(String[] args) {
    Deck deck = new Deck();
    System.out.println(deck.getNextCard());
    System.out.println(deck.getNextCard());
    }

}

提前感谢您的帮助!

【问题讨论】:

  • 喜欢 getNextCard() 中的 subtil 无限循环!
  • 看起来你每次都得到一个新的迭代器

标签: java arraylist next


【解决方案1】:

您总是会得到第一张卡片,因为每次调用 getNextCard () 方法时都会创建一个新的迭代器。线

next = cards.listIterator().next();

总是会创建一个新的迭代器。你想要做的看起来像(假设你想在每次到达牌组的最后一张牌时创建一个新的ListIterator 实例):

private ListIterator<Card> myIterator = null;

public Card getNextCard() {
    if (myIterator == null || !myIterator.hasNext ()) {
        myIterator = cards.listIterator ();
    }

    return myIterator.next(); 
}

【讨论】:

  • 刚刚尝试了那行代码,它仍然打印同样的东西
  • @NotaNoobForever 是的,我犯了一个错误。我用正确的代码修复了return 语句。
【解决方案2】:

你需要保存cards.listIterator()返回的迭代器。

您的代码每次都会创建一个新元素,这意味着您始终会获得第一个元素。

【讨论】:

    【解决方案3】:

    在您的getNextCard() 方法中,每次调用它时都会创建一个迭代器。迭代器总是从索引 0 开始(尽管有一个 listIterator(index) 方法),但你不应该需要它。

    选项 1: 跟踪迭代器,每次都使用相同的迭代器。然而,这有一个尚未被其他人指出的重要缺点。来自 Javadoc:

    这个类的iteratorlistIterator 方法返回的迭代器是快速失败的:如果列表在迭代器创建后的任何时间被结构修改,除了通过迭代器自己的删除或添加方法之外,迭代器将抛出一个ConcurrentModificationException

    翻译:如果您在迭代器之外以任何方式修改列表(例如,通过在列表末尾添加一张卡片),那么您的迭代器就会中断。这将我们引向选项 2:

    选项 2: 保留您上次返回的索引的计数器,并且每次都简单地返回。比如:

    public class Deck {
    
    public ArrayList<Card> cards = new ArrayList<>();
    Card next;
    int currentCardIndex = -1;
    
    /* The initialization stuff you have above */
    
    public Card getNextCard() {
    
        currentCardIndex++;
    
        // If we're at the end, go back to the beginning
        if (currentCardIndex >= cards.size()) {
            currentCardIndex = 0;
        }
    
        return (next = cards.get(currentCardIndex));
    }
    

    最后是选项 3:(不建议):如果你真的想要,你可以捕获 ConcurrentModificationException 并在此时生成一个新的迭代器,但没有真正的理由,除非您需要一些特定于迭代器的功能。 (get() 调用与交互器一样快 - 两者都是常数时间)。

    【讨论】:

    • 还没有尝试过,因为我必须去上班,但你的第二个选择是我将如何去做。谢谢!
    • 是的,这是可取的。祝你好运!
    猜你喜欢
    • 2014-06-30
    • 1970-01-01
    • 2014-06-30
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-11-07
    • 1970-01-01
    • 2014-06-13
    相关资源
    最近更新 更多