8166446: SingletonIterator.forEachRemaining doesn't advance before calling action
authorsmarks
Tue, 06 Dec 2016 17:26:43 -0800
changeset 42435 349ac3a65124
parent 42434 7fc88840baa5
child 42436 83d5d07ae03a
8166446: SingletonIterator.forEachRemaining doesn't advance before calling action Reviewed-by: martin
jdk/src/java.base/share/classes/java/util/Collections.java
jdk/test/java/util/Collections/SingletonIterator.java
--- a/jdk/src/java.base/share/classes/java/util/Collections.java	Tue Dec 06 14:44:12 2016 -0800
+++ b/jdk/src/java.base/share/classes/java/util/Collections.java	Tue Dec 06 17:26:43 2016 -0800
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 1997, 2015, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1997, 2016, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -4699,8 +4699,8 @@
             public void forEachRemaining(Consumer<? super E> action) {
                 Objects.requireNonNull(action);
                 if (hasNext) {
+                    hasNext = false;
                     action.accept(e);
-                    hasNext = false;
                 }
             }
         };
--- a/jdk/test/java/util/Collections/SingletonIterator.java	Tue Dec 06 14:44:12 2016 -0800
+++ b/jdk/test/java/util/Collections/SingletonIterator.java	Tue Dec 06 17:26:43 2016 -0800
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -23,6 +23,7 @@
 
 /*
  * @test
+ * @bug 8024500 8166446
  * @run testng SingletonIterator
  */
 
@@ -38,6 +39,15 @@
 
 @Test(groups = "unit")
 public class SingletonIterator {
+    static void assertIteratorExhausted(Iterator<?> it) {
+        assertFalse(it.hasNext());
+        try {
+            it.next();
+            fail("should have thrown NoSuchElementException");
+        } catch (NoSuchElementException success) { }
+        it.forEachRemaining(e -> { throw new AssertionError("action called incorrectly"); });
+    }
+
     public void testForEachRemaining() {
         Iterator<String> it = Collections.singleton("TheOne").iterator();
         AtomicInteger cnt = new AtomicInteger(0);
@@ -48,13 +58,18 @@
         });
 
         assertEquals(cnt.get(), 1);
-        assertFalse(it.hasNext());
+        assertIteratorExhausted(it);
+    }
+
+    static class SingletonException extends RuntimeException { }
+
+    public void testThrowFromForEachRemaining() {
+        Iterator<String> it = Collections.singleton("TheOne").iterator();
 
         try {
-            String str = it.next();
-            fail("Should throw NoSuchElementException at end");
-        } catch (NoSuchElementException ex) {
-            // ignore;
-        }
+            it.forEachRemaining(s -> { throw new SingletonException(); });
+        } catch (SingletonException ignore) { }
+
+        assertIteratorExhausted(it);
     }
 }