Add Iterable#forEach & Map#forEach from openJdk8

Based on openJdk 8u40 source & iam@ stream change in
ag/872080

Bug: 27404545
Change-Id: Ic67e20b35c24e7acce513e010b727510af09a83e
diff --git a/harmony-tests/src/test/java/org/apache/harmony/tests/java/util/ArrayListTest.java b/harmony-tests/src/test/java/org/apache/harmony/tests/java/util/ArrayListTest.java
index d33f5f2..90feb5f 100644
--- a/harmony-tests/src/test/java/org/apache/harmony/tests/java/util/ArrayListTest.java
+++ b/harmony-tests/src/test/java/org/apache/harmony/tests/java/util/ArrayListTest.java
@@ -1047,6 +1047,60 @@
         assertEquals("string2", it.next());
     }
 
+    public void test_forEach() throws Exception {
+        ArrayList<Integer> list = new ArrayList<>();
+        list.add(0);
+        list.add(1);
+        list.add(2);
+
+        ArrayList<Integer> output = new ArrayList<>();
+        list.forEach(k -> output.add(k));
+
+        assertEquals(list, output);
+    }
+
+    public void test_forEach_NPE() throws Exception {
+        ArrayList<Integer> list = new ArrayList<>();
+        try {
+            list.forEach(null);
+            fail();
+        } catch(NullPointerException expected) {}
+    }
+
+    public void test_forEach_CME() throws Exception {
+        ArrayList<Integer> list = new ArrayList<>();
+        list.add(1);
+        list.add(2);
+        ArrayList<Integer> processed = new ArrayList<>();
+        try {
+            list.forEach(new java.util.function.Consumer<Integer>() {
+                    @Override
+                    public void accept(Integer t) {
+                        processed.add(t);
+                        list.add(t);}
+                });
+            fail();
+        } catch(ConcurrentModificationException expected) {}
+        assertEquals(1, processed.size());
+    }
+
+    public void test_forEach_CME_onLastElement() throws Exception {
+        ArrayList<Integer> list = new ArrayList<>();
+        list.add(1);
+        list.add(2);
+        list.add(3);
+        try {
+            list.forEach(new java.util.function.Consumer<Integer>() {
+                        @Override
+                        public void accept(Integer t) {
+                            if (t == 3) {
+                                list.add(t);
+                            }
+                        }
+                });
+            fail();
+        } catch(ConcurrentModificationException expected) {}
+    }
 
     /**
      * Sets up the fixture, for example, open a network connection. This method
diff --git a/harmony-tests/src/test/java/org/apache/harmony/tests/java/util/Arrays2Test.java b/harmony-tests/src/test/java/org/apache/harmony/tests/java/util/Arrays2Test.java
index d6adbb5..a61e343 100644
--- a/harmony-tests/src/test/java/org/apache/harmony/tests/java/util/Arrays2Test.java
+++ b/harmony-tests/src/test/java/org/apache/harmony/tests/java/util/Arrays2Test.java
@@ -5,9 +5,9 @@
  * The ASF licenses this file to You under the Apache License, Version 2.0
  * (the "License"); you may not use this file except in compliance with
  * the License.  You may obtain a copy of the License at
- * 
+ *
  * http://www.apache.org/licenses/LICENSE-2.0
- * 
+ *
  * Unless required by applicable law or agreed to in writing, software
  * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
  * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
@@ -19,7 +19,9 @@
 
 import java.io.Serializable;
 import java.util.Arrays;
+import java.util.ArrayList;
 import java.util.Comparator;
+import java.util.ConcurrentModificationException;
 import java.util.List;
 import java.util.RandomAccess;
 
@@ -469,4 +471,19 @@
         } catch (NullPointerException e) {
         }
     }
+
+    public void test_forEach() throws Exception {
+        List<Integer> list = Arrays.asList(0, 1, 2);
+        ArrayList<Integer> output = new ArrayList<>();
+        list.forEach(k -> output.add(k));
+        assertEquals(list, output);
+    }
+
+    public void test_forEach_NPE() throws Exception {
+        List<Integer> list = Arrays.asList(0, 1, 2);
+        try {
+            list.forEach(null);
+            fail();
+        } catch(NullPointerException expected) {}
+    }
 }
diff --git a/harmony-tests/src/test/java/org/apache/harmony/tests/java/util/Collections2Test.java b/harmony-tests/src/test/java/org/apache/harmony/tests/java/util/Collections2Test.java
index 899cd18..e5cce1c 100644
--- a/harmony-tests/src/test/java/org/apache/harmony/tests/java/util/Collections2Test.java
+++ b/harmony-tests/src/test/java/org/apache/harmony/tests/java/util/Collections2Test.java
@@ -5,9 +5,9 @@
  * The ASF licenses this file to You under the Apache License, Version 2.0
  * (the "License"); you may not use this file except in compliance with
  * the License.  You may obtain a copy of the License at
- * 
+ *
  * http://www.apache.org/licenses/LICENSE-2.0
- * 
+ *
  * Unless required by applicable law or agreed to in writing, software
  * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
  * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
@@ -22,16 +22,19 @@
 import org.apache.harmony.testframework.serialization.SerializationTest.SerializableAssert;
 import tests.util.SerializationTester;
 import java.io.Serializable;
+import java.util.ArrayDeque;
 import java.util.ArrayList;
 import java.util.Arrays;
 import java.util.Collection;
 import java.util.Collections;
 import java.util.Comparator;
+import java.util.Deque;
 import java.util.HashMap;
 import java.util.HashSet;
 import java.util.LinkedList;
 import java.util.List;
 import java.util.Map;
+import java.util.Queue;
 import java.util.RandomAccess;
 import java.util.Set;
 import java.util.SortedMap;
@@ -492,4 +495,95 @@
         }
     }
 
+    void testCollectionForEach(Collection<Integer> collection) {
+        ArrayList<Integer> output = new ArrayList<Integer>();
+        collection.forEach(k -> output.add(k));
+
+        assertEquals(new ArrayList<>(collection), output);
+    }
+
+    public void test_Collection_forEach() {
+        ArrayList<Integer> list = new ArrayList<Integer>();
+        list.add(0);
+        list.add(1);
+        list.add(2);
+        testCollectionForEach(Collections.unmodifiableCollection(list));
+        testCollectionForEach(Collections.synchronizedCollection(list));
+        testCollectionForEach(Collections.checkedCollection(list, Integer.class));
+        testCollectionForEach(Collections.singletonList(new Integer(0)));
+    }
+
+    void testMapForEach(Map<String,String> map) {
+        HashMap<String, String> output = new HashMap<String, String>();
+        map.forEach((k, v) -> output.put(k, v));
+        assertEquals(map, output);
+
+        output.clear();
+        map.entrySet().forEach(entry -> output.put(entry.getKey(), entry.getValue()));
+        assertEquals(map, output);
+
+        HashSet<String> setOutput = new HashSet<>();
+        map.values().forEach(value -> setOutput.add(value));
+        assertEquals(new HashSet<>(map.values()), setOutput);
+
+        setOutput.clear();
+        map.keySet().forEach((k) -> setOutput.add(k));
+        assertEquals(map.keySet(), setOutput);
+    }
+
+    public void test_Map_forEach() {
+        HashMap<String, String> map = new HashMap<String, String>();
+        map.put("one", "1");
+        map.put("two", "2");
+        map.put("three", "3");
+        testMapForEach(Collections.unmodifiableMap(map));
+        testMapForEach(Collections.synchronizedMap(map));
+        testMapForEach(Collections.checkedMap(map, String.class, String.class));
+        testMapForEach(Collections.singletonMap("one", "1"));
+    }
+
+    void testSetForEach(Set<Integer> set) {
+        HashSet<Integer> output = new HashSet<Integer>();
+        set.forEach(k -> output.add(k));
+
+        assertEquals(set.size(), output.size());
+        for (Integer key : set) {
+            assertTrue(output.contains(key));
+        }
+    }
+
+    public void test_Set_forEach() {
+        HashSet<Integer> set = new HashSet<Integer>();
+        set.add(1);
+        set.add(2);
+        set.add(3);
+        testSetForEach(Collections.unmodifiableSet(set));
+        testSetForEach(Collections.synchronizedSet(set));
+        testSetForEach(Collections.checkedSet(set, Integer.class));
+        testSetForEach(Collections.singleton(1));
+
+        Set<Integer> fromMap = Collections.newSetFromMap(new HashMap<Integer, Boolean>());
+        fromMap.add(1);
+        fromMap.add(2);
+        fromMap.add(3);
+        testSetForEach(fromMap);
+    }
+
+
+    public void test_Queue_forEach() {
+        Deque<Integer> deque = new ArrayDeque<Integer>();
+        deque.addFirst(2);
+        deque.addFirst(1);
+        deque.addFirst(0);
+
+        Queue<Integer> queue = Collections.asLifoQueue(deque);
+        ArrayList<Integer> output = new ArrayList<Integer>();
+        queue.forEach(v -> output.add(v));
+
+        assertEquals(3, output.size());
+        assertEquals(0, (int)output.get(0));
+        assertEquals(1, (int)output.get(1));
+        assertEquals(2, (int)output.get(2));
+    }
+
 }
diff --git a/harmony-tests/src/test/java/org/apache/harmony/tests/java/util/HashMapTest.java b/harmony-tests/src/test/java/org/apache/harmony/tests/java/util/HashMapTest.java
index 26d0a8e..eb2bb47 100644
--- a/harmony-tests/src/test/java/org/apache/harmony/tests/java/util/HashMapTest.java
+++ b/harmony-tests/src/test/java/org/apache/harmony/tests/java/util/HashMapTest.java
@@ -27,7 +27,9 @@
 import java.util.Arrays;
 import java.util.Collection;
 import java.util.Collections;
+import java.util.ConcurrentModificationException;
 import java.util.HashMap;
+import java.util.HashSet;
 import java.util.Iterator;
 import java.util.Map;
 import java.util.Random;
@@ -689,6 +691,115 @@
         assertFalse(entrySet.contains(copyEntry));
     }
 
+    public void test_forEach() throws Exception {
+        HashMap<String, String> map = new HashMap<>();
+        map.put("one", "1");
+        map.put("two", "2");
+        map.put("three", "3");
+
+        HashMap<String, String> output = new HashMap<>();
+        map.forEach((k, v) -> output.put(k,v));
+        assertEquals(map, output);
+
+        HashSet<String> setOutput = new HashSet<>();
+        map.keySet().forEach((k) -> setOutput.add(k));
+        assertEquals(map.keySet(), setOutput);
+
+        setOutput.clear();
+        map.values().forEach((v) -> setOutput.add(v));
+        assertEquals(new HashSet<>(map.values()), setOutput);
+
+        HashSet<Map.Entry<String,String>> entrySetOutput = new HashSet<>();
+        map.entrySet().forEach((v) -> entrySetOutput.add(v));
+        assertEquals(map.entrySet(), entrySetOutput);
+    }
+
+    public void test_forEach_NPE() throws Exception {
+        HashMap<String, String> map = new HashMap<>();
+        try {
+            map.forEach(null);
+            fail();
+        } catch(NullPointerException expected) {}
+
+        try {
+            map.keySet().forEach(null);
+            fail();
+        } catch(NullPointerException expected) {}
+
+        try {
+            map.values().forEach(null);
+            fail();
+        } catch(NullPointerException expected) {}
+
+        try {
+            map.entrySet().forEach(null);
+            fail();
+        } catch(NullPointerException expected) {}
+    }
+
+    public void test_forEach_CME() throws Exception {
+        HashMap<String, String> map = new HashMap<>();
+        map.put("one", "1");
+        map.put("two", "2");
+        map.put("three", "3");
+
+        HashMap<String, String> outputMap = new HashMap<>();
+        try {
+            map.forEach(new java.util.function.BiConsumer<String, String>() {
+                    @Override
+                    public void accept(String k, String v) {
+                        outputMap.put(k, v);
+                        map.put("foo1", v);
+                    }
+                });
+            fail();
+        } catch(ConcurrentModificationException expected) {}
+        // We should get a CME and DO NOT continue forEach evaluation
+        assertEquals(1, outputMap.size());
+
+        outputMap.clear();
+        try {
+            map.keySet().forEach(new java.util.function.Consumer<String>() {
+                    @Override
+                    public void accept(String k) {
+                        outputMap.put(k, "foo");
+                        map.put("foo2", "boo");
+                    }
+                });
+            fail();
+        } catch(ConcurrentModificationException expected) {}
+        // We should get a CME and DO NOT continue forEach evaluation
+        assertEquals(1, outputMap.size());
+
+        outputMap.clear();
+        try {
+            map.values().forEach(new java.util.function.Consumer<String>() {
+                    @Override
+                    public void accept(String k)  {
+                        outputMap.put(k, "foo");
+                        map.put("foo3", "boo");
+                    }
+                });
+            fail();
+        } catch(ConcurrentModificationException expected) {}
+        // We should get a CME and DO NOT continue forEach evaluation
+        assertEquals(1, outputMap.size());
+
+        outputMap.clear();
+        try {
+            map.entrySet().forEach(new java.util.function.Consumer<Map.Entry<String,String>>() {
+                    @Override
+                    public void accept(Map.Entry<String,String> k)  {
+                        outputMap.put(k.getKey(), "foo");
+                        map.put("foo4", "boo");
+                    }
+                });
+            fail();
+        } catch(ConcurrentModificationException expected) {}
+        // We should get a CME and DO NOT continue forEach evaluation
+        assertEquals(1, outputMap.size());
+    }
+
     private static class MockEntry implements Map.Entry {
 
         public Object getKey() {
diff --git a/harmony-tests/src/test/java/org/apache/harmony/tests/java/util/HashSetTest.java b/harmony-tests/src/test/java/org/apache/harmony/tests/java/util/HashSetTest.java
index 4ff4b9d..7add356 100644
--- a/harmony-tests/src/test/java/org/apache/harmony/tests/java/util/HashSetTest.java
+++ b/harmony-tests/src/test/java/org/apache/harmony/tests/java/util/HashSetTest.java
@@ -18,6 +18,7 @@
 package org.apache.harmony.tests.java.util;
 
 import java.util.Arrays;
+import java.util.ConcurrentModificationException;
 import java.util.HashSet;
 import java.util.Iterator;
 import java.util.Set;
@@ -222,6 +223,39 @@
         cloned.add(new Integer(8));
     }
 
+    public void test_forEach() throws Exception {
+      HashSet<Integer> hs = new HashSet<>();
+      hs.add(0);
+      hs.add(1);
+      hs.add(2);
+
+      HashSet<Integer> output = new HashSet<>();
+      hs.forEach(k -> output.add(k));
+
+      assertEquals(hs, output);
+    }
+
+    public void test_forEach_NPE() throws Exception {
+        HashSet<String> set = new HashSet<>();
+        try {
+            set.forEach(null);
+            fail();
+        } catch(NullPointerException expected) {}
+    }
+
+    public void test_forEach_CME() throws Exception {
+        HashSet<String> set = new HashSet<>();
+        set.add("one");
+        set.add("two");
+        try {
+            set.forEach(new java.util.function.Consumer<String>() {
+                    @Override
+                    public void accept(String k) {set.add("foo");}
+                });
+            fail();
+        } catch(ConcurrentModificationException expected) {}
+    }
+
     /**
      * Sets up the fixture, for example, open a network connection. This method
      * is called before a test is executed.
diff --git a/harmony-tests/src/test/java/org/apache/harmony/tests/java/util/HashtableTest.java b/harmony-tests/src/test/java/org/apache/harmony/tests/java/util/HashtableTest.java
index 2c81f65..165ff23 100644
--- a/harmony-tests/src/test/java/org/apache/harmony/tests/java/util/HashtableTest.java
+++ b/harmony-tests/src/test/java/org/apache/harmony/tests/java/util/HashtableTest.java
@@ -895,6 +895,46 @@
         }
     }
 
+    public void test_forEach() throws Exception {
+        Hashtable<String, String> ht = new Hashtable<>();
+        ht.put("1", "one");
+        ht.put("2", "two");
+        ht.put("3", "three");
+        Hashtable<String, String> output = new Hashtable<>();
+
+        ht.forEach((k,v) -> output.put(k,v));
+        assertEquals(ht, output);
+    }
+
+    public void test_forEach_NPE() throws Exception {
+        Hashtable<String, String> ht = new Hashtable<>();
+        try {
+            ht.forEach(null);
+            fail();
+        } catch(NullPointerException expected) {}
+    }
+
+    public void test_forEach_CME() throws Exception {
+        Hashtable<String, String> ht = new Hashtable<>();
+        ht.put("one", "1");
+        ht.put("two", "2");
+        ht.put("three", "3");
+
+        Hashtable<String, String> outputHt = new Hashtable<>();
+        try {
+            ht.forEach(new java.util.function.BiConsumer<String, String>() {
+                    @Override
+                    public void accept(String k, String v) {
+                        outputHt.put(k, v);
+                        ht.put("foo", v);
+                    }
+                });
+            fail();
+        } catch(ConcurrentModificationException expected) {}
+        // We should get a CME and DO NOT continue forEach evaluation
+        assertEquals(1, outputHt.size());
+    }
+
     protected Hashtable hashtableClone(Hashtable s) {
         return (Hashtable) s.clone();
     }
diff --git a/harmony-tests/src/test/java/org/apache/harmony/tests/java/util/IdentityHashMapTest.java b/harmony-tests/src/test/java/org/apache/harmony/tests/java/util/IdentityHashMapTest.java
index 4ddaf65..bb85ec6 100644
--- a/harmony-tests/src/test/java/org/apache/harmony/tests/java/util/IdentityHashMapTest.java
+++ b/harmony-tests/src/test/java/org/apache/harmony/tests/java/util/IdentityHashMapTest.java
@@ -25,6 +25,7 @@
 import java.util.ArrayList;
 import java.util.Arrays;
 import java.util.Collection;
+import java.util.ConcurrentModificationException;
 import java.util.HashMap;
 import java.util.HashSet;
 import java.util.IdentityHashMap;
@@ -857,6 +858,116 @@
         assertSame(newValue, ihm.get(key));
     }
 
+    public void test_forEach() throws Exception {
+        IdentityHashMap<String, String> map = new IdentityHashMap<>();
+        map.put("one", "1");
+        map.put("two", "2");
+        map.put("three", "3");
+
+        IdentityHashMap<String, String> output = new IdentityHashMap<>();
+        map.forEach((k, v) -> output.put(k,v));
+        assertEquals(map, output);
+
+        HashSet<String> setOutput = new HashSet<>();
+        map.keySet().forEach((k) -> setOutput.add(k));
+        assertEquals(map.keySet(), setOutput);
+
+        setOutput.clear();
+        map.values().forEach((v) -> setOutput.add(v));
+        assertEquals(new HashSet<>(map.values()), setOutput);
+
+        HashSet<Map.Entry<String,String>> entrySetOutput = new HashSet<>();
+        map.entrySet().forEach((v) -> entrySetOutput.add(v));
+        assertEquals(map.entrySet(), entrySetOutput);
+    }
+
+
+    public void test_forEach_NPE() throws Exception {
+        IdentityHashMap<String, String> map = new IdentityHashMap<>();
+        try {
+            map.forEach(null);
+            fail();
+        } catch(NullPointerException expected) {}
+
+        try {
+            map.keySet().forEach(null);
+            fail();
+        } catch(NullPointerException expected) {}
+
+        try {
+            map.values().forEach(null);
+            fail();
+        } catch(NullPointerException expected) {}
+
+        try {
+            map.entrySet().forEach(null);
+            fail();
+        } catch(NullPointerException expected) {}
+    }
+
+    public void test_forEach_CME() throws Exception {
+        IdentityHashMap<String, String> map = new IdentityHashMap<>();
+        map.put("one", "1");
+        map.put("two", "2");
+        map.put("three", "3");
+
+        IdentityHashMap<String, String> outputMap = new IdentityHashMap<>();
+        try {
+            map.forEach(new java.util.function.BiConsumer<String, String>() {
+                    @Override
+                    public void accept(String k, String v) {
+                        outputMap.put(k, v);
+                        map.put("foo1", v);
+                    }
+                });
+            fail();
+        } catch(ConcurrentModificationException expected) {}
+        // We should get a CME and DO NOT continue forEach evaluation
+        assertEquals(1, outputMap.size());
+
+        outputMap.clear();
+        try {
+            map.keySet().forEach(new java.util.function.Consumer<String>() {
+                    @Override
+                    public void accept(String k) {
+                        outputMap.put(k, "foo");
+                        map.put("foo2", "boo");
+                    }
+                });
+            fail();
+        } catch(ConcurrentModificationException expected) {}
+        // We should get a CME and DO NOT continue forEach evaluation
+        assertEquals(1, outputMap.size());
+
+        outputMap.clear();
+        try {
+            map.values().forEach(new java.util.function.Consumer<String>() {
+                    @Override
+                    public void accept(String k)  {
+                        outputMap.put(k, "foo");
+                        map.put("foo3", "boo");
+                    }
+                });
+            fail();
+        } catch(ConcurrentModificationException expected) {}
+        // We should get a CME and DO NOT continue forEach evaluation
+        assertEquals(1, outputMap.size());
+
+        outputMap.clear();
+        try {
+            map.entrySet().forEach(new java.util.function.Consumer<Map.Entry<String,String>>() {
+                    @Override
+                    public void accept(Map.Entry<String,String> k)  {
+                        outputMap.put(k.getKey(), "foo");
+                        map.put("foo4", "boo");
+                    }
+                });
+            fail();
+        } catch(ConcurrentModificationException expected) {}
+        // We should get a CME and DO NOT continue forEach evaluation
+        assertEquals(1, outputMap.size());
+    }
+
     // comparator for IdentityHashMap objects
     private static final SerializableAssert COMPARATOR = new SerializableAssert() {
         public void assertDeserialized(Serializable initial,
diff --git a/harmony-tests/src/test/java/org/apache/harmony/tests/java/util/LinkedHashMapTest.java b/harmony-tests/src/test/java/org/apache/harmony/tests/java/util/LinkedHashMapTest.java
index 44d2183..05873f6 100644
--- a/harmony-tests/src/test/java/org/apache/harmony/tests/java/util/LinkedHashMapTest.java
+++ b/harmony-tests/src/test/java/org/apache/harmony/tests/java/util/LinkedHashMapTest.java
@@ -21,8 +21,10 @@
 import java.util.ArrayList;
 import java.util.Arrays;
 import java.util.Collection;
+import java.util.ConcurrentModificationException;
 import java.util.Iterator;
 import java.util.LinkedHashMap;
+import java.util.LinkedHashSet;
 import java.util.Map;
 import java.util.Set;
 import java.util.TreeMap;
@@ -705,6 +707,116 @@
         assertTrue("Entries left in map", !it1.hasNext());
     }
 
+    public void test_forEach() throws Exception {
+        LinkedHashMap<String, String> map = new LinkedHashMap<>();
+        map.put("three", "3");
+        map.put("two", "2");
+        map.put("one", "1");
+
+        LinkedHashMap<String, String> output = new LinkedHashMap<>();
+        map.forEach((k, v) -> output.put(k,v));
+        assertEquals(map, output);
+
+        LinkedHashSet<String> setOutput = new LinkedHashSet<>();
+        map.keySet().forEach((k) -> setOutput.add(k));
+        assertEquals(map.keySet(), setOutput);
+
+        setOutput.clear();
+        map.values().forEach((v) -> setOutput.add(v));
+        assertEquals(new LinkedHashSet<>(map.values()), setOutput);
+
+        LinkedHashSet<Map.Entry<String,String>> entrySetOutput = new LinkedHashSet<>();
+        map.entrySet().forEach((v) -> entrySetOutput.add(v));
+        assertEquals(map.entrySet(), entrySetOutput);
+    }
+
+
+    public void test_forEach_NPE() throws Exception {
+        LinkedHashMap<String, String> map = new LinkedHashMap<>();
+        try {
+            map.forEach(null);
+            fail();
+        } catch(NullPointerException expected) {}
+
+        try {
+            map.keySet().forEach(null);
+            fail();
+        } catch(NullPointerException expected) {}
+
+        try {
+            map.values().forEach(null);
+            fail();
+        } catch(NullPointerException expected) {}
+
+        try {
+            map.entrySet().forEach(null);
+            fail();
+        } catch(NullPointerException expected) {}
+    }
+
+    public void test_forEach_CME() throws Exception {
+        LinkedHashMap<String, String> map = new LinkedHashMap<>();
+        map.put("one", "1");
+        map.put("two", "2");
+        map.put("three", "3");
+
+        LinkedHashMap<String, String> outputMap = new LinkedHashMap<>();
+        try {
+            map.forEach(new java.util.function.BiConsumer<String, String>() {
+                    @Override
+                    public void accept(String k, String v) {
+                        outputMap.put(k, v);
+                        map.put("foo1", v);
+                    }
+                });
+            fail();
+        } catch(ConcurrentModificationException expected) {}
+        // We should get a CME and DO NOT continue forEach evaluation
+        assertEquals(1, outputMap.size());
+
+        outputMap.clear();
+        try {
+            map.keySet().forEach(new java.util.function.Consumer<String>() {
+                    @Override
+                    public void accept(String k) {
+                        outputMap.put(k, "foo");
+                        map.put("foo2", "boo");
+                    }
+                });
+            fail();
+        } catch(ConcurrentModificationException expected) {}
+        // We should get a CME and DO NOT continue forEach evaluation
+        assertEquals(1, outputMap.size());
+
+        outputMap.clear();
+        try {
+            map.values().forEach(new java.util.function.Consumer<String>() {
+                    @Override
+                    public void accept(String k)  {
+                        outputMap.put(k, "foo");
+                        map.put("foo3", "boo");
+                    }
+                });
+            fail();
+        } catch(ConcurrentModificationException expected) {}
+        // We should get a CME and DO NOT continue forEach evaluation
+        assertEquals(1, outputMap.size());
+
+        outputMap.clear();
+        try {
+            map.entrySet().forEach(new java.util.function.Consumer<Map.Entry<String,String>>() {
+                    @Override
+                    public void accept(Map.Entry<String,String> k)  {
+                        outputMap.put(k.getKey(), "foo");
+                        map.put("foo4", "boo");
+                    }
+                });
+            fail();
+        } catch(ConcurrentModificationException expected) {}
+        // We should get a CME and DO NOT continue forEach evaluation
+        assertEquals(1, outputMap.size());
+    }
+
     /**
      * Sets up the fixture, for example, open a network connection. This method
      * is called before a test is executed.
diff --git a/harmony-tests/src/test/java/org/apache/harmony/tests/java/util/TreeMapTest.java b/harmony-tests/src/test/java/org/apache/harmony/tests/java/util/TreeMapTest.java
index 2f11d58..14506fb 100644
--- a/harmony-tests/src/test/java/org/apache/harmony/tests/java/util/TreeMapTest.java
+++ b/harmony-tests/src/test/java/org/apache/harmony/tests/java/util/TreeMapTest.java
@@ -25,8 +25,10 @@
 import java.text.Collator;
 import java.util.AbstractMap;
 import java.util.Collection;
+import java.util.ConcurrentModificationException;
 import java.util.Comparator;
 import java.util.HashMap;
+import java.util.HashSet;
 import java.util.Iterator;
 import java.util.LinkedList;
 import java.util.List;
@@ -1955,6 +1957,89 @@
         Iterator iter = subMap.values().iterator();
     }
 
+    public void test_forEach() throws Exception {
+        TreeMap<String, String> map = new TreeMap<>();
+        map.put("one", "1");
+        map.put("two", "2");
+        map.put("three", "3");
+
+        TreeMap<String, String> output = new TreeMap<>();
+        map.forEach((k, v) -> output.put(k,v));
+        assertEquals(map, output);
+
+        HashSet<String> setOutput = new HashSet<>();
+        map.keySet().forEach((k) -> setOutput.add(k));
+        assertEquals(map.keySet(), setOutput);
+
+        setOutput.clear();
+        map.values().forEach((v) -> setOutput.add(v));
+        assertEquals(new HashSet<>(map.values()), setOutput);
+
+        HashSet<Map.Entry<String,String>> entrySetOutput = new HashSet<>();
+        map.entrySet().forEach((v) -> entrySetOutput.add(v));
+        assertEquals(map.entrySet(), entrySetOutput);
+    }
+
+    public void test_forEach_NPE() throws Exception {
+        TreeMap<String, String> map = new TreeMap<>();
+        try {
+            map.forEach(null);
+            fail();
+        } catch(NullPointerException expected) {}
+
+        try {
+            map.keySet().forEach(null);
+            fail();
+        } catch(NullPointerException expected) {}
+
+        try {
+            map.values().forEach(null);
+            fail();
+        } catch(NullPointerException expected) {}
+
+        try {
+            map.entrySet().forEach(null);
+            fail();
+        } catch(NullPointerException expected) {}
+    }
+
+    public void test_forEach_CME() throws Exception {
+        TreeMap<String, String> map = new TreeMap<>();
+        map.put("one", "1");
+        map.put("two", "2");
+        try {
+            map.forEach(new java.util.function.BiConsumer<String, String>() {
+                    @Override
+                    public void accept(String k, String v) {map.put("foo", v);}
+                });
+            fail();
+        } catch(ConcurrentModificationException expected) {}
+
+        try {
+            map.keySet().forEach(new java.util.function.Consumer<String>() {
+                    @Override
+                    public void accept(String k) {map.put("foo2", "boo");}
+                });
+            fail();
+        } catch(ConcurrentModificationException expected) {}
+
+        try {
+            map.values().forEach(new java.util.function.Consumer<String>() {
+                    @Override
+                    public void accept(String k) {map.put("foo3", "boo");}
+                });
+            fail();
+        } catch(ConcurrentModificationException expected) {}
+
+        try {
+            map.entrySet().forEach(new java.util.function.Consumer<Map.Entry<String,String>>() {
+                    @Override
+                    public void accept(Map.Entry<String,String> k) {map.put("foo4", "boo");}
+                });
+            fail();
+        } catch(ConcurrentModificationException expected) {}
+    }
+
     /**
      * Sets up the fixture, for example, open a network connection. This method
      * is called before a test is executed.
diff --git a/harmony-tests/src/test/java/org/apache/harmony/tests/java/util/VectorTest.java b/harmony-tests/src/test/java/org/apache/harmony/tests/java/util/VectorTest.java
index e32ca94..1818033 100644
--- a/harmony-tests/src/test/java/org/apache/harmony/tests/java/util/VectorTest.java
+++ b/harmony-tests/src/test/java/org/apache/harmony/tests/java/util/VectorTest.java
@@ -20,6 +20,7 @@
 import tests.support.Support_ListTest;
 import java.util.Arrays;
 import java.util.Collection;
+import java.util.ConcurrentModificationException;
 import java.util.Enumeration;
 import java.util.HashSet;
 import java.util.LinkedList;
@@ -1383,6 +1384,41 @@
         }
     }
 
+    public void test_forEach() throws Exception {
+      Vector<Integer> vector = new Vector<Integer>();
+      vector.add(0);
+      vector.add(1);
+      vector.add(2);
+
+      Vector<Integer> output = new Vector<Integer>();
+      vector.forEach ( k -> output.add(k) );
+
+      assertEquals(vector, output);
+    }
+
+
+    public void test_forEach_NPE() throws Exception {
+        Vector<Integer> vector = new Vector<>();
+        try {
+            vector.forEach(null);
+            fail();
+        } catch(NullPointerException expected) {}
+    }
+
+    public void test_forEach_CME() throws Exception {
+        Vector<Integer> vector = new Vector<>();
+        vector.add(1);
+        vector.add(2);
+        try {
+            vector.forEach(new java.util.function.Consumer<Integer>() {
+                    @Override
+                    public void accept(Integer t) {vector.add(t);}
+                });
+            fail();
+        } catch(ConcurrentModificationException expected) {}
+    }
+
+
     /**
      * Sets up the fixture, for example, open a network connection. This method
      * is called before a test is executed.
diff --git a/harmony-tests/src/test/java/org/apache/harmony/tests/java/util/WeakHashMapTest.java b/harmony-tests/src/test/java/org/apache/harmony/tests/java/util/WeakHashMapTest.java
index 395f495..1732dd3 100644
--- a/harmony-tests/src/test/java/org/apache/harmony/tests/java/util/WeakHashMapTest.java
+++ b/harmony-tests/src/test/java/org/apache/harmony/tests/java/util/WeakHashMapTest.java
@@ -19,7 +19,10 @@
 
 import java.util.AbstractMap;
 import java.util.Arrays;
+import java.util.ArrayList;
 import java.util.Collection;
+import java.util.ConcurrentModificationException;
+import java.util.HashSet;
 import java.util.Iterator;
 import java.util.List;
 import java.util.Map;
@@ -395,6 +398,113 @@
         assertEquals("Incorrect number of keys returned after gc,", 99, valuesCollection.size());
     }
 
+    public void test_forEach() throws Exception {
+        WeakHashMap map = new WeakHashMap();
+        for (int i = 0; i < 100; i++)
+            map.put(keyArray[i], valueArray[i]);
+
+        WeakHashMap output = new WeakHashMap();
+        map.forEach((k, v) -> output.put(k,v));
+        assertEquals(map, output);
+
+        HashSet setOutput = new HashSet();
+        map.keySet().forEach((k) -> setOutput.add(k));
+        assertEquals(map.keySet(), setOutput);
+
+        setOutput.clear();
+        map.values().forEach((v) -> setOutput.add(v));
+        assertEquals(new HashSet(map.values()), setOutput);
+
+        HashSet entrySetOutput = new HashSet();
+        map.entrySet().forEach((v) -> entrySetOutput.add(v));
+        assertEquals(map.entrySet(), entrySetOutput);
+    }
+
+    public void test_forEach_NPE() throws Exception {
+        WeakHashMap map = new WeakHashMap();
+        try {
+            map.forEach(null);
+            fail();
+        } catch(NullPointerException expected) {}
+
+        try {
+            map.keySet().forEach(null);
+            fail();
+        } catch(NullPointerException expected) {}
+
+        try {
+            map.values().forEach(null);
+            fail();
+        } catch(NullPointerException expected) {}
+
+        try {
+            map.entrySet().forEach(null);
+            fail();
+        } catch(NullPointerException expected) {}
+
+    }
+
+    public void test_forEach_CME() throws Exception {
+        WeakHashMap map = new WeakHashMap();
+        for (int i = 0; i < 100; i++)
+            map.put(keyArray[i], valueArray[i]);
+        ArrayList<Object> processed = new ArrayList<>();
+        try {
+            map.forEach(new java.util.function.BiConsumer<Object, Object>() {
+                    @Override
+                    public void accept(Object k, Object v) {
+                        processed.add(k);
+                        map.put("foo", v);
+                    }
+                });
+            fail();
+        } catch(ConcurrentModificationException expected) {}
+        // We should get a CME and DO NOT continue forEach evaluation
+        assertEquals(1, processed.size());
+
+        processed.clear();
+        try {
+            map.keySet().forEach(new java.util.function.Consumer<Object>() {
+                    @Override
+                    public void accept(Object k) {
+                        processed.add(k);
+                        map.put("foo2", "boo");
+                    }
+                });
+            fail();
+        } catch(ConcurrentModificationException expected) {}
+        // We should get a CME and DO NOT continue forEach evaluation
+        assertEquals(1, processed.size());
+
+        processed.clear();
+        try {
+            map.values().forEach(new java.util.function.Consumer<Object>() {
+                    @Override
+                    public void accept(Object k) {
+                        processed.add(k);
+                        map.put("foo3", "boo");
+                    }
+                });
+            fail();
+        } catch(ConcurrentModificationException expected) {}
+        // We should get a CME and DO NOT continue forEach evaluation
+        assertEquals(1, processed.size());
+
+        processed.clear();
+        try {
+            map.entrySet().forEach(new java.util.function.Consumer<Map.Entry<Object, Object>>() {
+                    @Override
+                    public void accept(Map.Entry<Object, Object> k) {
+                        processed.add(k.getKey());
+                        map.put("foo4", "boo");
+                    }
+                });
+            fail();
+        } catch(ConcurrentModificationException expected) {}
+        // We should get a CME and DO NOT continue forEach evaluation
+        assertEquals(1, processed.size());
+    }
+
     /**
      * Sets up the fixture, for example, open a network connection. This method
      * is called before a test is executed.
diff --git a/known_oj_tags.txt b/known_oj_tags.txt
index c92ec3c..1ac051c 100644
--- a/known_oj_tags.txt
+++ b/known_oj_tags.txt
@@ -20,3 +20,4 @@
 @spec
 @revised
 @jls
+@implSpec
diff --git a/luni/src/test/java/org/apache/harmony/security/tests/java/security/ProviderTest.java b/luni/src/test/java/org/apache/harmony/security/tests/java/security/ProviderTest.java
index 625da8a..4462f81 100644
--- a/luni/src/test/java/org/apache/harmony/security/tests/java/security/ProviderTest.java
+++ b/luni/src/test/java/org/apache/harmony/security/tests/java/security/ProviderTest.java
@@ -34,6 +34,7 @@
 import java.security.SecurityPermission;
 import java.security.Provider.Service;
 import java.util.Collection;
+import java.util.ConcurrentModificationException;
 import java.util.HashMap;
 import java.util.Iterator;
 import java.util.Locale;
@@ -200,6 +201,38 @@
         }
     }
 
+    public final void testForEach() {
+        p.put("MessageDigest.SHA-1", "aaa.bbb.ccc.ddd");
+        p.put("MessageDigest.abc", "value 1");
+
+        HashMap<String, String> hm = new HashMap<>();
+        p.forEach((k,v)-> hm.put((String)k, (String)v));
+
+        assertEquals(p.size(), hm.size());
+        for(String key : hm.keySet()) {
+          assertEquals(p.get(key), hm.get(key));
+        }
+    }
+
+    public void testForEachNPE() throws Exception {
+        try {
+            p.forEach(null);
+            fail();
+        } catch(NullPointerException expected) {}
+    }
+
+    public void testForEachCME() throws Exception {
+        p.put("MessageDigest.SHA-1", "aaa.bbb.ccc.ddd");
+        p.put("MessageDigest.abc", "value 1");
+        try {
+            p.forEach(new java.util.function.BiConsumer<Object, Object>() {
+                    @Override
+                    public void accept(Object k, Object v) {p.put("foo", "bar");}
+                });
+            fail();
+        } catch(ConcurrentModificationException expected) {}
+    }
+
     /*
      * Class under test for Set keySet()
      */
