changeset 5970:685ce67a171b it2-bootstrap

Merge
author mduigou
date Tue, 04 Sep 2012 15:29:13 -0700
parents eb56503977d6 6a1eb323c7df
children ff45d6cfdffc
files src/share/classes/java/util/Spliterator.java src/share/classes/java/util/Splittable.java
diffstat 25 files changed, 182 insertions(+), 190 deletions(-) [+]
line wrap: on
line diff
--- a/make/java/java/FILES_java.gmk	Tue Sep 04 14:14:34 2012 -0700
+++ b/make/java/java/FILES_java.gmk	Tue Sep 04 15:29:13 2012 -0700
@@ -281,7 +281,6 @@
     java/util/TimerTask.java \
     java/util/Objects.java \
     java/util/UUID.java \
-    java/util/Splittable.java \
     java/util/concurrent/AbstractExecutorService.java \
     java/util/concurrent/ArrayBlockingQueue.java \
     java/util/concurrent/BlockingDeque.java \
--- a/src/share/classes/java/util/Arrays.java	Tue Sep 04 14:14:34 2012 -0700
+++ b/src/share/classes/java/util/Arrays.java	Tue Sep 04 15:29:13 2012 -0700
@@ -26,7 +26,6 @@
 package java.util;
 
 import java.lang.reflect.*;
-import java.util.functions.*;
 import java.util.streams.*;
 
 /**
@@ -3737,14 +3736,16 @@
         }
 
         @Override
-        public void forEach(Block<? super T> block) {
+        public void into(Sink<T, ?, ?> sink) {
+            sink.begin(getRemainingSizeIfKnown());
             // Strange-looking way to iterate; reduce heap write traffic
             if (offset < endOffset) {
                 int wasOffset = offset;
                 offset = endOffset;
                 for (int i=wasOffset; i<endOffset; i++)
-                    block.apply(array[i]);
+                    sink.accept(array[i]);
             }
+            sink.end();
         }
 
         @Override
@@ -3754,6 +3755,11 @@
             offset += t;
             return ret;
         }
+
+        @Override
+        public Iterator<T> iterator() {
+            return this;
+        }
     }
 
     private static class ArrayStreamAccessor<T>
@@ -3763,14 +3769,16 @@
         }
 
         @Override
-        public void forEach(Block<? super T> block) {
+        public void into(Sink<T, ?, ?> sink) {
+            sink.begin(endOffset-offset);
             // Strange-looking way to iterate; reduce heap write traffic
             if (offset < endOffset) {
                 int wasOffset = offset;
                 offset = endOffset;
                 for (int i=wasOffset; i<endOffset; i++)
-                    block.apply(array[i]);
+                    sink.accept(array[i]);
             }
+            sink.end();
         }
 
         @Override
--- a/src/share/classes/java/util/Map.java	Tue Sep 04 14:14:34 2012 -0700
+++ b/src/share/classes/java/util/Map.java	Tue Sep 04 15:29:13 2012 -0700
@@ -26,11 +26,8 @@
 package java.util;
 
 import java.util.functions.BiBlock;
-import java.util.functions.Block;
-import java.util.functions.Predicate;
 import java.util.streams.MapStream;
-import java.util.streams.Stream;
-import java.util.streams.Streamable;
+import java.util.streams.MapStreamable;
 import java.util.streams.Streams;
 
 /**
@@ -122,7 +119,7 @@
  * @see Set
  * @since 1.2
  */
