2017-07-18 31 views
4

Collections.singleton()で作業しているうちに、exptecedとして機能していないことがわかりました。あなたが表示された場合、すべての 要素がCollections.singleton()とforEachRemaining - Java 8

を処理されるまで forEachRemainingコードは任意の exceptionを投げなかったり false forEachRemaining

のJavaのドキュメントから

itr.hasNext()上に戻ってもされていない後に以下のコードは、残りの各要素に対して特定のアクションを実行します

以下のコードの出し入れは以下のとおりです。elemはと私は私がこの動作を理解する助けてくださいはNoSuchElementException

public class Test { 
     public static void main(String[] args) { 
     Collection<String> abc = Collections.singleton("elementsItr"); 
     final Iterator<String> itr = abc.iterator(); 
     try { 
      itr.forEachRemaining((e) -> { 
       throw new RuntimeException(); 
      }); 
     } catch (RuntimeException e) { 

     } 
     System.out.println(itr.hasNext()); 
     System.out.println(itr.next()); 

    } 
} 

を期待しています。

+1

'forEachRemaining'は'それが呼び出す正確にどのような順序で指定していないようですhasNext() '、' next() '、そしてあなたのメソッド。 [javadoc](http://docs.oracle.com/javase/8/docs/api/java/util/Iterator.html#forEachRemaining-java.util.function.Consumer-)はデフォルトの実装を提供しますが、それは可能ですオーバーライドされる。あなたは実際の 'Iterator'クラスが何であるか分からず、' forEachRemaining'をオーバーライドすることができ、シングルトンのための特別な実装を持つことは理にかなっています。基本的に、これはあなたが数えるべきではない行動です。 – ajb

+0

@ ajb--私はJavaのドキュメントをチェックしています。 デフォルトの実装は、次のように動作します。 while(hasNext()) アクション。accept(next()); –

+0

あなたのesxceptionブロックも空ですので、例外がスローされているかどうかをどのように知っていますか? –

答えて

4

コードを見る:Collections.singleton()SingletonSetを返します。SingletonSetiterator()を呼び出すと、結果のイテレータは匿名クラスになります。匿名クラスはforEachRemainingを上書きします:

public void forEachRemaining(Consumer<? super E> action) { 
    Objects.requireNonNull(action); 
    if (hasNext) { 
     action.accept(e); 
     hasNext = false; 
    } 
} 

あなたacceptが例外をスローしているので、hasNexttrueまま。

例外がスローされた場合、javadocはforEachRemainingに何が起こるべきかを指定しないことに注意してください。したがって、ランタイムの次のバージョンがをaction.accept(e)の上に置く可能性があり、異なる結果につながる可能性があります。だから、あなたはその行動を何とかすることはできません。

+0

@ ajb--恐ろしく、男....非常によく説明されています –

+0

いいです!素晴らしい発見。 +1 – christopher

+0

私はこれをバグとみなし、OpenJDKのメンテナに向かってチケットを発行します –

2

Collections.singleton(T)が呼び出されたときにシングルトンをインスタンス化するために使用されるクラスSingletonSet<E>によって使用されるイテレータは、この動作を説明しています。
イテレータは、static <E> Iterator<E> Collections.singletonIterator(E e)メソッドによって提供されます。

これはconsummerは例外なく戻ってきた場合にのみ、falseに渡すhasNextフラグがありますが、私たちは安全チェックとして、それをこの動作を検討することもでき

static <E> Iterator<E> singletonIterator(final E e) { 
    ... 
     @Override 
     public void forEachRemaining(Consumer<? super E> action) { 
      Objects.requireNonNull(action); 
      if (hasNext) { 
       action.accept(e); 
       hasNext = false; 
      } 
     } 
    ... 
} 

方法のドキュメントが明示的にしないとイテレータを前進させるだけで、正しく消費されました。
しかし、それはしかし、例外処理についてのヒントを提供します:アクションによってスロー

例外は、呼び出し側に中継されます。

例外がforEachRemaining()中に発生した場合に例外がforEachRemaining()によってキャッチはなく、発信者に転送されませんように、イテレータの状態に関する保証はありません。

+0

ありがとうございました.... –

+0

あなたは大歓迎です:) – davidxxx

1

よく見ると、シングルトンイテレータ(Collections#singletonIterator())が得られることがわかります。

それのコードは以下のようになります。

あり
static <E> Iterator<E> singletonIterator(final E e) { 
    return new Iterator<E>() { 
     private boolean hasNext = true; 
     public boolean hasNext() { 
      return hasNext; 
     } 
     public E next() { 
      if (hasNext) { 
       hasNext = false; 
       return e; 
      } 
      throw new NoSuchElementException(); 
     } 
     public void remove() { 
      throw new UnsupportedOperationException(); 
     } 
     @Override 
     public void forEachRemaining(Consumer<? super E> action) { 
      Objects.requireNonNull(action); 
      if (hasNext) { 
       action.accept(e); 
       hasNext = false; 
      } 
     } 
    }; 
} 

お持ちの次の行:

action.accept(e); 
hasNext = false; 

あなたはラムダ内部RuntimeExceptionを投げると(accept(e)を使用することによって呼び出される)、変数hasNextは、回線に達していないため、falseに決して設定されません。

+0

ありがとうございました.... :) –

2

これはOpenJDKでJDK-8166446と報告されていました。分析の状態:

これはどのように仕様に違反するかはわかりません。全て 要素が処理されたまたはアクションが例外をスローするまで http://docs.oracle.com/javase/8/docs/api/java/util/Iterator.html#forEachRemaining-java.util.function.Consumer-

「は」」残りの各要素のために指定されたアクションを実行します。その順序は 指定例外がスローされた場合 アクションは、反復の順序で実行されています "" "

accept()が例外をスローすると、イテレータを"インクリメント "する必要があるかどうかはわかりません。

他のいくつかのクラスは、シングルトンと同じ動作を示します。 ながら(!I =サイズ& & modCount == expectedModCount){ consumer.accept((Eを 公共ボイドforEachRemaining(消費者の消費者){ ........}: ArrayList.Iterator次のコードを有します)elementData [i ++]); } //ヒープ書き込みトラフィックを減らすためにイテレーションの最後に1回更新する カーソル= i; lastRet = i - 1; ........}

----------私はバグではないと思う。

しかし、異なる の実装のforEachRemaining()の動作を統一して、それらが一貫性を持たせるようにすることができます。 デフォルト実装。 JDK 9で

、これを固定し、最新のJDK 9-eaでテストすると、出力は以下の通りです:

Is empty: false 
Exception in thread "main" java.util.NoSuchElementException 
     at java.base/java.util.Collections$1.next(Collections.java:4698) 
     at Test.main(Test.java:18) 
+0

@Pallavi --- JDKに関するこのような深い情報を...あなたはいつもJDKのバグや修正に関する情報をたくさん持っています...あなたはJDKチームの方ですか..... :) –

+0

Wooooowww .. ..私たちが取り組んでいる技術を動かす人に直接話すことは素晴らしいと思います....ありがとうPallavi .. :) Stack Overflowにもこのブリッジを作成した人に感謝します。 –