diff --git a/ojluni/src/main/java/java/lang/Iterable.java b/ojluni/src/main/java/java/lang/Iterable.java
index 24efc86..05bd805 100755
--- a/ojluni/src/main/java/java/lang/Iterable.java
+++ b/ojluni/src/main/java/java/lang/Iterable.java
@@ -26,14 +26,20 @@
 package java.lang;
 
 import java.util.Iterator;
+import java.util.Objects;
+import java.util.function.Consumer;
 
 /**
  * Implementing this interface allows an object to be the target of
- * the "foreach" statement.
+ * the "for-each loop" statement. See
+ * <strong>
+ * <a href="{@docRoot}/../technotes/guides/language/foreach.html">For-each Loop</a>
+ * </strong>
  *
  * @param <T> the type of elements returned by the iterator
  *
  * @since 1.5
+ * @jls 14.14.2 The enhanced for statement
  */
 public interface Iterable<T> {
 
@@ -43,4 +49,30 @@
      * @return an Iterator.
      */
     Iterator<T> iterator();
+
+    /**
+     * Performs the given action for each element of the {@code Iterable}
+     * until all elements have been processed or the action throws an
+     * exception.  Unless otherwise specified by the implementing class,
+     * actions are performed in the order of iteration (if an iteration order
+     * is specified).  Exceptions thrown by the action are relayed to the
+     * caller.
+     *
+     * @implSpec
+     * <p>The default implementation behaves as if:
+     * <pre>{@code
+     *     for (T t : this)
+     *         action.accept(t);
+     * }</pre>
+     *
+     * @param action The action to be performed for each element
+     * @throws NullPointerException if the specified action is null
+     * @since 1.8
+     */
+    default void forEach(Consumer<? super T> action) {
+        Objects.requireNonNull(action);
+        for (T t : this) {
+            action.accept(t);
+        }
+    }
 }