-public interface Map<K,V> extends Sized, Streamable<Mapping<K,V>>, MapTraversable<K,V>, MapStream.Destination<K,V> {
+public interface Map<K,V> extends Sized, MapStreamable<K,V>, MapTraversable<K,V>, MapStream.Destination<K,V> {
 
     // Query Operations
 
@@ -492,8 +489,14 @@
     }
 
     @Override
-    Stream<Mapping<K,V>> stream() default {
-        return Streams.stream(this, size());
+    void forEach(BiBlock<? super K, ? super V> block) default {
+        for (Map.Entry<K, V> entry : entrySet())
+            block.apply(entry.getKey(), entry.getValue());
+    }
+
+    @Override
+    MapStream<K,V> stream() default {
+        return Streams.stream(this);
     }
 
     @Override
--- a/src/share/classes/java/util/MapTraversable.java	Tue Sep 04 14:14:34 2012 -0700
+++ b/src/share/classes/java/util/MapTraversable.java	Tue Sep 04 15:29:13 2012 -0700
@@ -35,18 +35,13 @@
  *
  * @author Brian Goetz
  */
-public interface MapTraversable<K,V> extends Traversable<Mapping<K,V>> {
+public interface MapTraversable<K,V> {
     /**
      * Each element of the object will be provided to the specified Sink.
      *
      * @param block The Sink to which elements will be provided.
      */
-    void forEach(BiBlock<? super K, ? super V> block) default {
-        for (Mapping<K,V> m : this) {
-            block.apply(m.getKey(), m.getValue());
-        }
-    }
+    void forEach(BiBlock<? super K, ? super V> block);
 
-    @Override
     MapIterator<K,V> iterator();
 }
--- a/src/share/classes/java/util/Spliterator.java	Tue Sep 04 14:14:34 2012 -0700
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,66 +0,0 @@
-/*
- * Copyright (c) 2012, 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
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation.  Oracle designates this
- * particular file as subject to the "Classpath" exception as provided
- * by Oracle in the LICENSE file that accompanied this code.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- */
-package java.util;
-
-import java.util.functions.Block;
-
-/**
- * Spliterator
- *
- * @author Brian Goetz
- * @author Doug Lea
- */
-public interface Spliterator<T> extends Iterator<T> {
-    /**
-     * Returns a Spliterator covering approximately half of the
-     * elements, guaranteed not to overlap with those subsequently
-     * returned by this spliterator.  After invoking this method,
-     * the current Spliterator will <em>not</em> cover the
-     * elements of the returned Spliterator.
-     *
-     * @return a Spliterator covering the associated elements
-     * @throws IllegalStateException if this Spliterator has
-     * already commenced traversing elements.
-     */
-    Spliterator<T> split();
-
-    /** Process the remaining elements sequentially.  */
-    void forEach(Block<? super T> sink);
-
-    /**
-     * Return the number of elements remaining to be processed, if the count can
-     * be computed exactly and cheaply.  Otherwise, return -1.
-     *
-     * @return The number of remaining elements, or negative value if unknown
-     */
-    int getRemainingSizeIfKnown() default { return -1; }
-
-    /**
-     * Return {@code true} if this spliterator returns symmetric splits.
-     *
-     * @return {@code true} if this spliterator returns symmetric splits.
-     */
-    boolean isPredictableSplits() default { return false; }
-}
--- a/src/share/classes/java/util/Splittable.java	Tue Sep 04 14:14:34 2012 -0700
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,10 +0,0 @@
-package java.util;
-
-/**
- * A decomposable container for elements.
- *
- * @param <T> the type of elements returned by the sequential iterator
- */
-public interface Splittable<T> extends Iterable<T> {
-    Spliterator<T> spliterator();
-}
--- a/src/share/classes/java/util/streams/AbstractPipeline.java	Tue Sep 04 14:14:34 2012 -0700
+++ b/src/share/classes/java/util/streams/AbstractPipeline.java	Tue Sep 04 15:29:13 2012 -0700
@@ -148,18 +148,14 @@
         else {
             // Push traversal
             StatefulSink<U, V> terminalSink = terminal.sink();
-            Sink sink = wrapSink(ops, terminalSink);
-            sink.begin(-1); // @@@ supply size if known
-            source.forEach(sink);
-            sink.end();
+            source.into(wrapSink(ops, terminalSink));
             return terminalSink.getAndClearState();
         }
     }
 
     private static Sink wrapSink(IntermediateOp[] ops, Sink sink) {
         for (int i=ops.length-1; i >= 0; i--) {
-            IntermediateOp op = ops[i];
-            sink = op.sink(sink);
+            sink = ops[i].sink(sink);
         }
         return sink;
     }
@@ -202,7 +198,7 @@
 
     public Iterator<U> iterator() {
         if (iterator == null) {
-            iterator = (Iterator) ((op == null) ? source : op.iterator(upstream.iterator()));
+            iterator = (Iterator) ((op == null) ? source.iterator() : op.iterator(upstream.iterator()));
         }
         return iterator;
     }
--- a/src/share/classes/java/util/streams/AbstractSequentialMapStreamAccessor.java	Tue Sep 04 14:14:34 2012 -0700
+++ b/src/share/classes/java/util/streams/AbstractSequentialMapStreamAccessor.java	Tue Sep 04 15:29:13 2012 -0700
@@ -25,7 +25,6 @@
 package java.util.streams;
 
 import java.util.Mapping;
-import java.util.Spliterator;
 
 /**
  * AbstractSequentialMapStreamAccessor
--- a/src/share/classes/java/util/streams/AbstractSequentialStreamAccessor.java	Tue Sep 04 14:14:34 2012 -0700
+++ b/src/share/classes/java/util/streams/AbstractSequentialStreamAccessor.java	Tue Sep 04 15:29:13 2012 -0700
@@ -24,8 +24,6 @@
  */
 package java.util.streams;
 
-import java.util.Spliterator;
-
 /**
  * AbstractSequentialStreamAccessor
  *
--- a/src/share/classes/java/util/streams/MapStream.java	Tue Sep 04 14:14:34 2012 -0700
+++ b/src/share/classes/java/util/streams/MapStream.java	Tue Sep 04 15:29:13 2012 -0700
@@ -35,7 +35,7 @@
  *
  * @author Brian Goetz
  */
-public interface MapStream<K, V> extends MapTraversable<K, V> {
+public interface MapStream<K, V> {
     MapIterator<K, V> iterator();
 
     boolean isParallel();
--- a/src/share/classes/java/util/streams/MapStreamable.java	Tue Sep 04 14:14:34 2012 -0700
+++ b/src/share/classes/java/util/streams/MapStreamable.java	Tue Sep 04 15:29:13 2012 -0700
@@ -24,13 +24,10 @@
  */
 package java.util.streams;
 
-import java.util.Mapping;
-
 /**
  * MapStreamable
  *
- * @param <T> Type of stream elements.
- *
+ * @author Brian Goetz
  */
 public interface MapStreamable<K,V> {
     MapStream<K,V> stream();
--- a/src/share/classes/java/util/streams/Sink.java	Tue Sep 04 14:14:34 2012 -0700
+++ b/src/share/classes/java/util/streams/Sink.java	Tue Sep 04 15:29:13 2012 -0700
@@ -26,6 +26,7 @@
 
 import java.util.Mapping;
 import java.util.Objects;
+import java.util.functions.BiBlock;
 import java.util.functions.Block;
 
 /**
@@ -33,7 +34,7 @@
  *
  * @author Brian Goetz
  */
-public interface Sink<T, K, V> extends Block<T> {
+public interface Sink<T, K, V> extends Block<T>, BiBlock<K,V> {
     void accept(T t);
 
     void accept(K k, V v) default { throw new IllegalStateException(); }
@@ -60,6 +61,8 @@
     @Override
     void apply(T t) default { accept(t); }
 
+    @Override
+    void apply(K k, V v) default { accept(k, v); }
 
     public interface OfLinear<T> extends Sink<T, Object, Object> {
         @Override
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/share/classes/java/util/streams/Spliterator.java	Tue Sep 04 15:29:13 2012 -0700
@@ -0,0 +1,71 @@
+/*
+ * Copyright (c) 2012, 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
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package java.util.streams;
+
+import java.util.Iterator;
+
+/**
+ * Spliterator
+ *
+ * @author Brian Goetz
+ * @author Doug Lea
+ */
+public interface Spliterator<T> {
+    /**
+     * Returns a Spliterator covering approximately half of the
+     * elements, guaranteed not to overlap with those subsequently
+     * returned by this spliterator.  After invoking this method,
+     * the current Spliterator will <em>not</em> cover the
+     * elements of the returned Spliterator.
+     *
+     * @return a Spliterator covering the associated elements
+     * @throws IllegalStateException if this Spliterator has
+     * already commenced traversing elements.
+     */
+    Spliterator<T> split();
+
+    /**
+     * Return an Iterator covering the remaining elements
+     */
+    Iterator<T> iterator();
+
+    /** Send the remaining elements sequentially into the specified sink */
+    void into(Sink<T, ?, ?> sink);
+
+    /**
+     * Return the number of elements remaining to be processed, if the count can
+     * be computed exactly and cheaply.  Otherwise, return -1.
+     *
+     * @return The number of remaining elements, or negative value if unknown
+     */
+    int getRemainingSizeIfKnown() default { return -1; }
+
+    /**
+     * Return {@code true} if this spliterator returns symmetric splits.
+     *
+     * @return {@code true} if this spliterator returns symmetric splits.
+     */
+    boolean isPredictableSplits() default { return false; }
+}
--- a/src/share/classes/java/util/streams/Stream.java	Tue Sep 04 14:14:34 2012 -0700
+++ b/src/share/classes/java/util/streams/Stream.java	Tue Sep 04 15:29:13 2012 -0700
@@ -35,7 +35,7 @@
  *
  * @author Brian Goetz
  */
-public interface Stream<T> extends Traversable<T> {
+public interface Stream<T> {
     public enum Shape {
         LINEAR {
             @Override
@@ -131,7 +131,7 @@
 
 
     /**
-     * An aggregate that supports an {@code add(T)} operation.
+     * An aggregate that supports an {@code addAll(Stream)} operation.
      *
      * @param <T> Type of aggregate elements.
      */
--- a/src/share/classes/java/util/streams/StreamAccessor.java	Tue Sep 04 14:14:34 2012 -0700
+++ b/src/share/classes/java/util/streams/StreamAccessor.java	Tue Sep 04 15:29:13 2012 -0700
@@ -25,8 +25,6 @@
 package java.util.streams;
 
 import java.util.Iterator;
-import java.util.Spliterator;
-import java.util.functions.Block;
 
 /**
  * StreamAccessor
@@ -36,7 +34,7 @@
  * @author Brian Goetz
  */
 public interface StreamAccessor<T> {
-    void forEach(Block<? super T> sink);
+    void into(Sink<T, ?, ?> sink);
 
     Iterator<T> iterator();
 
--- a/src/share/classes/java/util/streams/Streams.java	Tue Sep 04 14:14:34 2012 -0700
+++ b/src/share/classes/java/util/streams/Streams.java	Tue Sep 04 15:29:13 2012 -0700
@@ -26,7 +26,6 @@
 
 import java.util.*;
 import java.util.functions.BiBlock;
-import java.util.functions.Block;
 
 /**
  * Streams
@@ -92,7 +91,15 @@
             }
 
             @Override
-            public void forEach(Block<? super T> block) { }
+            public Iterator<T> iterator() {
+                return Collections.emptyIterator();
+            }
+
+            @Override
+            public void into(Sink<T, ?, ?> sink) {
+                sink.begin(0);
+                sink.end();
+            }
 
             @Override
             public int getRemainingSizeIfKnown() {
@@ -103,16 +110,6 @@
             public boolean isPredictableSplits() {
                 return true;
             }
-
-            @Override
-            public boolean hasNext() {
-                return false;
-            }
-
-            @Override
-            public T next() {
-                throw new NoSuchElementException();
-            }
         };
     }
 
@@ -133,9 +130,11 @@
         }
 
         @Override
-        public void forEach(Block<? super T> block) {
+        public void into(Sink<T, ?, ?> sink) {
+            sink.begin(-1);
             while (it.hasNext())
-                block.apply(it.next());
+                sink.accept(it.next());
+            sink.end();
         }
 
         @Override
@@ -182,8 +181,8 @@
         }
 
         @Override
-        public void forEach(Block<? super T> block) {
-            spliterator.forEach(block);
+        public void into(Sink<T, ?, ?> sink) {
+            spliterator.into(sink);
         }
 
         @Override
@@ -201,7 +200,7 @@
 
         @Override
         public Iterator<T> iterator() {
-            return spliterator;
+            return spliterator.iterator();
         }
 
         @Override
@@ -248,15 +247,17 @@
         }
 
         @Override
-        public void forEach(Block<? super T> block) {
+        public void into(Sink<T, ?, ?> sink) {
+            sink.begin(-1);
             if (iterator == null) {
-                traversable.forEach(block);
+                traversable.forEach(sink);
                 iterator = Collections.emptyIterator();
             }
             else {
                 while (iterator.hasNext())
-                    block.apply(iterator.next());
+                    sink.accept(iterator.next());
             }
+            sink.end();
         }
 
         @Override
@@ -309,14 +310,17 @@
         }
 
         @Override
-        public void forEach(final Block<? super Mapping<K,V>> block) {
+        public void into(final Sink<Mapping<K,V>, ?, ?> sink) {
+            Sink<Mapping<K, V>, K, V> castSink = (Sink<Mapping<K, V>, K, V>) sink;
             if (iterator == null) {
-                traversable.forEach(block);
+                traversable.forEach(castSink);
                 iterator = new MapIterator.IteratorAdapter<>(Collections.<Mapping<K,V>>emptyIterator());
             }
             else {
                 while (iterator.hasNext()) {
-                    block.apply(iterator.next());
+                    K k = iterator.nextKey();
+                    V v = iterator.curValue();
+                    castSink.accept(k, v);
                 }
             }
         }
--- a/src/share/classes/java/util/streams/ops/CumulateOp.java	Tue Sep 04 14:14:34 2012 -0700
+++ b/src/share/classes/java/util/streams/ops/CumulateOp.java	Tue Sep 04 15:29:13 2012 -0700
@@ -26,7 +26,7 @@
 
 import java.util.Iterator;
 import java.util.Objects;
-import java.util.Spliterator;
+import java.util.streams.Spliterator;
 import java.util.concurrent.RecursiveTask;
 import java.util.functions.BinaryOperator;
 import java.util.streams.*;
@@ -180,10 +180,7 @@
                     else {
                         leafData = StreamBuilders.make();
                         StatefulSink<T, T> terminalSink = sink(leafData);
-                        Sink<V, ?, ?> sink = problem.helper.sink(terminalSink);
-                        sink.begin(-1);
-                        source.forEach(sink);
-                        sink.end();
+                        source.into(problem.helper.sink(terminalSink));
                         upward = terminalSink.getAndClearState();
                         // Special case -- if problem.depth == 0, just wrap the result and be done
                         if (isRoot())
--- a/src/share/classes/java/util/streams/ops/FoldOp.java	Tue Sep 04 14:14:34 2012 -0700
+++ b/src/share/classes/java/util/streams/ops/FoldOp.java	Tue Sep 04 15:29:13 2012 -0700
@@ -24,10 +24,9 @@
  */
 package java.util.streams.ops;
 
-import java.util.Spliterator;
+import java.util.streams.Spliterator;
 import java.util.concurrent.RecursiveTask;
 import java.util.functions.*;
-import java.util.streams.Sink;
 import java.util.streams.StatefulSink;
 
 /**
@@ -108,10 +107,7 @@
             }
             else {
                 final StatefulSink<T, U> reduceStage = op.sink();
-                final Sink<V, ?, ?> chain = helper.sink(reduceStage);
-                chain.begin(-1);
-                source.forEach(chain);
-                chain.end();
+                source.into(helper.sink(reduceStage));
                 return reduceStage.getAndClearState();
             }
         }
--- a/src/share/classes/java/util/streams/ops/ForEachOp.java	Tue Sep 04 14:14:34 2012 -0700
+++ b/src/share/classes/java/util/streams/ops/ForEachOp.java	Tue Sep 04 15:29:13 2012 -0700
@@ -26,7 +26,7 @@
 
 import java.util.Mapping;
 import java.util.Objects;
-import java.util.Spliterator;
+import java.util.streams.Spliterator;
 import java.util.concurrent.RecursiveAction;
 import java.util.functions.BiBlock;
 import java.util.functions.Block;
@@ -90,7 +90,7 @@
         Sink<V, ?, ?> compoundSink = helper.sink(sink);
         Spliterator<V> spliterator = helper.spliterator();
         if (depth == 0) {
-            spliterator.forEach(compoundSink);
+            spliterator.into(compoundSink);
         } else {
             helper.invoke(new ForEachTask<>(depth, spliterator, compoundSink));
         }
@@ -111,7 +111,7 @@
         @Override
         protected void compute() {
             if (depth == 0) {
-                spliterator.forEach(sink);
+                spliterator.into(sink);
             } else {
                 ForEachTask<T> left = new ForEachTask<>(depth - 1, spliterator.split(), sink);
                 ForEachTask<T> right = new ForEachTask<>(depth - 1, spliterator, sink);
--- a/src/share/classes/java/util/streams/ops/ParallelOp.java	Tue Sep 04 14:14:34 2012 -0700
+++ b/src/share/classes/java/util/streams/ops/ParallelOp.java	Tue Sep 04 15:29:13 2012 -0700
@@ -25,7 +25,7 @@
 package java.util.streams.ops;
 
 import java.util.Iterator;
-import java.util.Spliterator;
+import java.util.streams.Spliterator;
 import java.util.concurrent.ForkJoinTask;
 import java.util.streams.Sink;
 
--- a/src/share/classes/java/util/streams/ops/StatefulOp.java	Tue Sep 04 14:14:34 2012 -0700
+++ b/src/share/classes/java/util/streams/ops/StatefulOp.java	Tue Sep 04 15:29:13 2012 -0700
@@ -25,11 +25,7 @@
     <Z> TreeUtils.Node<U> computeParallel(ParallelOpHelper<T, Z> helper) default {
         // dumb default serial implementation
         final StreamBuilder<U> sb = StreamBuilders.make();
-        Sink<Z, ?, ?> sink = helper.sink(sink(sb));
-        Spliterator<Z> spliterator = helper.spliterator();
-        sink.begin(spliterator.getRemainingSizeIfKnown());
-        spliterator.forEach(sink);
-        sink.end();
+        helper.spliterator().into(helper.sink(sink(sb)));
         return TreeUtils.node(sb);
     }
 }
--- a/src/share/classes/java/util/streams/ops/TerminalOp.java	Tue Sep 04 14:14:34 2012 -0700
+++ b/src/share/classes/java/util/streams/ops/TerminalOp.java	Tue Sep 04 15:29:13 2012 -0700
@@ -25,8 +25,6 @@
 package java.util.streams.ops;
 
 import java.util.Iterator;
-import java.util.Spliterator;
-import java.util.streams.Sink;
 import java.util.streams.StatefulSink;
 
 /**
@@ -59,11 +57,7 @@
     <V> U computeParallel(ParallelOpHelper<T, V> helper) default {
         // dumb default serial version
         StatefulSink<T, U> toArraySink = sink();
-        Sink<V, ?, ?> sink = helper.sink(toArraySink);
-        Spliterator<V> spliterator = helper.spliterator();
-        sink.begin(spliterator.getRemainingSizeIfKnown());
-        spliterator.forEach(sink);
-        sink.end();
+        helper.spliterator().into(helper.sink(toArraySink));
         return toArraySink.getAndClearState();
     }
 }
--- a/src/share/classes/java/util/streams/ops/ToArrayOp.java	Tue Sep 04 14:14:34 2012 -0700
+++ b/src/share/classes/java/util/streams/ops/ToArrayOp.java	Tue Sep 04 15:29:13 2012 -0700
@@ -35,6 +35,7 @@
 public class ToArrayOp<T> implements TerminalOp<T, Object[]> {
 
     private final static ToArrayOp<?> INSTANCE = new ToArrayOp<>();
+    private final static Object[] EMPTY_ARRAY = new Object[0];
 
     @SuppressWarnings("unchecked")
     public static <T> ToArrayOp<T> singleton() {
@@ -47,7 +48,7 @@
         return new StatefulSink<T, Object[]>() {
             private static final int DEFAULT_CHUNK = 16;
             Object[] elements;
-            int count;
+            int count = 0;
 
             @Override
             public void begin(int size) {
@@ -67,11 +68,16 @@
 
             @Override
             public Object[] getAndClearState() {
-                Object[] result = (count == elements.length)
-                                  ? elements
-                                  : Arrays.copyOf(elements, count);
-                elements = null;
-                return result;
+                if (count == 0)
+                    return EMPTY_ARRAY;
+                else {
+                    Object[] result = (count == elements.length)
+                                      ? elements
+                                      : Arrays.copyOf(elements, count);
+                    elements = null;
+                    count = 0;
+                    return result;
+                }
             }
         };
     }
--- a/src/share/classes/java/util/streams/ops/TreeUtils.java	Tue Sep 04 14:14:34 2012 -0700
+++ b/src/share/classes/java/util/streams/ops/TreeUtils.java	Tue Sep 04 15:29:13 2012 -0700
@@ -53,18 +53,12 @@
             // Need to account for SIZED flag from pipeline
             if (size != -1 && splitSizesKnown) {
                 builder = StreamBuilders.makeFixed(size);
-                Sink sink = helper.sink(builder);
-                sink.begin(spliterator.getRemainingSizeIfKnown());
-                spliterator.forEach(sink);
-                sink.end();
+                spliterator.into(helper.sink(builder));
                 return node((T[]) builder.toArray());
             }
             else {
                 builder = StreamBuilders.make();
-                Sink sink = helper.sink(builder);
-                sink.begin(spliterator.getRemainingSizeIfKnown());
-                spliterator.forEach(sink);
-                sink.end();
+                spliterator.into(helper.sink(builder));
                 return node(builder);
             }
         }
@@ -122,7 +116,7 @@
             if (depth == 0) {
                 // @@@ Usual comment about using fixed stream builders if we know enough to do so
                 StreamBuilder<U> builder = StreamBuilders.make();
-                spliterator.forEach(helper.sink(builder));
+                spliterator.into(helper.sink(builder));
                 return node(builder);
             }
             else {
@@ -156,7 +150,7 @@
         @Override
         protected void compute() {
             if (depth == 0) {
-                spliterator.forEach(helper.sink(Arrays.sink(array, offset, length)));
+                spliterator.into(helper.sink(Arrays.sink(array, offset, length)));
             }
             else {
                 Spliterator<T> split = spliterator.split();
@@ -199,8 +193,10 @@
         }
     }
 
-    public static interface Node<T> extends Traversable<T>, Streamable<T>, Splittable<T>, Sized {
+    public static interface Node<T> extends Traversable<T>, Streamable<T>, Sized, Iterable<T> {
         void copyTo(T[] array, int offset);
+
+        Spliterator<T> spliterator();
     }
 
     public static interface InternalNode<T> extends Node<T> {
@@ -370,7 +366,7 @@
             return String.format("IntNode[%s,%s]", left.toString(), right.toString());
         }
 
-        private static class InternalNodeSpliterator<T> implements Spliterator<T> {
+        private static class InternalNodeSpliterator<T> implements Spliterator<T>, Iterator<T> {
             private Node<T> cur;
             private Iterator<T> iterator;
 
@@ -378,7 +374,7 @@
                 this.cur = cur;
             }
 
-            private Iterator<T> iterator() {
+            public Iterator<T> iterator() {
                 if (iterator == null)
                     iterator = cur.iterator();
                 return iterator;
@@ -399,15 +395,17 @@
             }
 
             @Override
-            public void forEach(Block<? super T> block) {
+            public void into(Sink<T, ?, ?> sink) {
+                sink.begin(getRemainingSizeIfKnown());
                 if (iterator == null) {
-                    cur.forEach(block);
+                    cur.forEach(sink);
                     iterator = Collections.emptyIterator();
                 }
                 else {
                     while (iterator.hasNext())
-                        block.apply(iterator.next());
+                        sink.accept(iterator.next());
                 }
+                sink.end();
             }
 
             @Override
--- a/test-ng/tests/org/openjdk/tests/java/util/streams/ops/StreamOpTestCase.java	Tue Sep 04 14:14:34 2012 -0700
+++ b/test-ng/tests/org/openjdk/tests/java/util/streams/ops/StreamOpTestCase.java	Tue Sep 04 15:29:13 2012 -0700
@@ -516,7 +516,17 @@
 
         @Override
         public void forEach(Block<? super Mapping<K,V>> block) {
-            map.forEach(block);
+            map.forEach((k, v) -> block.apply(new Mapping.AbstractMapping<K,V>() {
+                @Override
+                public K getKey() {
+                    return k;
+                }
+
+                @Override
+                public V getValue() {
+                    return v;
+                }
+            }));
         }
 
         public void forEach(BiBlock<? super K, ? super V> block) {