非常に多くの時間を循環させるための、しかし、あなたが本当にそれを知っていますか?

まず、ループの基礎

0は、また、関連するループのために探求するためにここに、円形の方法を使用している間、それは展開されません。

図1に示すように、アレイを介して、ループに使用される初心者パターン次

for(int i=0;i<a.length;i++){
    System.out.println(n);
}

時間の収集および使用することにより2は、イテレータイテレータのとおりです。

:名前のセットを考えると、以下を達成するために、(ここではあなた自身とあなたのチームを許可する)チーム対毎の

enum Option {Tom, Jerry, Jack, Mary}

言葉遣いは想像:

Collection<Option> options = Arrays.asList(Option.values());
for(Iterator<Option> i = options.iterator(); i.hasNext();){
    for (Iterator<Option> j = options.iterator(); j.hasNext();) {
        System.out.println(i.next()+" "+j.next());
    }

しかし、あなたは、このコードの実装後わずか4グループで、その結果、欠陥があることがわかります。

だからここでポートフォリオの残りの部分はにありますか?

このプログラムは、単にので、例外をスローしないi.next()値が削除されるたびに、その前の図がありました。

しかし、外側の要素は、要素の内部セットよりも大きい場合。

次のコード例:

enum OptionFirst {Tom, Jerry, Jack, Mary}
enum OptionSecond {Tom, Jerry, Jack, Mary, Mali, Tomsun, Lijie, Oolyyou}

public static void main(String[] args) {
    Collection<OptionFirst> optionFirstCollection = Arrays.asList(OptionFirst.values());
    Collection<OptionSecond> optionSecondCollection = Arrays.asList(OptionSecond.values());
    for (Iterator<OptionFirst> i = optionFirstCollection.iterator(); i.hasNext(); ) {
        for (Iterator<OptionSecond> j = optionSecondCollection.iterator(); j.hasNext(); ) {
            System.out.println(i.next() + " " + j.next());
        }
    }
}

実行した後に、スローされますjava.util.NoSuchElementException循環が生じ、なぜなら内部要素の不足のサイクル数を呼び出し、しないように外側のループが異常を投げたので、例外を、原因があります。

この種の問題を解決するためにのみ、外部の要素の第2サイクルの前に保持する変数を追加する必要があります。あなたが達成したい効果を得ることができます。

Collection<Option> options = Arrays.asList(Option.values());
for(Iterator<Option> i = options.iterator(); i.hasNext();){
    Option option = i.next();
    for (Iterator<Option> j = options.iterator(); j.hasNext();) {
        System.out.println(option+" "+j.next());
    }
}

二、のために、各ループ

このサイクル方法、アレイまたはコレクションは実用的で、より効率的であるかどうか、発現のより簡潔な形。

for(Element e:elements){
    System.out.println(e);
}

上記の質問に再び二十から二チームアップに直面したとき、より簡潔な不十分な要素の問題だけでなく、コードを考慮する必要はありません。

for (Option option : options) {
    for (Option rank : options) {
        System.out.println(option + " " + rank);
    }
}

「効果的なJavaは」このため、各ループのように書かれています:

三、それぞれのために、神ではありません

彼はのために、それぞれ非常に多くの利点を言ったが、それは、万能薬ではない、それは注意が必要であることを三つの条件があり、神ではありません。

3.1フィルタ、解体を使用することができません

あなたは、コレクションをループする必要があり、選択された要素を削除した場合、あなたはそれがそのremoveメソッドを呼び出すことができるようにすることを、明示的なイテレータを使用する必要があります。しかし、removeIf Java8収集方法の増加は、多くの場合、明示的なトラバースを避けます。

次のコード例:

List<String> list = new ArrayList<String>();

list.add("1");
list.add("2");

for (String item : list) {
    if ("1".equals(item)) {
        list.remove(item);
        System.out.println("执行if语句成功");
    }
}

このコードは何の問題、配列リストが正常に要素1を削除することはできません、あなたが対応する文をプリントアウトすることができ、直接実行されます。

しかし、我々は、いずれか、次の操作を行います。

  • list.remove(アイテム)list.add(「3」)に置き換えた場合、操作する方法?
  • (「3」)ライン6にlist.addの添加、その後のコードは間違いだろうか?
  • 若把if语句中的“1”换成“2”,结果你感到意外吗?

如果都能正确执行当然就不需要问了,所以3个都会报ConcurrentModificationException的异常;
执行结果异常

而出现这些情况的原因稍稍解释下就是:

首先,这涉及多线程操作,Iterator是不支持多线程操作的,List类会在内部维护一个modCount的变量,用来记录修改次数。

举例:ArrayList源码

protected transient int modCount = 0;

每生成一个Iterator,Iterator就会记录该modCount,每次调用next()方法就会将该记录与外部类List的modCount进行对比,发现不相等就会抛出多线程编辑异常。

为什么这么做呢?我的理解是你创建了一个迭代器,该迭代器和要遍历的集合的内容是紧耦合的,意思就是这个迭代器对应的集合内容就是当前的内容,我肯定不会希望在我冒泡排序的时候,还有线程在向我的集合里插入数据对吧?所以Java用了这种简单的处理机制来禁止遍历时修改集合。

至于为什么删除“1”就可以呢,原因在于foreach和迭代器的hasNext()方法,foreach这个语法,实际上就是

while(itr.hasNext()){
    itr.next()
}

所以每次循环都会先执行hasNext(),那么看看ArrayList的hasNext()是怎么写的:

public boolean hasNext() {
    return cursor != size;
}

cursor是用于标记迭代器位置的变量,该变量由0开始,每次调用next执行+1操作,于是:

所以代码在执行删除“1”后,size=1,cursor=1,此时hasNext()返回false,结束循环,因此你的迭代器并没有调用next查找第二个元素,也就无从检测modCount了,因此也不会出现多线程修改异常;但当你删除“2”时,迭代器调用了两次next,此时size=1,cursor=2,hasNext()返回true,于是迭代器傻乎乎的就又去调用了一次next(),因此也引发了modCount不相等,抛出多线程修改的异常。

当你的集合有三个元素的时候,你就会神奇的发现,删除“1”是会抛出异常的,但删除“2”就没有问题了,究其原因,和上面的程序执行顺序是一致的。

因此,在《阿里巴巴Java开发手册中有这样一条规定》:

3.2、转换

如果需要遍历列表或数组,并取代它的部分或者全部元素值,就需要使用列表迭代器或者数组索引,以便替换元素的值。

因为for-each是一循到底的,中间不做停留和位置信息的显示;所以要替换元素就不能使用它了。

3.3、平行迭代

如果需要并行的遍历多个集合,就需要显式的控制迭代器或者索引变量,以便所有迭代器或者索引变量都可以同步前进(就像上面讲述Iterator迭代器的时候提到的组合减少的情况,只想出现下标一一对应的元素组合)。

四、总结

for-each循环不仅适用于遍历集合和数组,而且能让你遍历任何实现Iterator接口的对象;最最关键的是它还没有性能损失。而对数组或集合进行修改(添加删除操作),就要用for循环。

所以循环遍历所有数据的时候,能用它的时候还是选择它吧,嘻嘻。

おすすめ

転載: www.cnblogs.com/mmzs/p/12040757.html