diff --git a/ojluni/src/main/java/java/security/Provider.java b/ojluni/src/main/java/java/security/Provider.java
index 165f648..a1c8cfa 100755
--- a/ojluni/src/main/java/java/security/Provider.java
+++ b/ojluni/src/main/java/java/security/Provider.java
@@ -36,6 +36,7 @@
 import java.lang.reflect.*;
 import java.security.Security;
 import java.security.cert.CertStoreParameters;
+import java.util.function.BiConsumer;
 
 import javax.security.auth.login.Configuration;
 
@@ -379,6 +380,15 @@
         return super.get(key);
     }
 
+    /**
+     * @since 1.8
+     */
+    @Override
+    public synchronized void forEach(BiConsumer<? super Object, ? super Object> action) {
+        checkInitialized();
+        super.forEach(action);
+    }
+
     // let javadoc show doc from superclass
     public Enumeration<Object> keys() {
         checkInitialized();
diff --git a/ojluni/src/main/java/java/util/ArrayList.java b/ojluni/src/main/java/java/util/ArrayList.java
index 57be652..3a7469d 100755
--- a/ojluni/src/main/java/java/util/ArrayList.java
+++ b/ojluni/src/main/java/java/util/ArrayList.java
@@ -26,6 +26,8 @@
 
 package java.util;
 
+import java.util.function.Consumer;
+
 /**
  * Resizable-array implementation of the <tt>List</tt> interface.  Implements
  * all optional list operations, and permits all elements, including
@@ -1166,4 +1168,22 @@
             return "Index: "+index+", Size: "+this.size;
         }
     }
+
+    @Override
+    public void forEach(Consumer<? super E> action) {
+        Objects.requireNonNull(action);
+        final int expectedModCount = modCount;
+        @SuppressWarnings("unchecked")
+        final E[] elementData = (E[]) this.elementData;
+        final int size = this.size;
+        for (int i=0; modCount == expectedModCount && i < size; i++) {
+            action.accept(elementData[i]);
+        }
+        // Note
+        // Iterator will not throw a CME if we add something while iterating over the *last* element
+        // forEach will throw a CME in this case.
+        if (modCount != expectedModCount) {
+            throw new ConcurrentModificationException();
+        }
+    }
 }
diff --git a/ojluni/src/main/java/java/util/Arrays.java b/ojluni/src/main/java/java/util/Arrays.java
index d6ce587..e32dca1 100755
--- a/ojluni/src/main/java/java/util/Arrays.java
+++ b/ojluni/src/main/java/java/util/Arrays.java
@@ -27,6 +27,7 @@
 package java.util;
 
 import java.lang.reflect.*;
+import java.util.function.Consumer;
 
 /**
  * This class contains various methods for manipulating arrays (such as
@@ -2887,6 +2888,14 @@
         public boolean contains(Object o) {
             return indexOf(o) != -1;
         }
+
+        @Override
+        public void forEach(Consumer<? super E> action) {
+            Objects.requireNonNull(action);
+            for (E e : a) {
+                action.accept(e);
+            }
+        }
     }
 
     /**
diff --git a/ojluni/src/main/java/java/util/Collections.java b/ojluni/src/main/java/java/util/Collections.java
index ade8c2c..7194899 100755
--- a/ojluni/src/main/java/java/util/Collections.java
+++ b/ojluni/src/main/java/java/util/Collections.java
@@ -25,10 +25,14 @@
  */
 
 package java.util;
-import java.io.Serializable;
-import java.io.ObjectOutputStream;
+
 import java.io.IOException;
+import java.io.ObjectOutputStream;
+import java.io.Serializable;
 import java.lang.reflect.Array;
+import java.util.function.BiConsumer;
+import java.util.function.Consumer;
+
 
 /**
  * This class consists exclusively of static methods that operate on or return
@@ -1104,6 +1108,12 @@
         public void clear() {
             throw new UnsupportedOperationException();
         }
+
+        // Override default methods in Collection
+        @Override
+        public void forEach(Consumer<? super E> action) {
+            c.forEach(action);
+        }
     }
 
     /**
@@ -1388,6 +1398,12 @@
         public int hashCode()           {return m.hashCode();}
         public String toString()        {return m.toString();}
 
+        // Override default methods in Map
+        @Override
+        public void forEach(BiConsumer<? super K, ? super V> action) {
+            m.forEach(action);
+        }
+
         /**
          * We need this class in addition to UnmodifiableSet as
          * Map.Entries themselves permit modification of the backing Map
@@ -1403,6 +1419,17 @@
             UnmodifiableEntrySet(Set<? extends Map.Entry<? extends K, ? extends V>> s) {
                 super((Set)s);
             }
+
+            static <K, V> Consumer<Map.Entry<K, V>> entryConsumer(Consumer<? super Entry<K, V>> action) {
+                return e -> action.accept(new UnmodifiableEntry<>(e));
+            }
+
+            // Override default methods in Collection
+            public void forEach(Consumer<? super Entry<K, V>> action) {
+                Objects.requireNonNull(action);
+                c.forEach(entryConsumer(action));
+            }
+
             public Iterator<Map.Entry<K,V>> iterator() {
                 return new Iterator<Map.Entry<K,V>>() {
                     private final Iterator<? extends Map.Entry<? extends K, ? extends V>> i = c.iterator();
@@ -1668,6 +1695,13 @@
         public String toString() {
             synchronized (mutex) {return c.toString();}
         }
+
+        // Override default methods in Collection
+        @Override
+        public void forEach(Consumer<? super E> consumer) {
+            synchronized (mutex) {c.forEach(consumer);}
+        }
+
         private void writeObject(ObjectOutputStream s) throws IOException {
             synchronized (mutex) {s.defaultWriteObject();}
         }
@@ -2100,6 +2134,12 @@
         public String toString() {
             synchronized (mutex) {return m.toString();}
         }
+        // Override default methods in Map
+        @Override
+        public void forEach(BiConsumer<? super K, ? super V> action) {
+            synchronized (mutex) {m.forEach(action);}
+        }
+
         private void writeObject(ObjectOutputStream s) throws IOException {
             synchronized (mutex) {s.defaultWriteObject();}
         }
@@ -2368,6 +2408,10 @@
             // element as we added it)
             return c.addAll(checkedCopyOf(coll));
         }
+
+        // Override default methods in Collection
+        @Override
+        public void forEach(Consumer<? super E> action) {c.forEach(action);}
     }
 
     /**
@@ -2717,6 +2761,12 @@
             return entrySet;
         }
 
+        // Override default methods in Map
+        @Override
+        public void forEach(BiConsumer<? super K, ? super V> action) {
+            m.forEach(action);
+        }
+
         /**
          * We need this class in addition to CheckedSet as Map.Entry permits
          * modification of the backing Map via the setValue operation.  This
@@ -3160,6 +3210,12 @@
         private Object readResolve() {
             return EMPTY_SET;
         }
+
+        // Override default methods in Collection
+        @Override
+        public void forEach(Consumer<? super E> action) {
+            Objects.requireNonNull(action);
+        }
     }
 
     /**
@@ -3233,6 +3289,12 @@
         private Object readResolve() {
             return EMPTY_LIST;
         }
+
+        // Override default methods in Collection
+        @Override
+        public void forEach(Consumer<? super E> action) {
+            Objects.requireNonNull(action);
+        }
     }
 
     /**
@@ -3292,6 +3354,12 @@
         private Object readResolve() {
             return EMPTY_MAP;
         }
+
+        // Override default methods in Map
+        @Override
+        public void forEach(BiConsumer<? super K, ? super V> action) {
+            Objects.requireNonNull(action);
+        }
     }
 
     // Singleton collections
@@ -3346,6 +3414,12 @@
         public int size() {return 1;}
 
         public boolean contains(Object o) {return eq(o, element);}
+
+        // Override default methods for Collection
+        @Override
+        public void forEach(Consumer<? super E> action) {
+            action.accept(element);
+        }
     }
 
     /**
@@ -3386,6 +3460,12 @@
               throw new IndexOutOfBoundsException("Index: "+index+", Size: 1");
             return element;
         }
+
+        // Override default methods for Collection
+        @Override
+        public void forEach(Consumer<? super E> action) {
+            action.accept(element);
+        }
     }
 
     /**
@@ -3451,6 +3531,12 @@
             return values;
         }
 
+        // Override default methods in Map
+        @Override
+        public void forEach(BiConsumer<? super K, ? super V> action) {
+            action.accept(k, v);
+        }
+
     }
 
     // Miscellaneous
@@ -3925,6 +4011,12 @@
 
         private static final long serialVersionUID = 2454657854757543876L;
 
+        // Override default methods in Collection
+        @Override
+        public void forEach(Consumer<? super E> action) {
+            s.forEach(action);
+        }
+
         private void readObject(java.io.ObjectInputStream stream)
             throws IOException, ClassNotFoundException
         {
@@ -3981,5 +4073,9 @@
         public boolean removeAll(Collection<?> c)   {return q.removeAll(c);}
         public boolean retainAll(Collection<?> c)   {return q.retainAll(c);}
         // We use inherited addAll; forwarding addAll would be wrong
+
+        // Override default methods in Collection
+        @Override
+        public void forEach(Consumer<? super E> action) {q.forEach(action);}
     }
 }
diff --git a/ojluni/src/main/java/java/util/HashMap.java b/ojluni/src/main/java/java/util/HashMap.java
index 01b70a4..e4cad69 100755
--- a/ojluni/src/main/java/java/util/HashMap.java
+++ b/ojluni/src/main/java/java/util/HashMap.java
@@ -25,7 +25,10 @@
  */
 
 package java.util;
+
 import java.io.*;
+import java.util.function.Consumer;
+import java.util.function.BiConsumer;
 
 /**
  * Hash table based implementation of the <tt>Map</tt> interface.  This
@@ -1027,6 +1030,25 @@
         public void clear() {
             HashMap.this.clear();
         }
+        public final void forEach(Consumer<? super K> action) {
+            HashMapEntry<K,V>[] tab;
+            if (action == null)
+                throw new NullPointerException();
+            if (size > 0 && (tab = table) != null) {
+                int mc = modCount;
+                for (int i = 0; i < tab.length; ++i) {
+                    for (HashMapEntry<K,V> e = tab[i]; e != null; e = e.next) {
+                        action.accept(e.key);
+                        // Android-modified - this was outside of the loop, inconsistent with other
+                        // collections
+                        if (modCount != mc) {
+                            throw new ConcurrentModificationException();
+                        }
+                    }
+                }
+
+            }
+        }
     }
 
     /**
@@ -1060,6 +1082,24 @@
         public void clear() {
             HashMap.this.clear();
         }
+        public final void forEach(Consumer<? super V> action) {
+            HashMapEntry<K,V>[] tab;
+            if (action == null)
+                throw new NullPointerException();
+            if (size > 0 && (tab = table) != null) {
+                int mc = modCount;
+                for (int i = 0; i < tab.length; ++i) {
+                    for (HashMapEntry<K,V> e = tab[i]; e != null; e = e.next) {
+                        action.accept(e.value);
+                        // Android-modified - this was outside of the loop, inconsistent with other
+                        // collections
+                        if (modCount != mc) {
+                            throw new ConcurrentModificationException();
+                        }
+                    }
+                }
+            }
+        }
     }
 
     /**
@@ -1109,6 +1149,44 @@
         public void clear() {
             HashMap.this.clear();
         }
+        public final void forEach(Consumer<? super Map.Entry<K,V>> action) {
+            HashMapEntry<K,V>[] tab;
+            if (action == null)
+                throw new NullPointerException();
+            if (size > 0 && (tab = table) != null) {
+                int mc = modCount;
+                for (int i = 0; i < tab.length; ++i) {
+                    for (HashMapEntry<K,V> e = tab[i]; e != null; e = e.next) {
+                        action.accept(e);
+                        // Android-modified - this was outside of the loop, inconsistent with other
+                        // collections
+                        if (modCount != mc) {
+                            throw new ConcurrentModificationException();
+                        }
+                    }
+                }
+            }
+        }
+    }
+
+    @Override
+    public void forEach(BiConsumer<? super K, ? super V> action) {
+        HashMapEntry<K,V>[] tab;
+        if (action == null)
+            throw new NullPointerException();
+        if (size > 0 && (tab = table) != null) {
+            int mc = modCount;
+            for (int i = 0; i < tab.length; ++i) {
+                for (HashMapEntry<K,V> e = tab[i]; e != null; e = e.next) {
+                    action.accept(e.key, e.value);
+                    // Android-modified - this was outside of the loop, inconsistent with other
+                    // collections
+                    if (modCount != mc) {
+                        throw new ConcurrentModificationException();
+                    }
+                }
+            }
+        }
     }
 
     /**
diff --git a/ojluni/src/main/java/java/util/Hashtable.java b/ojluni/src/main/java/java/util/Hashtable.java
index a88bda1..57d9587 100755
--- a/ojluni/src/main/java/java/util/Hashtable.java
+++ b/ojluni/src/main/java/java/util/Hashtable.java
@@ -25,7 +25,9 @@
  */
 
 package java.util;
+
 import java.io.*;
+import java.util.function.BiConsumer;
 
 /**
  * This class implements a hash table, which maps keys to values. Any
@@ -921,6 +923,26 @@
         return h;
     }
 
+    @SuppressWarnings("unchecked")
+    @Override
+    public synchronized void forEach(BiConsumer<? super K, ? super V> action) {
+        Objects.requireNonNull(action);     // explicit check required in case
+                                            // table is empty.
+        final int expectedModCount = modCount;
+
+        HashtableEntry<?, ?>[] tab = table;
+        for (HashtableEntry<?, ?> entry : tab) {
+            while (entry != null) {
+                action.accept((K)entry.key, (V)entry.value);
+                entry = entry.next;
+
+                if (expectedModCount != modCount) {
+                    throw new ConcurrentModificationException();
+                }
+            }
+        }
+    }
+
     /**
      * Save the state of the Hashtable to a stream (i.e., serialize it).
      *
diff --git a/ojluni/src/main/java/java/util/IdentityHashMap.java b/ojluni/src/main/java/java/util/IdentityHashMap.java
index 95ff9f0..b0847ec 100755
--- a/ojluni/src/main/java/java/util/IdentityHashMap.java
+++ b/ojluni/src/main/java/java/util/IdentityHashMap.java
@@ -24,7 +24,10 @@
  */
 
 package java.util;
+
 import java.io.*;
+import java.util.function.BiConsumer;
+import java.util.function.Consumer;
 
 /**
  * This class implements the <tt>Map</tt> interface with a hash table, using
@@ -1240,4 +1243,24 @@
         tab[i] = k;
         tab[i + 1] = value;
     }
+
+    @SuppressWarnings("unchecked")
+    @Override
+    public void forEach(BiConsumer<? super K, ? super V> action) {
+        Objects.requireNonNull(action);
+        int expectedModCount = modCount;
+
+        Object[] t = table;
+        for (int index = 0; index < t.length; index += 2) {
+            Object k = t[index];
+            if (k != null) {
+                action.accept((K) unmaskNull(k), (V) t[index + 1]);
+            }
+
+            if (modCount != expectedModCount) {
+                throw new ConcurrentModificationException();
+            }
+        }
+    }
+
 }
diff --git a/ojluni/src/main/java/java/util/LinkedHashMap.java b/ojluni/src/main/java/java/util/LinkedHashMap.java
index 9a7eefe..c1b2644 100755
--- a/ojluni/src/main/java/java/util/LinkedHashMap.java
+++ b/ojluni/src/main/java/java/util/LinkedHashMap.java
@@ -25,7 +25,10 @@
  */
 
 package java.util;
+
 import java.io.*;
+import java.util.function.Consumer;
+import java.util.function.BiConsumer;
 
 /**
  * <p>Hash table and linked list implementation of the <tt>Map</tt> interface,
@@ -502,4 +505,16 @@
     protected boolean removeEldestEntry(Map.Entry<K,V> eldest) {
         return false;
     }
+
+    // Map overrides
+    public void forEach(BiConsumer<? super K, ? super V> action) {
+        if (action == null)
+            throw new NullPointerException();
+        int mc = modCount;
+        // Android modified - breaks from the loop when modCount != mc
+        for (LinkedHashMapEntry<K,V> e = header.after; modCount == mc && e != header; e = e.after)
+            action.accept(e.key, e.value);
+        if (modCount != mc)
+            throw new ConcurrentModificationException();
+    }
 }
diff --git a/ojluni/src/main/java/java/util/Map.java b/ojluni/src/main/java/java/util/Map.java
index ccdb288..afb24ba 100755
--- a/ojluni/src/main/java/java/util/Map.java
+++ b/ojluni/src/main/java/java/util/Map.java
@@ -25,6 +25,12 @@
 
 package java.util;
 
+
+import java.util.function.BiConsumer;
+import java.util.function.BiFunction;
+import java.util.function.Function;
+
+
 /**
  * An object that maps keys to values.  A map cannot contain duplicate keys;
  * each key can map to at most one value.
@@ -475,4 +481,44 @@
      */
     int hashCode();
 
+    /**
+     * Performs the given action for each entry in this map until all entries
+     * have been processed or the action throws an exception.   Unless
+     * otherwise specified by the implementing class, actions are performed in
+     * the order of entry set iteration (if an iteration order is specified.)
+     * Exceptions thrown by the action are relayed to the caller.
+     *
+     * @implSpec
+     * The default implementation is equivalent to, for this {@code map}:
+     * <pre> {@code
+     * for (Map.Entry<K, V> entry : map.entrySet())
+     *     action.accept(entry.getKey(), entry.getValue());
+     * }</pre>
+     *
+     * The default implementation makes no guarantees about synchronization
+     * or atomicity properties of this method. Any implementation providing
+     * atomicity guarantees must override this method and document its
+     * concurrency properties.
+     *
+     * @param action The action to be performed for each entry
+     * @throws NullPointerException if the specified action is null
+     * @throws ConcurrentModificationException if an entry is found to be
+     * removed during iteration
+     * @since 1.8
+     */
+    default void forEach(BiConsumer<? super K, ? super V> action) {
+        Objects.requireNonNull(action);
+        for (Map.Entry<K, V> entry : entrySet()) {
+            K k;
+            V v;
+            try {
+                k = entry.getKey();
+                v = entry.getValue();
+            } catch(IllegalStateException ise) {
+                // this usually means the entry is no longer in the map.
+                throw new ConcurrentModificationException(ise);
+            }
+            action.accept(k, v);
+        }
+    }
 }
diff --git a/ojluni/src/main/java/java/util/TreeMap.java b/ojluni/src/main/java/java/util/TreeMap.java
index f25e5af..d9235a9 100755
--- a/ojluni/src/main/java/java/util/TreeMap.java
+++ b/ojluni/src/main/java/java/util/TreeMap.java
@@ -26,6 +26,9 @@
 
 package java.util;
 
+import java.util.function.BiConsumer;
+import java.util.function.Consumer;
+
 /**
  * A Red-Black tree based {@link NavigableMap} implementation.
  * The map is sorted according to the {@linkplain Comparable natural
@@ -965,6 +968,19 @@
         return tailMap(fromKey, true);
     }
 
+    @Override
+    public void forEach(BiConsumer<? super K, ? super V> action) {
+        Objects.requireNonNull(action);
+        int expectedModCount = modCount;
+        for (TreeMapEntry<K, V> e = getFirstEntry(); e != null; e = successor(e)) {
+            action.accept(e.key, e.value);
+
+            if (expectedModCount != modCount) {
+                throw new ConcurrentModificationException();
+            }
+        }
+    }
+
     // View class support
 
     class Values extends AbstractCollection<V> {
diff --git a/ojluni/src/main/java/java/util/Vector.java b/ojluni/src/main/java/java/util/Vector.java
index 0d69591..f2c919f 100755
--- a/ojluni/src/main/java/java/util/Vector.java
+++ b/ojluni/src/main/java/java/util/Vector.java
@@ -25,6 +25,8 @@
 
 package java.util;
 
+import java.util.function.Consumer;
+
 /**
  * The {@code Vector} class implements a growable array of
  * objects. Like an array, it contains components that can be
@@ -1209,4 +1211,19 @@
             lastRet = -1;
         }
     }
+
+    @Override
+    public synchronized void forEach(Consumer<? super E> action) {
+        Objects.requireNonNull(action);
+        final int expectedModCount = modCount;
+        @SuppressWarnings("unchecked")
+        final E[] elementData = (E[]) this.elementData;
+        final int elementCount = this.elementCount;
+        for (int i=0; modCount == expectedModCount && i < elementCount; i++) {
+            action.accept(elementData[i]);
+        }
+        if (modCount != expectedModCount) {
+            throw new ConcurrentModificationException();
+        }
+    }
 }
diff --git a/ojluni/src/main/java/java/util/WeakHashMap.java b/ojluni/src/main/java/java/util/WeakHashMap.java
index 652b053..fa5dace 100755
--- a/ojluni/src/main/java/java/util/WeakHashMap.java
+++ b/ojluni/src/main/java/java/util/WeakHashMap.java
@@ -27,6 +27,8 @@
 package java.util;
 import java.lang.ref.WeakReference;
 import java.lang.ref.ReferenceQueue;
+import java.util.function.BiConsumer;
+import java.util.function.Consumer;
 
 
 /**
@@ -1077,4 +1079,26 @@
             return deepCopy().toArray(a);
         }
     }
+
+    @SuppressWarnings("unchecked")
+    @Override
+    public void forEach(BiConsumer<? super K, ? super V> action) {
+        Objects.requireNonNull(action);
+        int expectedModCount = modCount;
+
+        Entry<K, V>[] tab = getTable();
+        for (Entry<K, V> entry : tab) {
+            while (entry != null) {
+                Object key = entry.get();
+                if (key != null) {
+                    action.accept((K)WeakHashMap.unmaskNull(key), entry.value);
+                }
+                entry = entry.next;
+
+                if (expectedModCount != modCount) {
+                    throw new ConcurrentModificationException();
+                }
+            }
+        }
+    }
 }