changeset 8442:2fba6ae13ed8

Merge
author mduigou
date Tue, 30 Apr 2013 12:32:49 -0700
parents 0e6f412f5536 ac3e189c9099
children 7c4898c8b974 1432a6247ac9
files
diffstat 16 files changed, 4766 insertions(+), 97 deletions(-) [+]
line wrap: on
line diff
--- a/src/share/classes/java/net/Inet6Address.java	Tue Apr 30 12:31:51 2013 -0700
+++ b/src/share/classes/java/net/Inet6Address.java	Tue Apr 30 12:32:49 2013 -0700
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2000, 2011, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2000, 2013, 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
@@ -203,6 +203,12 @@
      */
     private transient NetworkInterface scope_ifname;  // null
 
+    /**
+     * set if the object is constructed with a scoped
+     * interface instead of a numeric scope id.
+     */
+    private boolean scope_ifname_set; // false;
+
     private static final long serialVersionUID = 6880410070516793377L;
 
     // Perform native initialization
@@ -332,7 +338,7 @@
         }
     }
 
-    private void initif(String hostName, byte addr[],NetworkInterface nif)
+    private void initif(String hostName, byte addr[], NetworkInterface nif)
         throws UnknownHostException
     {
         holder().hostName = hostName;
@@ -344,6 +350,7 @@
             scope_ifname = nif;
             scope_id = deriveNumericScope(nif);
             scope_id_set = true;
+            scope_ifname_set = true;  // for consistency
         }
     }
 
@@ -431,6 +438,7 @@
             try {
                 scope_ifname = NetworkInterface.getByName(ifname);
                 if (scope_ifname != null) {
+                    scope_ifname_set = true;
                     try {
                         scope_id = deriveNumericScope(scope_ifname);
                     } catch (UnknownHostException e) {
@@ -438,6 +446,12 @@
                         // the machine being used for deserialization has
                         // the same interface name but without IPv6 configured.
                     }
+                } else {
+                    /* the interface does not exist on this system, so we clear
+                     * the scope information completely */
+                    scope_id_set = false;
+                    scope_ifname_set = false;
+                    scope_id = 0;
                 }
             } catch (SocketException e) {}
 
@@ -784,8 +798,10 @@
     private synchronized void writeObject(java.io.ObjectOutputStream s)
         throws IOException
     {
-        if (scope_ifname != null)
+        if (scope_ifname != null) {
             ifname = scope_ifname.getName();
+            scope_ifname_set = true;
+        }
         s.defaultWriteObject();
     }
 }
--- a/src/share/classes/java/sql/Driver.java	Tue Apr 30 12:31:51 2013 -0700
+++ b/src/share/classes/java/sql/Driver.java	Tue Apr 30 12:32:49 2013 -0700
@@ -44,13 +44,16 @@
  *
  * <P>When a Driver class is loaded, it should create an instance of
  * itself and register it with the DriverManager. This means that a
- * user can load and register a driver by calling
- * <pre>
- *   <code>Class.forName("foo.bah.Driver")</code>
- * </pre>
- *
+ * user can load and register a driver by calling:
+ * <p>
+ * {@code Class.forName("foo.bah.Driver")}
+ * <p>
+ * A JDBC driver may create a {@linkplain DriverAction} implementation in order
+ * to receive notifications when {@linkplain DriverManager#deregisterDriver} has
+ * been called.
  * @see DriverManager
  * @see Connection
+ * @see DriverAction
  */
 public interface Driver {
 
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/share/classes/java/sql/DriverAction.java	Tue Apr 30 12:32:49 2013 -0700
@@ -0,0 +1,66 @@
+/*
+ * Copyright (c) 2013, 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.sql;
+
+/**
+ * An interface that must be implemented when a {@linkplain Driver} wants to be
+ * notified by {@code DriverManager}.
+ *<P>
+ * A {@code DriverAction} implementation is not intended to be used
+ * directly by applications. A JDBC Driver  may choose
+ * to create its {@code DriverAction} implementation in a private class
+ * to avoid it being called directly.
+ * <o>
+ * The JDBC driver's static initialization block must call
+ * {@linkplain DriverManager#registerDriver(java.sql.Driver, java.sql.DriverAction) } in order
+ * to inform {@code DriverManager} which {@code DriverAction} implementation to
+ * call when the JDBC driver is de-registered.
+ * @since 1.8
+ */
+public interface DriverAction {
+    /**
+     * Method called by
+     * {@linkplain DriverManager#deregisterDriver(Driver) }
+     *  to notify the JDBC driver that it was de-registered.
+     * <p>
+     * The {@code deregister} method is intended only to be used by JDBC Drivers
+     * and not by applications.  JDBC drivers are recommended to not implement
+     * {@code DriverAction} in a public class.  If there are active
+     * connections to the database at the time that the {@code deregister}
+     * method is called, it is implementation specific as to whether the
+     * connections are closed or allowed to continue. Once this method is
+     * called, it is implementation specific as to whether the driver may
+     * limit the ability to create new connections to the database, invoke
+     * other {@code Driver} methods or throw a {@code SQLException}.
+     * Consult your JDBC driver's documentation for additional information
+     * on its behavior.
+     * @see DriverManager#registerDriver(java.sql.Driver, java.sql.DriverAction)
+     * @see DriverManager#deregisterDriver(Driver)
+     * @since 1.8
+     */
+    void deregister();
+
+}
--- a/src/share/classes/java/sql/DriverManager.java	Tue Apr 30 12:31:51 2013 -0700
+++ b/src/share/classes/java/sql/DriverManager.java	Tue Apr 30 12:32:49 2013 -0700
@@ -110,6 +110,14 @@
     final static SQLPermission SET_LOG_PERMISSION =
         new SQLPermission("setLog");
 
+    /**
+     * The {@code SQLPermission} constant that allows the
+     * un-register a registered JDBC driver.
+     * @since 1.8
+     */
+    final static SQLPermission DEREGISTER_DRIVER_PERMISSION =
+        new SQLPermission("deregisterDriver");
+
     //--------------------------JDBC 2.0-----------------------------
 
     /**
@@ -309,21 +317,42 @@
 
 
     /**
-     * Registers the given driver with the <code>DriverManager</code>.
+     * Registers the given driver with the {@code DriverManager}.
      * A newly-loaded driver class should call
-     * the method <code>registerDriver</code> to make itself
-     * known to the <code>DriverManager</code>.
+     * the method {@code registerDriver} to make itself
+     * known to the {@code DriverManager}. If the driver had previously been
+     * registered, no action is taken.
      *
      * @param driver the new JDBC Driver that is to be registered with the
-     *               <code>DriverManager</code>
+     *               {@code DriverManager}
      * @exception SQLException if a database access error occurs
      */
     public static synchronized void registerDriver(java.sql.Driver driver)
         throws SQLException {
 
+        registerDriver(driver, null);
+    }
+
+    /**
+     * Registers the given driver with the {@code DriverManager}.
+     * A newly-loaded driver class should call
+     * the method {@code registerDriver} to make itself
+     * known to the {@code DriverManager}. If the driver had previously been
+     * registered, no action is taken.
+     *
+     * @param driver the new JDBC Driver that is to be registered with the
+     *               {@code DriverManager}
+     * @param da     the {@code DriverAction} implementation to be used when
+     *               {@code DriverManager#deregisterDriver} is called
+     * @exception SQLException if a database access error occurs
+     */
+    public static synchronized void registerDriver(java.sql.Driver driver,
+            DriverAction da)
+        throws SQLException {
+
         /* Register the driver if it has not already been added to our list */
         if(driver != null) {
-            registeredDrivers.addIfAbsent(new DriverInfo(driver));
+            registeredDrivers.addIfAbsent(new DriverInfo(driver, da));
         } else {
             // This is for compatibility with the original DriverManager
             throw new NullPointerException();
@@ -334,11 +363,29 @@
     }
 
     /**
-     * Drops a driver from the <code>DriverManager</code>'s list.
-     *  Applets can only deregister drivers from their own classloaders.
+     * Removes the specified driver from the {@code DriverManager}'s list of
+     * registered drivers.
+     * <p>
+     * If a {@code null} value is specified for the driver to be removed, then no
+     * action is taken.
+     * <p>
+     * If a security manager exists and its {@code checkPermission} denies
+     * permission, then a {@code SecurityException} will be thrown.
+     * <p>
+     * If the specified driver is not found in the list of registered drivers,
+     * then no action is taken.  If the driver was found, it will be removed
+     * from the list of registered drivers.
+     * <p>
+     * If a {@code DriverAction} instance was specified when the JDBC driver was
+     * registered, its deregister method will be called
+     * prior to the driver being removed from the list of registered drivers.
      *
-     * @param driver the JDBC Driver to drop
+     * @param driver the JDBC Driver to remove
      * @exception SQLException if a database access error occurs
+     * @throws SecurityException if a security manager exists and its
+     * {@code checkPermission} method denies permission to deregister a driver.
+     *
+     * @see SecurityManager#checkPermission
      */
     @CallerSensitive
     public static synchronized void deregisterDriver(Driver driver)
@@ -347,11 +394,22 @@
             return;
         }
 
+        SecurityManager sec = System.getSecurityManager();
+        if (sec != null) {
+            sec.checkPermission(DEREGISTER_DRIVER_PERMISSION);
+        }
+
         println("DriverManager.deregisterDriver: " + driver);
 
-        DriverInfo aDriver = new DriverInfo(driver);
+        DriverInfo aDriver = new DriverInfo(driver, null);
         if(registeredDrivers.contains(aDriver)) {
             if (isDriverAllowed(driver, Reflection.getCallerClass())) {
+                DriverInfo di = registeredDrivers.get(registeredDrivers.indexOf(aDriver));
+                 // If a DriverAction was specified, Call it to notify the
+                 // driver that it has been deregistered
+                 if(di.action() != null) {
+                     di.action().deregister();
+                 }
                  registeredDrivers.remove(aDriver);
             } else {
                 // If the caller does not have permission to load the driver then
@@ -639,8 +697,10 @@
 class DriverInfo {
 
     final Driver driver;
-    DriverInfo(Driver driver) {
+    DriverAction da;
+    DriverInfo(Driver driver, DriverAction action) {
         this.driver = driver;
+        da = action;
     }
 
     @Override
@@ -658,4 +718,8 @@
     public String toString() {
         return ("driver[className="  + driver + "]");
     }
+
+    DriverAction action() {
+        return da;
+    }
 }
--- a/src/share/classes/java/sql/SQLPermission.java	Tue Apr 30 12:31:51 2013 -0700
+++ b/src/share/classes/java/sql/SQLPermission.java	Tue Apr 30 12:32:49 2013 -0700
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 1999, 2012, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1999, 2013, 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
@@ -30,8 +30,9 @@
 
 /**
  * The permission for which the <code>SecurityManager</code> will check
- * when code that is running in an applet, or an application with a
+ * when code that is running an application with a
  * <code>SecurityManager</code> enabled, calls the
+ * {@code DriverManager.deregisterDriver} method,
  * <code>DriverManager.setLogWriter</code> method,
  * <code>DriverManager.setLogStream</code> (deprecated) method,
  * {@code SyncFactory.setJNDIContext} method,
@@ -95,14 +96,16 @@
  * <code>Connection</code> or
  * objects created from the <code>Connection</code>
  * will wait for the database to reply to any one request.</td>
+ * <tr>
+ * <td>deregisterDriver</td>
+ *   <td>Allows the invocation of the {@code DriverManager}
+ * method {@code deregisterDriver}</td>
+ *   <td>Permits an application to remove a JDBC driver from the list of
+ * registered Drivers and release its resources.</td>
+ * </tr>
  * </tr>
  * </table>
  *<p>
- * The person running an applet decides what permissions to allow
- * and will run the <code>Policy Tool</code> to create an
- * <code>SQLPermission</code> in a policy file.  A programmer does
- * not use a constructor directly to create an instance of <code>SQLPermission</code>
- * but rather uses a tool.
  * @since 1.3
  * @see java.security.BasicPermission
  * @see java.security.Permission
--- a/src/share/classes/java/util/Arrays.java	Tue Apr 30 12:31:51 2013 -0700
+++ b/src/share/classes/java/util/Arrays.java	Tue Apr 30 12:32:49 2013 -0700
@@ -25,7 +25,21 @@
 
 package java.util;
 
-import java.lang.reflect.*;
+import java.lang.reflect.Array;
+import java.util.concurrent.ForkJoinPool;
+import java.util.function.BinaryOperator;
+import java.util.function.DoubleBinaryOperator;
+import java.util.function.IntBinaryOperator;
+import java.util.function.IntFunction;
+import java.util.function.IntToDoubleFunction;
+import java.util.function.IntToLongFunction;
+import java.util.function.IntUnaryOperator;
+import java.util.function.LongBinaryOperator;
+import java.util.stream.DoubleStream;
+import java.util.stream.IntStream;
+import java.util.stream.LongStream;
+import java.util.stream.Stream;
+import java.util.stream.StreamSupport;
 import static java.util.ArraysParallelSortHelpers.*;
 
 /**
@@ -4306,17 +4320,171 @@
         dejaVu.remove(a);
     }
 
+
     /**
-     * Creates a {@link Spliterator} covering all of the specified array.
+     * Set all elements of the specified array, using the provided
+     * generator function to compute each element.
+     *
+     * <p>If the generator function throws an exception, it is relayed to
+     * the caller and the array is left in an indeterminate state.
+     *
+     * @param <T> type of elements of the array
+     * @param array array to be initialized
+     * @param generator a function accepting an index and producing the desired
+     *        value for that position
+     * @throws NullPointerException if the generator is null
+     * @since 1.8
+     */
+    public static <T> void setAll(T[] array, IntFunction<? extends T> generator) {
+        Objects.requireNonNull(generator);
+        for (int i = 0; i < array.length; i++)
+            array[i] = generator.apply(i);
+    }
+
+    /**
+     * Set all elements of the specified array, in parallel, using the
+     * provided generator function to compute each element.
+     *
+     * <p>If the generator function throws an exception, an unchecked exception
+     * is thrown from {@code parallelSetAll} and the array is left in an
+     * indeterminate state.
+     *
+     * @param <T> type of elements of the array
+     * @param array array to be initialized
+     * @param generator a function accepting an index and producing the desired
+     *        value for that position
+     * @throws NullPointerException if the generator is null
+     * @since 1.8
+     */
+    public static <T> void parallelSetAll(T[] array, IntFunction<? extends T> generator) {
+        Objects.requireNonNull(generator);
+        IntStream.range(0, array.length).parallel().forEach(i -> { array[i] = generator.apply(i); });
+    }
+
+    /**
+     * Set all elements of the specified array, using the provided
+     * generator function to compute each element.
+     *
+     * <p>If the generator function throws an exception, it is relayed to
+     * the caller and the array is left in an indeterminate state.
+     *
+     * @param array array to be initialized
+     * @param generator a function accepting an index and producing the desired
+     *        value for that position
+     * @throws NullPointerException if the generator is null
+     * @since 1.8
+     */
+    public static void setAll(int[] array, IntUnaryOperator generator) {
+        Objects.requireNonNull(generator);
+        for (int i = 0; i < array.length; i++)
+            array[i] = generator.applyAsInt(i);
+    }
+
+    /**
+     * Set all elements of the specified array, in parallel, using the
+     * provided generator function to compute each element.
+     *
+     * <p>If the generator function throws an exception, an unchecked exception
+     * is thrown from {@code parallelSetAll} and the array is left in an
+     * indeterminate state.
+     *
+     * @param array array to be initialized
+     * @param generator a function accepting an index and producing the desired
+     * value for that position
+     * @throws NullPointerException if the generator is null
+     * @since 1.8
+     */
+    public static void parallelSetAll(int[] array, IntUnaryOperator generator) {
+        Objects.requireNonNull(generator);
+        IntStream.range(0, array.length).parallel().forEach(i -> { array[i] = generator.applyAsInt(i); });
+    }
+
+    /**
+     * Set all elements of the specified array, using the provided
+     * generator function to compute each element.
+     *
+     * <p>If the generator function throws an exception, it is relayed to
+     * the caller and the array is left in an indeterminate state.
+     *
+     * @param array array to be initialized
+     * @param generator a function accepting an index and producing the desired
+     *        value for that position
+     * @throws NullPointerException if the generator is null
+     * @since 1.8
+     */
+    public static void setAll(long[] array, IntToLongFunction generator) {
+        Objects.requireNonNull(generator);
+        for (int i = 0; i < array.length; i++)
+            array[i] = generator.applyAsLong(i);
+    }
+
+    /**
+     * Set all elements of the specified array, in parallel, using the
+     * provided generator function to compute each element.
+     *
+     * <p>If the generator function throws an exception, an unchecked exception
+     * is thrown from {@code parallelSetAll} and the array is left in an
+     * indeterminate state.
+     *
+     * @param array array to be initialized
+     * @param generator a function accepting an index and producing the desired
+     *        value for that position
+     * @throws NullPointerException if the generator is null
+     * @since 1.8
+     */
+    public static void parallelSetAll(long[] array, IntToLongFunction generator) {
+        Objects.requireNonNull(generator);
+        IntStream.range(0, array.length).parallel().forEach(i -> { array[i] = generator.applyAsLong(i); });
+    }
+
+    /**
+     * Set all elements of the specified array, using the provided
+     * generator function to compute each element.
+     *
+     * <p>If the generator function throws an exception, it is relayed to
+     * the caller and the array is left in an indeterminate state.
+     *
+     * @param array array to be initialized
+     * @param generator a function accepting an index and producing the desired
+     *        value for that position
+     * @throws NullPointerException if the generator is null
+     * @since 1.8
+     */
+    public static void setAll(double[] array, IntToDoubleFunction generator) {
+        Objects.requireNonNull(generator);
+        for (int i = 0; i < array.length; i++)
+            array[i] = generator.applyAsDouble(i);
+    }
+
+    /**
+     * Set all elements of the specified array, in parallel, using the
+     * provided generator function to compute each element.
+     *
+     * <p>If the generator function throws an exception, an unchecked exception
+     * is thrown from {@code parallelSetAll} and the array is left in an
+     * indeterminate state.
+     *
+     * @param array array to be initialized
+     * @param generator a function accepting an index and producing the desired
+     *        value for that position
+     * @throws NullPointerException if the generator is null
+     * @since 1.8
+     */
+    public static void parallelSetAll(double[] array, IntToDoubleFunction generator) {
+        Objects.requireNonNull(generator);
+        IntStream.range(0, array.length).parallel().forEach(i -> { array[i] = generator.applyAsDouble(i); });
+    }
+
+    /**
+     * Returns a {@link Spliterator} covering all of the specified array.
      *
      * <p>The spliterator reports {@link Spliterator#SIZED},
      * {@link Spliterator#SUBSIZED}, {@link Spliterator#ORDERED}, and
      * {@link Spliterator#IMMUTABLE}.
      *
-     * @param <T> Type of elements
-     * @param array The array, assumed to be unmodified during use
-     * @return A spliterator from the array
-     * @throws NullPointerException if the specified array is {@code null}
+     * @param <T> type of elements
+     * @param array the array, assumed to be unmodified during use
+     * @return a spliterator for the array elements
      * @since 1.8
      */
     public static <T> Spliterator<T> spliterator(T[] array) {
@@ -4325,39 +4493,38 @@
     }
 
     /**
-     * Creates a {@link Spliterator} covering the specified range of the
+     * Returns a {@link Spliterator} covering the specified range of the
      * specified array.
      *
      * <p>The spliterator reports {@link Spliterator#SIZED},
      * {@link Spliterator#SUBSIZED}, {@link Spliterator#ORDERED}, and
      * {@link Spliterator#IMMUTABLE}.
      *
-     * @param <T> Type of elements
-     * @param array The array, assumed to be unmodified during use
-     * @param fromIndex The least index (inclusive) to cover
-     * @param toIndex One past the greatest index to cover
-     * @return A spliterator from the array
-     * @throws NullPointerException if the specified array is {@code null}
-     * @throws ArrayIndexOutOfBoundsException if {@code fromIndex} is negative,
-     *         {@code toIndex} is less than {@code fromIndex}, or
-     *         {@code toIndex} is greater than the array size
+     * @param <T> type of elements
+     * @param array the array, assumed to be unmodified during use
+     * @param startInclusive the first index to cover, inclusive
+     * @param endExclusive index immediately past the last index to cover
+     * @return a spliterator for the array elements
+     * @throws ArrayIndexOutOfBoundsException if {@code startInclusive} is
+     *         negative, {@code endExclusive} is less than
+     *         {@code startInclusive}, or {@code endExclusive} is greater than
+     *         the array size
      * @since 1.8
      */
-    public static <T> Spliterator<T> spliterator(T[] array, int fromIndex, int toIndex) {
-        return Spliterators.spliterator(array, fromIndex, toIndex,
+    public static <T> Spliterator<T> spliterator(T[] array, int startInclusive, int endExclusive) {
+        return Spliterators.spliterator(array, startInclusive, endExclusive,
                                         Spliterator.ORDERED | Spliterator.IMMUTABLE);
     }
 
     /**
-     * Creates a {@link Spliterator.OfInt} covering all of the specified array.
+     * Returns a {@link Spliterator.OfInt} covering all of the specified array.
      *
      * <p>The spliterator reports {@link Spliterator#SIZED},
      * {@link Spliterator#SUBSIZED}, {@link Spliterator#ORDERED}, and
      * {@link Spliterator#IMMUTABLE}.
      *
-     * @param array The array, assumed to be unmodified during use
-     * @return A spliterator from the array
-     * @throws NullPointerException if the specified array is {@code null}
+     * @param array the array, assumed to be unmodified during use
+     * @return a spliterator for the array elements
      * @since 1.8
      */
     public static Spliterator.OfInt spliterator(int[] array) {
@@ -4366,38 +4533,37 @@
     }
 
     /**
-     * Creates a {@link Spliterator.OfInt} covering the specified range of the
+     * Returns a {@link Spliterator.OfInt} covering the specified range of the
      * specified array.
      *
      * <p>The spliterator reports {@link Spliterator#SIZED},
      * {@link Spliterator#SUBSIZED}, {@link Spliterator#ORDERED}, and
      * {@link Spliterator#IMMUTABLE}.
      *
-     * @param array The array, assumed to be unmodified during use
-     * @param fromIndex The least index (inclusive) to cover
-     * @param toIndex One past the greatest index to cover
-     * @return A spliterator from the array
-     * @throws NullPointerException if the specified array is {@code null}
-     * @throws ArrayIndexOutOfBoundsException if {@code fromIndex} is negative,
-     *         {@code toIndex} is less than {@code fromIndex}, or
-     *         {@code toIndex} is greater than the array size
+     * @param array the array, assumed to be unmodified during use
+     * @param startInclusive the first index to cover, inclusive
+     * @param endExclusive index immediately past the last index to cover
+     * @return a spliterator for the array elements
+     * @throws ArrayIndexOutOfBoundsException if {@code startInclusive} is
+     *         negative, {@code endExclusive} is less than
+     *         {@code startInclusive}, or {@code endExclusive} is greater than
+     *         the array size
      * @since 1.8
      */
-    public static Spliterator.OfInt spliterator(int[] array, int fromIndex, int toIndex) {
-        return Spliterators.spliterator(array, fromIndex, toIndex,
+    public static Spliterator.OfInt spliterator(int[] array, int startInclusive, int endExclusive) {
+        return Spliterators.spliterator(array, startInclusive, endExclusive,
                                         Spliterator.ORDERED | Spliterator.IMMUTABLE);
     }
 
     /**
-     * Creates a {@link Spliterator.OfLong} covering all of the specified array.
+     * Returns a {@link Spliterator.OfLong} covering all of the specified array.
      *
      * <p>The spliterator reports {@link Spliterator#SIZED},
      * {@link Spliterator#SUBSIZED}, {@link Spliterator#ORDERED}, and
      * {@link Spliterator#IMMUTABLE}.
      *
-     * @param array The array, assumed to be unmodified during use
-     * @return A spliterator from the array
-     * @throws NullPointerException if the specified array is {@code null}
+     * @param array the array, assumed to be unmodified during use
+     * @return the spliterator for the array elements
      * @since 1.8
      */
     public static Spliterator.OfLong spliterator(long[] array) {
@@ -4406,39 +4572,38 @@
     }
 
     /**
-     * Creates a {@link Spliterator.OfLong} covering the specified range of the
+     * Returns a {@link Spliterator.OfLong} covering the specified range of the
      * specified array.
      *
      * <p>The spliterator reports {@link Spliterator#SIZED},
      * {@link Spliterator#SUBSIZED}, {@link Spliterator#ORDERED}, and
      * {@link Spliterator#IMMUTABLE}.
      *
-     * @param array The array, assumed to be unmodified during use
-     * @param fromIndex The least index (inclusive) to cover
-     * @param toIndex One past the greatest index to cover
-     * @return A spliterator from the array
-     * @throws NullPointerException if the specified array is {@code null}
-     * @throws ArrayIndexOutOfBoundsException if {@code fromIndex} is negative,
-     *         {@code toIndex} is less than {@code fromIndex}, or
-     *         {@code toIndex} is greater than the array size
+     * @param array the array, assumed to be unmodified during use
+     * @param startInclusive the first index to cover, inclusive
+     * @param endExclusive index immediately past the last index to cover
+     * @return a spliterator for the array elements
+     * @throws ArrayIndexOutOfBoundsException if {@code startInclusive} is
+     *         negative, {@code endExclusive} is less than
+     *         {@code startInclusive}, or {@code endExclusive} is greater than
+     *         the array size
      * @since 1.8
      */
-    public static Spliterator.OfLong spliterator(long[] array, int fromIndex, int toIndex) {
-        return Spliterators.spliterator(array, fromIndex, toIndex,
+    public static Spliterator.OfLong spliterator(long[] array, int startInclusive, int endExclusive) {
+        return Spliterators.spliterator(array, startInclusive, endExclusive,
                                         Spliterator.ORDERED | Spliterator.IMMUTABLE);
     }
 
     /**
-     * Creates a {@link Spliterator.OfDouble} covering all of the specified
+     * Returns a {@link Spliterator.OfDouble} covering all of the specified
      * array.
      *
      * <p>The spliterator reports {@link Spliterator#SIZED},
      * {@link Spliterator#SUBSIZED}, {@link Spliterator#ORDERED}, and
      * {@link Spliterator#IMMUTABLE}.
      *
-     * @param array The array, assumed to be unmodified during use
-     * @return A spliterator from the array
-     * @throws NullPointerException if the specified array is {@code null}
+     * @param array the array, assumed to be unmodified during use
+     * @return a spliterator for the array elements
      * @since 1.8
      */
     public static Spliterator.OfDouble spliterator(double[] array) {
@@ -4447,25 +4612,147 @@
     }
 
     /**
-     * Creates a {@link Spliterator.OfDouble} covering the specified range of
+     * Returns a {@link Spliterator.OfDouble} covering the specified range of
      * the specified array.
      *
      * <p>The spliterator reports {@link Spliterator#SIZED},
      * {@link Spliterator#SUBSIZED}, {@link Spliterator#ORDERED}, and
      * {@link Spliterator#IMMUTABLE}.
      *
-     * @param array The array, assumed to be unmodified during use
-     * @param fromIndex The least index (inclusive) to cover
-     * @param toIndex One past the greatest index to cover
-     * @return A spliterator from the array
-     * @throws NullPointerException if the specified array is {@code null}
-     * @throws ArrayIndexOutOfBoundsException if {@code fromIndex} is negative,
-     *         {@code toIndex} is less than {@code fromIndex}, or
-     *         {@code toIndex} is greater than the array size
+     * @param array the array, assumed to be unmodified during use
+     * @param startInclusive the first index to cover, inclusive
+     * @param endExclusive index immediately past the last index to cover
+     * @return a spliterator for the array elements
+     * @throws ArrayIndexOutOfBoundsException if {@code startInclusive} is
+     *         negative, {@code endExclusive} is less than
+     *         {@code startInclusive}, or {@code endExclusive} is greater than
+     *         the array size
      * @since 1.8
      */
-    public static Spliterator.OfDouble spliterator(double[] array, int fromIndex, int toIndex) {
-        return Spliterators.spliterator(array, fromIndex, toIndex,
+    public static Spliterator.OfDouble spliterator(double[] array, int startInclusive, int endExclusive) {
+        return Spliterators.spliterator(array, startInclusive, endExclusive,
                                         Spliterator.ORDERED | Spliterator.IMMUTABLE);
     }
+
+    /**
+     * Returns a sequential {@link Stream} with the specified array as its
+     * source.
+     *
+     * @param <T> The type of the array elements
+     * @param array The array, assumed to be unmodified during use
+     * @return a {@code Stream} for the array
+     * @since 1.8
+     */
+    public static <T> Stream<T> stream(T[] array) {
+        return stream(array, 0, array.length);
+    }
+
+    /**
+     * Returns a sequential {@link Stream} with the specified range of the
+     * specified array as its source.
+     *
+     * @param <T> the type of the array elements
+     * @param array the array, assumed to be unmodified during use
+     * @param startInclusive the first index to cover, inclusive
+     * @param endExclusive index immediately past the last index to cover
+     * @return a {@code Stream} for the array range
+     * @throws ArrayIndexOutOfBoundsException if {@code startInclusive} is
+     *         negative, {@code endExclusive} is less than
+     *         {@code startInclusive}, or {@code endExclusive} is greater than
+     *         the array size
+     * @since 1.8
+     */
+    public static <T> Stream<T> stream(T[] array, int startInclusive, int endExclusive) {
+        return StreamSupport.stream(spliterator(array, startInclusive, endExclusive));
+    }
+
+    /**
+     * Returns a sequential {@link IntStream} with the specified array as its
+     * source.
+     *
+     * @param array the array, assumed to be unmodified during use
+     * @return an {@code IntStream} for the array
+     * @since 1.8
+     */
+    public static IntStream stream(int[] array) {
+        return stream(array, 0, array.length);
+    }
+
+    /**
+     * Returns a sequential {@link IntStream} with the specified range of the
+     * specified array as its source.
+     *
+     * @param array the array, assumed to be unmodified during use
+     * @param startInclusive the first index to cover, inclusive
+     * @param endExclusive index immediately past the last index to cover
+     * @return an {@code IntStream} for the array range
+     * @throws ArrayIndexOutOfBoundsException if {@code startInclusive} is
+     *         negative, {@code endExclusive} is less than
+     *         {@code startInclusive}, or {@code endExclusive} is greater than
+     *         the array size
+     * @since 1.8
+     */
+    public static IntStream stream(int[] array, int startInclusive, int endExclusive) {
+        return StreamSupport.intStream(spliterator(array, startInclusive, endExclusive));
+    }
+
+    /**
+     * Returns a sequential {@link LongStream} with the specified array as its
+     * source.
+     *
+     * @param array the array, assumed to be unmodified during use
+     * @return a {@code LongStream} for the array
+     * @since 1.8
+     */
+    public static LongStream stream(long[] array) {
+        return stream(array, 0, array.length);
+    }
+
+    /**
+     * Returns a sequential {@link LongStream} with the specified range of the
+     * specified array as its source.
+     *
+     * @param array the array, assumed to be unmodified during use
+     * @param startInclusive the first index to cover, inclusive
+     * @param endExclusive index immediately past the last index to cover
+     * @return a {@code LongStream} for the array range
+     * @throws ArrayIndexOutOfBoundsException if {@code startInclusive} is
+     *         negative, {@code endExclusive} is less than
+     *         {@code startInclusive}, or {@code endExclusive} is greater than
+     *         the array size
+     * @since 1.8
+     */
+    public static LongStream stream(long[] array, int startInclusive, int endExclusive) {
+        return StreamSupport.longStream(spliterator(array, startInclusive, endExclusive));
+    }
+
+    /**
+     * Returns a sequential {@link DoubleStream} with the specified array as its
+     * source.
+     *
+     * @param array the array, assumed to be unmodified during use
+     * @return a {@code DoubleStream} for the array
+     * @since 1.8
+     */
+    public static DoubleStream stream(double[] array) {
+        return stream(array, 0, array.length);
+    }
+
+    /**
+     * Returns a sequential {@link DoubleStream} with the specified range of the
+     * specified array as its source.
+     *
+     * @param array the array, assumed to be unmodified during use
+     * @param startInclusive the first index to cover, inclusive
+     * @param endExclusive index immediately past the last index to cover
+     * @return a {@code DoubleStream} for the array range
+     * @throws ArrayIndexOutOfBoundsException if {@code startInclusive} is
+     *         negative, {@code endExclusive} is less than
+     *         {@code startInclusive}, or {@code endExclusive} is greater than
+     *         the array size
+     * @since 1.8
+     */
+    public static DoubleStream stream(double[] array, int startInclusive, int endExclusive) {
+        return StreamSupport.doubleStream(spliterator(array, startInclusive, endExclusive));
+    }
 }
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/share/classes/java/util/stream/Collectors.java	Tue Apr 30 12:32:49 2013 -0700
@@ -0,0 +1,1320 @@
+/*
+ * Copyright (c) 2012, 2013, 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.stream;
+
+import java.util.AbstractMap;
+import java.util.AbstractSet;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.Comparator;
+import java.util.Comparators;
+import java.util.DoubleSummaryStatistics;
+import java.util.EnumSet;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.IntSummaryStatistics;
+import java.util.Iterator;
+import java.util.List;
+import java.util.LongSummaryStatistics;
+import java.util.Map;
+import java.util.NoSuchElementException;
+import java.util.Objects;
+import java.util.Set;
+import java.util.StringJoiner;
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.concurrent.ConcurrentMap;
+import java.util.function.BiFunction;
+import java.util.function.BinaryOperator;
+import java.util.function.Function;
+import java.util.function.Predicate;
+import java.util.function.Supplier;
+import java.util.function.ToDoubleFunction;
+import java.util.function.ToIntFunction;
+import java.util.function.ToLongFunction;
+
+/**
+ * Implementations of {@link Collector} that implement various useful reduction
+ * operations, such as accumulating elements into collections, summarizing
+ * elements according to various criteria, etc.
+ *
+ * <p>The following are examples of using the predefined {@code Collector}
+ * implementations in {@link Collectors} with the {@code Stream} API to perform
+ * mutable reduction tasks:
+ *
+ * <pre>{@code
+ *     // Accumulate elements into a List
+ *     List<Person> list = people.collect(Collectors.toList());
+ *
+ *     // Accumulate elements into a TreeSet
+ *     List<Person> list = people.collect(Collectors.toCollection(TreeSet::new));
+ *
+ *     // Convert elements to strings and concatenate them, separated by commas
+ *     String joined = stream.map(Object::toString)
+ *                           .collect(Collectors.toStringJoiner(", "))
+ *                           .toString();
+ *
+ *     // Find highest-paid employee
+ *     Employee highestPaid = employees.stream()
+ *                                     .collect(Collectors.maxBy(Comparators.comparing(Employee::getSalary)));
+ *
+ *     // Group employees by department
+ *     Map<Department, List<Employee>> byDept
+ *         = employees.stream()
+ *                    .collect(Collectors.groupingBy(Employee::getDepartment));
+ *
+ *     // Find highest-paid employee by department
+ *     Map<Department, Employee> highestPaidByDept
+ *         = employees.stream()
+ *                    .collect(Collectors.groupingBy(Employee::getDepartment,
+ *                                                   Collectors.maxBy(Comparators.comparing(Employee::getSalary))));
+ *
+ *     // Partition students into passing and failing
+ *     Map<Boolean, List<Student>> passingFailing =
+ *         students.stream()
+ *                 .collect(Collectors.partitioningBy(s -> s.getGrade() >= PASS_THRESHOLD);
+ *
+ * }</pre>
+ *
+ * TODO explanation of parallel collection
+ *
+ * @since 1.8
+ */
+public final class Collectors {
+
+    private static final Set<Collector.Characteristics> CH_CONCURRENT
+            = Collections.unmodifiableSet(EnumSet.of(Collector.Characteristics.CONCURRENT,
+                                                     Collector.Characteristics.STRICTLY_MUTATIVE,
+                                                     Collector.Characteristics.UNORDERED));
+    private static final Set<Collector.Characteristics> CH_STRICT
+            = Collections.unmodifiableSet(EnumSet.of(Collector.Characteristics.STRICTLY_MUTATIVE));
+    private static final Set<Collector.Characteristics> CH_STRICT_UNORDERED
+            = Collections.unmodifiableSet(EnumSet.of(Collector.Characteristics.STRICTLY_MUTATIVE,
+                                                     Collector.Characteristics.UNORDERED));
+
+    private Collectors() { }
+
+    /**
+     * Returns a merge function, suitable for use in
+     * {@link Map#merge(Object, Object, BiFunction) Map.merge()} or
+     * {@link #toMap(Function, Function, BinaryOperator) toMap()}, which always
+     * throws {@code IllegalStateException}.  This can be used to enforce the
+     * assumption that the elements being collected are distinct.
+     *
+     * @param <T> the type of input arguments to the merge function
+     * @return a merge function which always throw {@code IllegalStateException}
+     *
+     * @see #firstWinsMerger()
+     * @see #lastWinsMerger()
+     */
+    public static <T> BinaryOperator<T> throwingMerger() {
+        return (u,v) -> { throw new IllegalStateException(String.format("Duplicate key %s", u)); };
+    }
+
+    /**
+     * Returns a merge function, suitable for use in
+     * {@link Map#merge(Object, Object, BiFunction) Map.merge()} or
+     * {@link #toMap(Function, Function, BinaryOperator) toMap()},
+     * which implements a "first wins" policy.
+     *
+     * @param <T> the type of input arguments to the merge function
+     * @return a merge function which always returns its first argument
+     * @see #lastWinsMerger()
+     * @see #throwingMerger()
+     */
+    public static <T> BinaryOperator<T> firstWinsMerger() {
+        return (u,v) -> u;
+    }
+
+    /**
+     * Returns a merge function, suitable for use in
+     * {@link Map#merge(Object, Object, BiFunction) Map.merge()} or
+     * {@link #toMap(Function, Function, BinaryOperator) toMap()},
+     * which implements a "last wins" policy.
+     *
+     * @param <T> the type of input arguments to the merge function
+     * @return a merge function which always returns its second argument
+     * @see #firstWinsMerger()
+     * @see #throwingMerger()
+     */
+    public static <T> BinaryOperator<T> lastWinsMerger() {
+        return (u,v) -> v;
+    }
+
+    /**
+     * Simple implementation class for {@code Collector}.
+     *
+     * @param <T> the type of elements to be collected
+     * @param <R> the type of the result
+     */
+    private static final class CollectorImpl<T, R> implements Collector<T,R> {
+        private final Supplier<R> resultSupplier;
+        private final BiFunction<R, T, R> accumulator;
+        private final BinaryOperator<R> combiner;
+        private final Set<Characteristics> characteristics;
+
+        CollectorImpl(Supplier<R> resultSupplier,
+                      BiFunction<R, T, R> accumulator,
+                      BinaryOperator<R> combiner,
+                      Set<Characteristics> characteristics) {
+            this.resultSupplier = resultSupplier;
+            this.accumulator = accumulator;
+            this.combiner = combiner;
+            this.characteristics = characteristics;
+        }
+
+        CollectorImpl(Supplier<R> resultSupplier,
+                      BiFunction<R, T, R> accumulator,
+                      BinaryOperator<R> combiner) {
+            this(resultSupplier, accumulator, combiner, Collections.emptySet());
+        }
+
+        @Override
+        public BiFunction<R, T, R> accumulator() {
+            return accumulator;
+        }
+
+        @Override
+        public Supplier<R> resultSupplier() {
+            return resultSupplier;
+        }
+
+        @Override
+        public BinaryOperator<R> combiner() {
+            return combiner;
+        }
+
+        @Override
+        public Set<Characteristics> characteristics() {
+            return characteristics;
+        }
+    }
+
+    /**
+     * Returns a {@code Collector} that accumulates the input elements into a
+     * new {@code Collection}, in encounter order.  The {@code Collection} is
+     * created by the provided factory.
+     *
+     * @param <T> the type of the input elements
+     * @param <C> the type of the resulting {@code Collection}
+     * @param collectionFactory a {@code Supplier} which returns a new, empty
+     * {@code Collection} of the appropriate type
+     * @return a {@code Collector} which collects all the input elements into a
+     * {@code Collection}, in encounter order
+     */
+    public static <T, C extends Collection<T>>
+    Collector<T, C> toCollection(Supplier<C> collectionFactory) {
+        return new CollectorImpl<>(collectionFactory,
+                                   (r, t) -> { r.add(t); return r; },
+                                   (r1, r2) -> { r1.addAll(r2); return r1; },
+                                   CH_STRICT);
+    }
+
+    /**
+     * Returns a {@code Collector} that accumulates the input elements into a
+     * new {@code List}. There are no guarantees on the type, mutability,
+     * serializability, or thread-safety of the {@code List} returned.
+     *
+     * @param <T> the type of the input elements
+     * @return a {@code Collector} which collects all the input elements into a
+     * {@code List}, in encounter order
+     */
+    public static <T>
+    Collector<T, List<T>> toList() {
+        BiFunction<List<T>, T, List<T>> accumulator = (list, t) -> {
+            switch (list.size()) {
+                case 0:
+                    return Collections.singletonList(t);
+                case 1:
+                    List<T> newList = new ArrayList<>();
+                    newList.add(list.get(0));
+                    newList.add(t);
+                    return newList;
+                default:
+                    list.add(t);
+                    return list;
+            }
+        };
+        BinaryOperator<List<T>> combiner = (left, right) -> {
+            switch (left.size()) {
+                case 0:
+                    return right;
+                case 1:
+                    List<T> newList = new ArrayList<>(left.size() + right.size());
+                    newList.addAll(left);
+                    newList.addAll(right);
+                    return newList;
+                default:
+                    left.addAll(right);
+                    return left;
+            }
+        };
+        return new CollectorImpl<>(Collections::emptyList, accumulator, combiner);
+    }
+
+    /**
+     * Returns a {@code Collector} that accumulates the input elements into a
+     * new {@code Set}. There are no guarantees on the type, mutability,
+     * serializability, or thread-safety of the {@code Set} returned.
+     *
+     * <p>This is an {@link Collector.Characteristics#UNORDERED unordered}
+     * Collector.
+     *
+     * @param <T> the type of the input elements
+     * @return a {@code Collector} which collects all the input elements into a
+     * {@code Set}
+     */
+    public static <T>
+    Collector<T, Set<T>> toSet() {
+        return new CollectorImpl<>((Supplier<Set<T>>) HashSet::new,
+                                   (r, t) -> { r.add(t); return r; },
+                                   (r1, r2) -> { r1.addAll(r2); return r1; },
+                                   CH_STRICT_UNORDERED);
+    }
+
+    /**
+     * Returns a {@code Collector} that concatenates the input elements into a
+     * new {@link StringBuilder}.
+     *
+     * @return a {@code Collector} which collects String elements into a
+     * {@code StringBuilder}, in encounter order
+     */
+    public static Collector<String, StringBuilder> toStringBuilder() {
+        return new CollectorImpl<>(StringBuilder::new,
+                                   (r, t) -> { r.append(t); return r; },
+                                   (r1, r2) -> { r1.append(r2); return r1; },
+                                   CH_STRICT);
+    }
+
+    /**
+     * Returns a {@code Collector} that concatenates the input elements into a
+     * new {@link StringJoiner}, using the specified delimiter.
+     *
+     * @param delimiter the delimiter to be used between each element
+     * @return A {@code Collector} which collects String elements into a
+     * {@code StringJoiner}, in encounter order
+     */
+    public static Collector<CharSequence, StringJoiner> toStringJoiner(CharSequence delimiter) {
+        BinaryOperator<StringJoiner> merger = (sj, other) -> {
+            if (other.length() > 0)
+                sj.add(other.toString());
+            return sj;
+        };
+        return new CollectorImpl<>(() -> new StringJoiner(delimiter),
+                                   (r, t) -> { r.add(t); return r; },
+                                   merger, CH_STRICT);
+    }
+
+    /**
+     * {@code BinaryOperator<Map>} that merges the contents of its right
+     * argument into its left argument, using the provided merge function to
+     * handle duplicate keys.
+     *
+     * @param <K> type of the map keys
+     * @param <V> type of the map values
+     * @param <M> type of the map
+     * @param mergeFunction A merge function suitable for
+     * {@link Map#merge(Object, Object, BiFunction) Map.merge()}
+     * @return a merge function for two maps
+     */
+    private static <K, V, M extends Map<K,V>>
+    BinaryOperator<M> mapMerger(BinaryOperator<V> mergeFunction) {
+        return (m1, m2) -> {
+            for (Map.Entry<K,V> e : m2.entrySet())
+                m1.merge(e.getKey(), e.getValue(), mergeFunction);
+            return m1;
+        };
+    }
+
+    /**
+     * Adapts a {@code Collector<U,R>} to a {@code Collector<T,R>} by applying
+     * a mapping function to each input element before accumulation.
+     *
+     * @apiNote
+     * The {@code mapping()} collectors are most useful when used in a
+     * multi-level reduction, downstream of {@code groupingBy} or
+     * {@code partitioningBy}.  For example, given a stream of
+     * {@code Person}, to accumulate the set of last names in each city:
+     * <pre>{@code
+     *     Map<City, Set<String>> lastNamesByCity
+     *         = people.stream().collect(groupingBy(Person::getCity,
+     *                                              mapping(Person::getLastName, toSet())));
+     * }</pre>
+     *
+     * @param <T> the type of the input elements
+     * @param <U> type of elements accepted by downstream collector
+     * @param <R> result type of collector
+     * @param mapper a function to be applied to the input elements
+     * @param downstream a collector which will accept mapped values
+     * @return a collector which applies the mapping function to the input
+     * elements and provides the mapped results to the downstream collector
+     */
+    public static <T, U, R> Collector<T, R>
+    mapping(Function<? super T, ? extends U> mapper, Collector<? super U, R> downstream) {
+        BiFunction<R, ? super U, R> downstreamAccumulator = downstream.accumulator();
+        return new CollectorImpl<>(downstream.resultSupplier(),
+                                   (r, t) -> downstreamAccumulator.apply(r, mapper.apply(t)),
+                                   downstream.combiner(), downstream.characteristics());
+    }
+
+    /**
+     * Returns a {@code Collector<T, Long>} that counts the number of input
+     * elements.
+     *
+     * @implSpec
+     * This produces a result equivalent to:
+     * <pre>{@code
+     *     reducing(0L, e -> 1L, Long::sum)
+     * }</pre>
+     *
+     * @param <T> the type of the input elements
+     * @return a {@code Collector} that counts the input elements
+     */
+    public static <T> Collector<T, Long>
+    counting() {
+        return reducing(0L, e -> 1L, Long::sum);
+    }
+
+    /**
+     * Returns a {@code Collector<T, T>} that produces the minimal element
+     * according to a given {@code Comparator}.
+     *
+     * @implSpec
+     * This produces a result equivalent to:
+     * <pre>{@code
+     *     reducing(Comparators.lesserOf(comparator))
+     * }</pre>
+     *
+     * @param <T> the type of the input elements
+     * @param comparator a {@code Comparator} for comparing elements
+     * @return a {@code Collector} that produces the minimal value
+     */
+    public static <T> Collector<T, T>
+    minBy(Comparator<? super T> comparator) {
+        return reducing(Comparators.lesserOf(comparator));
+    }
+
+    /**
+     * Returns a {@code Collector<T, T>} that produces the maximal element
+     * according to a given {@code Comparator}.
+     *
+     * @implSpec
+     * This produces a result equivalent to:
+     * <pre>{@code
+     *     reducing(Comparators.greaterOf(comparator))
+     * }</pre>
+     *
+     * @param <T> the type of the input elements
+     * @param comparator a {@code Comparator} for comparing elements
+     * @return a {@code Collector} that produces the maximal value
+     */
+    public static <T> Collector<T, T>
+    maxBy(Comparator<? super T> comparator) {
+        return reducing(Comparators.greaterOf(comparator));
+    }
+
+    /**
+     * Returns a {@code Collector<T, Long>} that produces the sum of a
+     * long-valued function applied to the input element.
+     *
+     * @implSpec
+     * This produces a result equivalent to:
+     * <pre>{@code
+     *     reducing(0L, mapper, Long::sum)
+     * }</pre>
+     *
+     * @param <T> the type of the input elements
+     * @param mapper a function extracting the property to be summed
+     * @return a {@code Collector} that produces the sum of a derived property
+     */
+    public static <T> Collector<T, Long>
+    sumBy(Function<? super T, Long> mapper) {
+        return reducing(0L, mapper, Long::sum);
+    }
+
+    /**
+     * Returns a {@code Collector<T,T>} which performs a reduction of its
+     * input elements under a specified {@code BinaryOperator}.
+     *
+     * @apiNote
+     * The {@code reducing()} collectors are most useful when used in a
+     * multi-level reduction, downstream of {@code groupingBy} or
+     * {@code partitioningBy}.  To perform a simple reduction on a stream,
+     * use {@link Stream#reduce(BinaryOperator)} instead.
+     *
+     * @param <T> element type for the input and output of the reduction
+     * @param identity the identity value for the reduction (also, the value
+     *                 that is returned when there are no input elements)
+     * @param op a {@code BinaryOperator<T>} used to reduce the input elements
+     * @return a {@code Collector} which implements the reduction operation
+     *
+     * @see #reducing(BinaryOperator)
+     * @see #reducing(Object, Function, BinaryOperator)
+     */
+    public static <T> Collector<T, T>
+    reducing(T identity, BinaryOperator<T> op) {
+        return new CollectorImpl<>(() -> identity, (r, t) -> (r == null ? t : op.apply(r, t)), op);
+    }
+
+    /**
+     * Returns a {@code Collector<T,T>} which performs a reduction of its
+     * input elements under a specified {@code BinaryOperator}.
+     *
+     * @apiNote
+     * The {@code reducing()} collectors are most useful when used in a
+     * multi-level reduction, downstream of {@code groupingBy} or
+     * {@code partitioningBy}.  To perform a simple reduction on a stream,
+     * use {@link Stream#reduce(BinaryOperator)} instead.
+     *
+     * <p>For example, given a stream of {@code Person}, to calculate tallest
+     * person in each city:
+     * <pre>{@code
+     *     Comparator<Person> byHeight = Comparators.comparing(Person::getHeight);
+     *     BinaryOperator<Person> tallerOf = Comparators.greaterOf(byHeight);
+     *     Map<City, Person> tallestByCity
+     *         = people.stream().collect(groupingBy(Person::getCity, reducing(tallerOf)));
+     * }</pre>
+     *
+     * @implSpec
+     * The default implementation is equivalent to:
+     * <pre>{@code
+     *     reducing(null, op);
+     * }</pre>
+     *
+     * @param <T> element type for the input and output of the reduction
+     * @param op a {@code BinaryOperator<T>} used to reduce the input elements
+     * @return a {@code Collector} which implements the reduction operation
+     *
+     * @see #reducing(Object, BinaryOperator)
+     * @see #reducing(Object, Function, BinaryOperator)
+     */
+    public static <T> Collector<T, T>
+    reducing(BinaryOperator<T> op) {
+        return reducing(null, op);
+    }
+
+    /**
+     * Returns a {@code Collector<T,U>} which performs a reduction of its
+     * input elements under a specified mapping function and
+     * {@code BinaryOperator}. This is a generalization of
+     * {@link #reducing(Object, BinaryOperator)} which allows a transformation
+     * of the elements before reduction.
+     *
+     * @apiNote
+     * The {@code reducing()} collectors are most useful when used in a
+     * multi-level reduction, downstream of {@code groupingBy} or
+     * {@code partitioningBy}.  To perform a simple reduction on a stream,
+     * use {@link Stream#reduce(BinaryOperator)} instead.
+     *
+     * <p>For example, given a stream of {@code Person}, to calculate the longest
+     * last name of residents in each city:
+     * <pre>{@code
+     *     Comparator<String> byLength = Comparators.comparing(String::length);
+     *     BinaryOperator<String> longerOf = Comparators.greaterOf(byLength);
+     *     Map<City, String> longestLastNameByCity
+     *         = people.stream().collect(groupingBy(Person::getCity,
+     *                                              reducing(Person::getLastName, longerOf)));
+     * }</pre>
+     *
+     * @param <T> the type of the input elements
+     * @param <U> the type of the mapped values
+     * @param identity the identity value for the reduction (also, the value
+     *                 that is returned when there are no input elements)
+     * @param mapper a mapping function to apply to each input value
+     * @param op a {@code BinaryOperator<U>} used to reduce the mapped values
+     * @return a {@code Collector} implementing the map-reduce operation
+     *
+     * @see #reducing(Object, BinaryOperator)
+     * @see #reducing(BinaryOperator)
+     */
+    public static <T, U>
+    Collector<T, U> reducing(U identity,
+                             Function<? super T, ? extends U> mapper,
+                             BinaryOperator<U> op) {
+        return new CollectorImpl<>(() -> identity,
+                                   (r, t) -> (r == null ? mapper.apply(t) : op.apply(r, mapper.apply(t))),
+                                   op);
+    }
+
+    /**
+     * Returns a {@code Collector} implementing a "group by" operation on
+     * input elements of type {@code T}, grouping elements according to a
+     * classification function.
+     *
+     * <p>The classification function maps elements to some key type {@code K}.
+     * The collector produces a {@code Map<K, List<T>>} whose keys are the
+     * values resulting from applying the classification function to the input
+     * elements, and whose corresponding values are {@code List}s containing the
+     * input elements which map to the associated key under the classification
+     * function.
+     *
+     * <p>There are no guarantees on the type, mutability, serializability, or
+     * thread-safety of the {@code Map} or {@code List} objects returned.
+     * @implSpec
+     * This produces a result similar to:
+     * <pre>{@code
+     *     groupingBy(classifier, toList());
+     * }</pre>
+     *
+     * @param <T> the type of the input elements
+     * @param <K> the type of the keys
+     * @param classifier the classifier function mapping input elements to keys
+     * @return a {@code Collector} implementing the group-by operation
+     *
+     * @see #groupingBy(Function, Collector)
+     * @see #groupingBy(Function, Supplier, Collector)
+     * @see #groupingByConcurrent(Function)
+     */
+    public static <T, K>
+    Collector<T, Map<K, List<T>>> groupingBy(Function<? super T, ? extends K> classifier) {
+        return groupingBy(classifier, HashMap::new, toList());
+    }
+
+    /**
+     * Returns a {@code Collector} implementing a cascaded "group by" operation
+     * on input elements of type {@code T}, grouping elements according to a
+     * classification function, and then performing a reduction operation on
+     * the values associated with a given key using the specified downstream
+     * {@code Collector}.
+     *
+     * <p>The classification function maps elements to some key type {@code K}.
+     * The downstream collector operates on elements of type {@code T} and
+     * produces a result of type {@code D}. The resulting collector produces a
+     * {@code Map<K, D>}.
+     *
+     * <p>There are no guarantees on the type, mutability,
+     * serializability, or thread-safety of the {@code Map} returned.
+     *
+     * <p>For example, to compute the set of last names of people in each city:
+     * <pre>{@code
+     *     Map<City, Set<String>> namesByCity
+     *         = people.stream().collect(groupingBy(Person::getCity,
+     *                                              mapping(Person::getLastName, toSet())));
+     * }</pre>
+     *
+     * @param <T> the type of the input elements
+     * @param <K> the type of the keys
+     * @param <D> the result type of the downstream reduction
+     * @param classifier a classifier function mapping input elements to keys
+     * @param downstream a {@code Collector} implementing the downstream reduction
+     * @return a {@code Collector} implementing the cascaded group-by operation
+     * @see #groupingBy(Function)
+     *
+     * @see #groupingBy(Function, Supplier, Collector)
+     * @see #groupingByConcurrent(Function, Collector)
+     */
+    public static <T, K, D>
+    Collector<T, Map<K, D>> groupingBy(Function<? super T, ? extends K> classifier,
+                                       Collector<? super T, D> downstream) {
+        return groupingBy(classifier, HashMap::new, downstream);
+    }
+
+    /**
+     * Returns a {@code Collector} implementing a cascaded "group by" operation
+     * on input elements of type {@code T}, grouping elements according to a
+     * classification function, and then performing a reduction operation on
+     * the values associated with a given key using the specified downstream
+     * {@code Collector}.  The {@code Map} produced by the Collector is created
+     * with the supplied factory function.
+     *
+     * <p>The classification function maps elements to some key type {@code K}.
+     * The downstream collector operates on elements of type {@code T} and
+     * produces a result of type {@code D}. The resulting collector produces a
+     * {@code Map<K, D>}.
+     *
+     * <p>For example, to compute the set of last names of people in each city,
+     * where the city names are sorted:
+     * <pre>{@code
+     *     Map<City, Set<String>> namesByCity
+     *         = people.stream().collect(groupingBy(Person::getCity, TreeMap::new,
+     *                                              mapping(Person::getLastName, toSet())));
+     * }</pre>
+     *
+     * @param <T> the type of the input elements
+     * @param <K> the type of the keys
+     * @param <D> the result type of the downstream reduction
+     * @param <M> the type of the resulting {@code Map}
+     * @param classifier a classifier function mapping input elements to keys
+     * @param downstream a {@code Collector} implementing the downstream reduction
+     * @param mapFactory a function which, when called, produces a new empty
+     *                   {@code Map} of the desired type
+     * @return a {@code Collector} implementing the cascaded group-by operation
+     *
+     * @see #groupingBy(Function, Collector)
+     * @see #groupingBy(Function)
+     * @see #groupingByConcurrent(Function, Supplier, Collector)
+     */
+    public static <T, K, D, M extends Map<K, D>>
+    Collector<T, M> groupingBy(Function<? super T, ? extends K> classifier,
+                               Supplier<M> mapFactory,
+                               Collector<? super T, D> downstream) {
+        Supplier<D> downstreamSupplier = downstream.resultSupplier();
+        BiFunction<D, ? super T, D> downstreamAccumulator = downstream.accumulator();
+        BiFunction<M, T, M> accumulator = (m, t) -> {
+            K key = Objects.requireNonNull(classifier.apply(t), "element cannot be mapped to a null key");
+            D oldContainer = m.computeIfAbsent(key, k -> downstreamSupplier.get());
+            D newContainer = downstreamAccumulator.apply(oldContainer, t);
+            if (newContainer != oldContainer)
+                m.put(key, newContainer);
+            return m;
+        };
+        return new CollectorImpl<>(mapFactory, accumulator, mapMerger(downstream.combiner()), CH_STRICT);
+    }
+
+    /**
+     * Returns a {@code Collector} implementing a concurrent "group by"
+     * operation on input elements of type {@code T}, grouping elements
+     * according to a classification function.
+     *
+     * <p>This is a {@link Collector.Characteristics#CONCURRENT concurrent} and
+     * {@link Collector.Characteristics#UNORDERED unordered} Collector.
+     *
+     * <p>The classification function maps elements to some key type {@code K}.
+     * The collector produces a {@code ConcurrentMap<K, List<T>>} whose keys are the
+     * values resulting from applying the classification function to the input
+     * elements, and whose corresponding values are {@code List}s containing the
+     * input elements which map to the associated key under the classification
+     * function.
+     *
+     * <p>There are no guarantees on the type, mutability, or serializability
+     * of the {@code Map} or {@code List} objects returned, or of the
+     * thread-safety of the {@code List} objects returned.
+     * @implSpec
+     * This produces a result similar to:
+     * <pre>{@code
+     *     groupingByConcurrent(classifier, toList());
+     * }</pre>
+     *
+     * @param <T> the type of the input elements
+     * @param <K> the type of the keys
+     * @param classifier a classifier function mapping input elements to keys
+     * @return a {@code Collector} implementing the group-by operation
+     *
+     * @see #groupingBy(Function)
+     * @see #groupingByConcurrent(Function, Collector)
+     * @see #groupingByConcurrent(Function, Supplier, Collector)
+     */
+    public static <T, K>
+    Collector<T, ConcurrentMap<K, List<T>>> groupingByConcurrent(Function<? super T, ? extends K> classifier) {
+        return groupingByConcurrent(classifier, ConcurrentHashMap::new, toList());
+    }
+
+    /**
+     * Returns a {@code Collector} implementing a concurrent cascaded "group by"
+     * operation on input elements of type {@code T}, grouping elements
+     * according to a classification function, and then performing a reduction
+     * operation on the values associated with a given key using the specified
+     * downstream {@code Collector}.
+     *
+     * <p>This is a {@link Collector.Characteristics#CONCURRENT concurrent} and
+     * {@link Collector.Characteristics#UNORDERED unordered} Collector.
+     *
+     * <p>The classification function maps elements to some key type {@code K}.
+     * The downstream collector operates on elements of type {@code T} and
+     * produces a result of type {@code D}. The resulting collector produces a
+     * {@code Map<K, D>}.
+     *
+     * <p>For example, to compute the set of last names of people in each city,
+     * where the city names are sorted:
+     * <pre>{@code
+     *     ConcurrentMap<City, Set<String>> namesByCity
+     *         = people.stream().collect(groupingByConcurrent(Person::getCity, TreeMap::new,
+     *                                                        mapping(Person::getLastName, toSet())));
+     * }</pre>
+     *
+     * @param <T> the type of the input elements
+     * @param <K> the type of the keys
+     * @param <D> the result type of the downstream reduction
+     * @param classifier a classifier function mapping input elements to keys
+     * @param downstream a {@code Collector} implementing the downstream reduction
+     * @return a {@code Collector} implementing the cascaded group-by operation
+     *
+     * @see #groupingBy(Function, Collector)
+     * @see #groupingByConcurrent(Function)
+     * @see #groupingByConcurrent(Function, Supplier, Collector)
+     */
+    public static <T, K, D>
+    Collector<T, ConcurrentMap<K, D>> groupingByConcurrent(Function<? super T, ? extends K> classifier,
+                                                           Collector<? super T, D> downstream) {
+        return groupingByConcurrent(classifier, ConcurrentHashMap::new, downstream);
+    }
+
+    /**
+     * Returns a concurrent {@code Collector} implementing a cascaded "group by"
+     * operation on input elements of type {@code T}, grouping elements
+     * according to a classification function, and then performing a reduction
+     * operation on the values associated with a given key using the specified
+     * downstream {@code Collector}.  The {@code ConcurrentMap} produced by the
+     * Collector is created with the supplied factory function.
+     *
+     * <p>This is a {@link Collector.Characteristics#CONCURRENT concurrent} and
+     * {@link Collector.Characteristics#UNORDERED unordered} Collector.
+     *
+     * <p>The classification function maps elements to some key type {@code K}.
+     * The downstream collector operates on elements of type {@code T} and
+     * produces a result of type {@code D}. The resulting collector produces a
+     * {@code Map<K, D>}.
+     *
+     * <p>For example, to compute the set of last names of people in each city,
+     * where the city names are sorted:
+     * <pre>{@code
+     *     ConcurrentMap<City, Set<String>> namesByCity
+     *         = people.stream().collect(groupingBy(Person::getCity, ConcurrentSkipListMap::new,
+     *                                              mapping(Person::getLastName, toSet())));
+     * }</pre>
+     *
+     *
+     * @param <T> the type of the input elements
+     * @param <K> the type of the keys
+     * @param <D> the result type of the downstream reduction
+     * @param <M> the type of the resulting {@code ConcurrentMap}
+     * @param classifier a classifier function mapping input elements to keys
+     * @param downstream a {@code Collector} implementing the downstream reduction
+     * @param mapFactory a function which, when called, produces a new empty
+     *                   {@code ConcurrentMap} of the desired type
+     * @return a {@code Collector} implementing the cascaded group-by operation
+     *
+     * @see #groupingByConcurrent(Function)
+     * @see #groupingByConcurrent(Function, Collector)
+     * @see #groupingBy(Function, Supplier, Collector)
+     */
+    public static <T, K, D, M extends ConcurrentMap<K, D>>
+    Collector<T, M> groupingByConcurrent(Function<? super T, ? extends K> classifier,
+                                         Supplier<M> mapFactory,
+                                         Collector<? super T, D> downstream) {
+        Supplier<D> downstreamSupplier = downstream.resultSupplier();
+        BiFunction<D, ? super T, D> downstreamAccumulator = downstream.accumulator();
+        BinaryOperator<M> combiner = mapMerger(downstream.combiner());
+        if (downstream.characteristics().contains(Collector.Characteristics.CONCURRENT)) {
+            BiFunction<M, T, M> accumulator = (m, t) -> {
+                K key = Objects.requireNonNull(classifier.apply(t), "element cannot be mapped to a null key");
+                downstreamAccumulator.apply(m.computeIfAbsent(key, k -> downstreamSupplier.get()), t);
+                return m;
+            };
+            return new CollectorImpl<>(mapFactory, accumulator, combiner, CH_CONCURRENT);
+        } else if (downstream.characteristics().contains(Collector.Characteristics.STRICTLY_MUTATIVE)) {
+            BiFunction<M, T, M> accumulator = (m, t) -> {
+                K key = Objects.requireNonNull(classifier.apply(t), "element cannot be mapped to a null key");
+                D resultContainer = m.computeIfAbsent(key, k -> downstreamSupplier.get());
+                synchronized (resultContainer) {
+                    downstreamAccumulator.apply(resultContainer, t);
+                }
+                return m;
+            };
+            return new CollectorImpl<>(mapFactory, accumulator, combiner, CH_CONCURRENT);
+        } else {
+            BiFunction<M, T, M> accumulator = (m, t) -> {
+                K key = Objects.requireNonNull(classifier.apply(t), "element cannot be mapped to a null key");
+                do {
+                    D oldResult = m.computeIfAbsent(key, k -> downstreamSupplier.get());
+                    if (oldResult == null) {
+                        if (m.putIfAbsent(key, downstreamAccumulator.apply(null, t)) == null)
+                            return m;
+                    } else {
+                        synchronized (oldResult) {
+                            if (m.get(key) != oldResult)
+                                continue;
+                            D newResult = downstreamAccumulator.apply(oldResult, t);
+                            if (oldResult != newResult)
+                                m.put(key, newResult);
+                            return m;
+                        }
+                    }
+                } while (true);
+            };
+            return new CollectorImpl<>(mapFactory, accumulator, combiner, CH_CONCURRENT);
+        }
+    }
+
+    /**
+     * Returns a {@code Collector} which partitions the input elements according
+     * to a {@code Predicate}, and organizes them into a
+     * {@code Map<Boolean, List<T>>}.
+     *
+     * There are no guarantees on the type, mutability,
+     * serializability, or thread-safety of the {@code Map} returned.
+     *
+     * @param <T> the type of the input elements
+     * @param predicate a predicate used for classifying input elements
+     * @return a {@code Collector} implementing the partitioning operation
+     *
+     * @see #partitioningBy(Predicate, Collector)
+     */
+    public static <T>
+    Collector<T, Map<Boolean, List<T>>> partitioningBy(Predicate<? super T> predicate) {
+        return partitioningBy(predicate, toList());
+    }
+
+    /**
+     * Returns a {@code Collector} which partitions the input elements according
+     * to a {@code Predicate}, reduces the values in each partition according to
+     * another {@code Collector}, and organizes them into a
+     * {@code Map<Boolean, D>} whose values are the result of the downstream
+     * reduction.
+     *
+     * <p>There are no guarantees on the type, mutability,
+     * serializability, or thread-safety of the {@code Map} returned.
+     *
+     * @param <T> the type of the input elements
+     * @param <D> the result type of the downstream reduction
+     * @param predicate a predicate used for classifying input elements
+     * @param downstream a {@code Collector} implementing the downstream
+     *                   reduction
+     * @return a {@code Collector} implementing the cascaded partitioning
+     *         operation
+     *
+     * @see #partitioningBy(Predicate)
+     */
+    public static <T, D>
+    Collector<T, Map<Boolean, D>> partitioningBy(Predicate<? super T> predicate,
+                                                 Collector<? super T, D> downstream) {
+        BiFunction<D, ? super T, D> downstreamAccumulator = downstream.accumulator();
+        BiFunction<Map<Boolean, D>, T, Map<Boolean, D>> accumulator = (result, t) -> {
+            Partition<D> asPartition = ((Partition<D>) result);
+            if (predicate.test(t)) {
+                D newResult = downstreamAccumulator.apply(asPartition.forTrue, t);
+                if (newResult != asPartition.forTrue)
+                    asPartition.forTrue = newResult;
+            } else {
+                D newResult = downstreamAccumulator.apply(asPartition.forFalse, t);
+                if (newResult != asPartition.forFalse)
+                    asPartition.forFalse = newResult;
+            }
+            return result;
+        };
+        return new CollectorImpl<>(() -> new Partition<>(downstream.resultSupplier().get(),
+                                                         downstream.resultSupplier().get()),
+                                   accumulator, partitionMerger(downstream.combiner()), CH_STRICT);
+    }
+
+    /**
+     * Merge function for two partitions, given a merge function for the
+     * elements.
+     */
+    private static <D> BinaryOperator<Map<Boolean, D>> partitionMerger(BinaryOperator<D> op) {
+        return (m1, m2) -> {
+            Partition<D> left = (Partition<D>) m1;
+            Partition<D> right = (Partition<D>) m2;
+            if (left.forFalse == null)
+                left.forFalse = right.forFalse;
+            else if (right.forFalse != null)
+                left.forFalse = op.apply(left.forFalse, right.forFalse);
+            if (left.forTrue == null)
+                left.forTrue = right.forTrue;
+            else if (right.forTrue != null)
+                left.forTrue = op.apply(left.forTrue, right.forTrue);
+            return left;
+        };
+    }
+
+    /**
+     * Accumulate elements into a {@code Map} whose keys and values are the
+     * result of applying mapping functions to the input elements.
+     * If the mapped keys contains duplicates (according to
+     * {@link Object#equals(Object)}), an {@code IllegalStateException} is
+     * thrown when the collection operation is performed.  If the mapped keys
+     * may have duplicates, use {@link #toMap(Function, Function, BinaryOperator)}
+     * instead.
+     *
+     * @apiNote
+     * It is common for either the key or the value to be the input elements.
+     * In this case, the utility method
+     * {@link java.util.function.Function#identity()} may be helpful.
+     * For example, the following produces a {@code Map} mapping
+     * students to their grade point average:
+     * <pre>{@code
+     *     Map<Student, Double> studentToGPA
+     *         students.stream().collect(toMap(Functions.identity(),
+     *                                         student -> computeGPA(student)));
+     * }</pre>
+     * And the following produces a {@code Map} mapping a unique identifier to
+     * students:
+     * <pre>{@code
+     *     Map<String, Student> studentIdToStudent
+     *         students.stream().collect(toMap(Student::getId,
+     *                                         Functions.identity());
+     * }</pre>
+     *
+     * @param <T> the type of the input elements
+     * @param <K> the output type of the key mapping function
+     * @param <U> the output type of the value mapping function
+     * @param keyMapper a mapping function to produce keys
+     * @param valueMapper a mapping function to produce values
+     * @return a {@code Collector} which collects elements into a {@code Map}
+     * whose keys and values are the result of applying mapping functions to
+     * the input elements
+     *
+     * @see #toMap(Function, Function, BinaryOperator)
+     * @see #toMap(Function, Function, BinaryOperator, Supplier)
+     * @see #toConcurrentMap(Function, Function)
+     */
+    public static <T, K, U>
+    Collector<T, Map<K,U>> toMap(Function<? super T, ? extends K> keyMapper,
+                                 Function<? super T, ? extends U> valueMapper) {
+        return toMap(keyMapper, valueMapper, throwingMerger(), HashMap::new);
+    }
+
+    /**
+     * Accumulate elements into a {@code Map} whose keys and values are the
+     * result of applying mapping functions to the input elements. If the mapped
+     * keys contains duplicates (according to {@link Object#equals(Object)}),
+     * the value mapping function is applied to each equal element, and the
+     * results are merged using the provided merging function.
+     *
+     * @apiNote
+     * There are multiple ways to deal with collisions between multiple elements
+     * mapping to the same key.  There are some predefined merging functions,
+     * such as {@link #throwingMerger()}, {@link #firstWinsMerger()}, and
+     * {@link #lastWinsMerger()}, that implement common policies, or you can
+     * implement custom policies easily.  For example, if you have a stream
+     * of {@code Person}, and you want to produce a "phone book" mapping name to
+     * address, but it is possible that two persons have the same name, you can
+     * do as follows to gracefully deals with these collisions, and produce a
+     * {@code Map} mapping names to a concatenated list of addresses:
+     * <pre>{@code
+     *     Map<String, String> phoneBook
+     *         people.stream().collect(toMap(Person::getName,
+     *                                       Person::getAddress,
+     *                                       (s, a) -> s + ", " + a));
+     * }</pre>
+     *
+     * @param <T> the type of the input elements
+     * @param <K> the output type of the key mapping function
+     * @param <U> the output type of the value mapping function
+     * @param keyMapper a mapping function to produce keys
+     * @param valueMapper a mapping function to produce values
+     * @param mergeFunction a merge function, used to resolve collisions between
+     *                      values associated with the same key, as supplied
+     *                      to {@link Map#merge(Object, Object, BiFunction)}
+     * @return a {@code Collector} which collects elements into a {@code Map}
+     * whose keys are the result of applying a key mapping function to the input
+     * elements, and whose values are the result of applying a value mapping
+     * function to all input elements equal to the key and combining them
+     * using the merge function
+     *
+     * @see #toMap(Function, Function)
+     * @see #toMap(Function, Function, BinaryOperator, Supplier)
+     * @see #toConcurrentMap(Function, Function, BinaryOperator)
+     */
+    public static <T, K, U>
+    Collector<T, Map<K,U>> toMap(Function<? super T, ? extends K> keyMapper,
+                                 Function<? super T, ? extends U> valueMapper,
+                                 BinaryOperator<U> mergeFunction) {
+        return toMap(keyMapper, valueMapper, mergeFunction, HashMap::new);
+    }
+
+    /**
+     * Accumulate elements into a {@code Map} whose keys and values are the
+     * result of applying mapping functions to the input elements. If the mapped
+     * keys contains duplicates (according to {@link Object#equals(Object)}),
+     * the value mapping function is applied to each equal element, and the
+     * results are merged using the provided merging function.  The {@code Map}
+     * is created by a provided supplier function.
+     *
+     * @param <T> the type of the input elements
+     * @param <K> the output type of the key mapping function
+     * @param <U> the output type of the value mapping function
+     * @param <M> the type of the resulting {@code Map}
+     * @param keyMapper a mapping function to produce keys
+     * @param valueMapper a mapping function to produce values
+     * @param mergeFunction a merge function, used to resolve collisions between
+     *                      values associated with the same key, as supplied
+     *                      to {@link Map#merge(Object, Object, BiFunction)}
+     * @param mapSupplier a function which returns a new, empty {@code Map} into
+     *                    which the results will be inserted
+     * @return a {@code Collector} which collects elements into a {@code Map}
+     * whose keys are the result of applying a key mapping function to the input
+     * elements, and whose values are the result of applying a value mapping
+     * function to all input elements equal to the key and combining them
+     * using the merge function
+     *
+     * @see #toMap(Function, Function)
+     * @see #toMap(Function, Function, BinaryOperator)
+     * @see #toConcurrentMap(Function, Function, BinaryOperator, Supplier)
+     */
+    public static <T, K, U, M extends Map<K, U>>
+    Collector<T, M> toMap(Function<? super T, ? extends K> keyMapper,
+                          Function<? super T, ? extends U> valueMapper,
+                          BinaryOperator<U> mergeFunction,
+                          Supplier<M> mapSupplier) {
+        BiFunction<M, T, M> accumulator
+                = (map, element) -> {
+                      map.merge(keyMapper.apply(element), valueMapper.apply(element), mergeFunction);
+                      return map;
+                  };
+        return new CollectorImpl<>(mapSupplier, accumulator, mapMerger(mergeFunction), CH_STRICT);
+    }
+
+    /**
+     * Accumulate elements into a {@code ConcurrentMap} whose keys and values
+     * are the result of applying mapping functions to the input elements.
+     * If the mapped keys contains duplicates (according to
+     * {@link Object#equals(Object)}), an {@code IllegalStateException} is
+     * thrown when the collection operation is performed.  If the mapped keys
+     * may have duplicates, use
+     * {@link #toConcurrentMap(Function, Function, BinaryOperator)} instead.
+     *
+     * @apiNote
+     * It is common for either the key or the value to be the input elements.
+     * In this case, the utility method
+     * {@link java.util.function.Function#identity()} may be helpful.
+     * For example, the following produces a {@code Map} mapping
+     * students to their grade point average:
+     * <pre>{@code
+     *     Map<Student, Double> studentToGPA
+     *         students.stream().collect(toMap(Functions.identity(),
+     *                                         student -> computeGPA(student)));
+     * }</pre>
+     * And the following produces a {@code Map} mapping a unique identifier to
+     * students:
+     * <pre>{@code
+     *     Map<String, Student> studentIdToStudent
+     *         students.stream().collect(toConcurrentMap(Student::getId,
+     *                                                   Functions.identity());
+     * }</pre>
+     *
+     * <p>This is a {@link Collector.Characteristics#CONCURRENT concurrent} and
+     * {@link Collector.Characteristics#UNORDERED unordered} Collector.
+     *
+     * @param <T> the type of the input elements
+     * @param <K> the output type of the key mapping function
+     * @param <U> the output type of the value mapping function
+     * @param keyMapper the mapping function to produce keys
+     * @param valueMapper the mapping function to produce values
+     * @return a concurrent {@code Collector} which collects elements into a
+     * {@code ConcurrentMap} whose keys are the result of applying a key mapping
+     * function to the input elements, and whose values are the result of
+     * applying a value mapping function to the input elements
+     *
+     * @see #toMap(Function, Function)
+     * @see #toConcurrentMap(Function, Function, BinaryOperator)
+     * @see #toConcurrentMap(Function, Function, BinaryOperator, Supplier)
+     */
+    public static <T, K, U>
+    Collector<T, ConcurrentMap<K,U>> toConcurrentMap(Function<? super T, ? extends K> keyMapper,
+                                                     Function<? super T, ? extends U> valueMapper) {
+        return toConcurrentMap(keyMapper, valueMapper, throwingMerger(), ConcurrentHashMap::new);
+    }
+
+    /**
+     * Accumulate elements into a {@code ConcurrentMap} whose keys and values
+     * are the result of applying mapping functions to the input elements. If
+     * the mapped keys contains duplicates (according to {@link Object#equals(Object)}),
+     * the value mapping function is applied to each equal element, and the
+     * results are merged using the provided merging function.
+     *
+     * @apiNote
+     * There are multiple ways to deal with collisions between multiple elements
+     * mapping to the same key.  There are some predefined merging functions,
+     * such as {@link #throwingMerger()}, {@link #firstWinsMerger()}, and
+     * {@link #lastWinsMerger()}, that implement common policies, or you can
+     * implement custom policies easily.  For example, if you have a stream
+     * of {@code Person}, and you want to produce a "phone book" mapping name to
+     * address, but it is possible that two persons have the same name, you can
+     * do as follows to gracefully deals with these collisions, and produce a
+     * {@code Map} mapping names to a concatenated list of addresses:
+     * <pre>{@code
+     *     Map<String, String> phoneBook
+     *         people.stream().collect(toConcurrentMap(Person::getName,
+     *                                                 Person::getAddress,
+     *                                                 (s, a) -> s + ", " + a));
+     * }</pre>
+     *
+     * <p>This is a {@link Collector.Characteristics#CONCURRENT concurrent} and
+     * {@link Collector.Characteristics#UNORDERED unordered} Collector.
+     *
+     * @param <T> the type of the input elements
+     * @param <K> the output type of the key mapping function
+     * @param <U> the output type of the value mapping function
+     * @param keyMapper a mapping function to produce keys
+     * @param valueMapper a mapping function to produce values
+     * @param mergeFunction a merge function, used to resolve collisions between
+     *                      values associated with the same key, as supplied
+     *                      to {@link Map#merge(Object, Object, BiFunction)}
+     * @return a concurrent {@code Collector} which collects elements into a
+     * {@code ConcurrentMap} whose keys are the result of applying a key mapping
+     * function to the input elements, and whose values are the result of
+     * applying a value mapping function to all input elements equal to the key
+     * and combining them using the merge function
+     *
+     * @see #toConcurrentMap(Function, Function)
+     * @see #toConcurrentMap(Function, Function, BinaryOperator, Supplier)
+     * @see #toMap(Function, Function, BinaryOperator)
+     */
+    public static <T, K, U>
+    Collector<T, ConcurrentMap<K,U>> toConcurrentMap(Function<? super T, ? extends K> keyMapper,
+                                                     Function<? super T, ? extends U> valueMapper,
+                                                     BinaryOperator<U> mergeFunction) {
+        return toConcurrentMap(keyMapper, valueMapper, mergeFunction, ConcurrentHashMap::new);
+    }
+
+    /**
+     * Accumulate elements into a {@code ConcurrentMap} whose keys and values
+     * are the result of applying mapping functions to the input elements. If
+     * the mapped keys contains duplicates (according to {@link Object#equals(Object)}),
+     * the value mapping function is applied to each equal element, and the
+     * results are merged using the provided merging function.  The
+     * {@code ConcurrentMap} is created by a provided supplier function.
+     *
+     * <p>This is a {@link Collector.Characteristics#CONCURRENT concurrent} and
+     * {@link Collector.Characteristics#UNORDERED unordered} Collector.
+     *
+     * @param <T> the type of the input elements
+     * @param <K> the output type of the key mapping function
+     * @param <U> the output type of the value mapping function
+     * @param <M> the type of the resulting {@code ConcurrentMap}
+     * @param keyMapper a mapping function to produce keys
+     * @param valueMapper a mapping function to produce values
+     * @param mergeFunction a merge function, used to resolve collisions between
+     *                      values associated with the same key, as supplied
+     *                      to {@link Map#merge(Object, Object, BiFunction)}
+     * @param mapSupplier a function which returns a new, empty {@code Map} into
+     *                    which the results will be inserted
+     * @return a concurrent {@code Collector} which collects elements into a
+     * {@code ConcurrentMap} whose keys are the result of applying a key mapping
+     * function to the input elements, and whose values are the result of
+     * applying a value mapping function to all input elements equal to the key
+     * and combining them using the merge function
+     *
+     * @see #toConcurrentMap(Function, Function)
+     * @see #toConcurrentMap(Function, Function, BinaryOperator)
+     * @see #toMap(Function, Function, BinaryOperator, Supplier)
+     */
+    public static <T, K, U, M extends ConcurrentMap<K, U>>
+    Collector<T, M> toConcurrentMap(Function<? super T, ? extends K> keyMapper,
+                                    Function<? super T, ? extends U> valueMapper,
+                                    BinaryOperator<U> mergeFunction,
+                                    Supplier<M> mapSupplier) {
+        BiFunction<M, T, M> accumulator = (map, element) -> {
+            map.merge(keyMapper.apply(element), valueMapper.apply(element), mergeFunction);
+            return map;
+        };
+        return new CollectorImpl<>(mapSupplier, accumulator, mapMerger(mergeFunction), CH_CONCURRENT);
+    }
+
+    /**
+     * Returns a {@code Collector} which applies an {@code int}-producing
+     * mapping function to each input element, and returns summary statistics
+     * for the resulting values.
+     *
+     * @param <T> the type of the input elements
+     * @param mapper a mapping function to apply to each element
+     * @return a {@code Collector} implementing the summary-statistics reduction
+     *
+     * @see #toDoubleSummaryStatistics(ToDoubleFunction)
+     * @see #toLongSummaryStatistics(ToLongFunction)
+     */
+    public static <T>
+    Collector<T, IntSummaryStatistics> toIntSummaryStatistics(ToIntFunction<? super T> mapper) {
+        return new CollectorImpl<>(IntSummaryStatistics::new,
+                                   (r, t) -> { r.accept(mapper.applyAsInt(t)); return r; },
+                                   (l, r) -> { l.combine(r); return l; }, CH_STRICT);
+    }
+
+    /**
+     * Returns a {@code Collector} which applies an {@code long}-producing
+     * mapping function to each input element, and returns summary statistics
+     * for the resulting values.
+     *
+     * @param <T> the type of the input elements
+     * @param mapper the mapping function to apply to each element
+     * @return a {@code Collector} implementing the summary-statistics reduction
+     *
+     * @see #toDoubleSummaryStatistics(ToDoubleFunction)
+     * @see #toIntSummaryStatistics(ToIntFunction)
+     */
+    public static <T>
+    Collector<T, LongSummaryStatistics> toLongSummaryStatistics(ToLongFunction<? super T> mapper) {
+        return new CollectorImpl<>(LongSummaryStatistics::new,
+                                   (r, t) -> { r.accept(mapper.applyAsLong(t)); return r; },
+                                   (l, r) -> { l.combine(r); return l; }, CH_STRICT);
+    }
+
+    /**
+     * Returns a {@code Collector} which applies an {@code double}-producing
+     * mapping function to each input element, and returns summary statistics
+     * for the resulting values.
+     *
+     * @param <T> the type of the input elements
+     * @param mapper a mapping function to apply to each element
+     * @return a {@code Collector} implementing the summary-statistics reduction
+     *
+     * @see #toLongSummaryStatistics(ToLongFunction)
+     * @see #toIntSummaryStatistics(ToIntFunction)
+     */
+    public static <T>
+    Collector<T, DoubleSummaryStatistics> toDoubleSummaryStatistics(ToDoubleFunction<? super T> mapper) {
+        return new CollectorImpl<>(DoubleSummaryStatistics::new,
+                                   (r, t) -> { r.accept(mapper.applyAsDouble(t)); return r; },
+                                   (l, r) -> { l.combine(r); return l; }, CH_STRICT);
+    }
+
+    /**
+     * Implementation class used by partitioningBy.
+     */
+    private static final class Partition<T>
+            extends AbstractMap<Boolean, T>
+            implements Map<Boolean, T> {
+        T forTrue;
+        T forFalse;
+
+        Partition(T forTrue, T forFalse) {
+            this.forTrue = forTrue;
+            this.forFalse = forFalse;
+        }
+
+        @Override
+        public Set<Map.Entry<Boolean, T>> entrySet() {
+            return new AbstractSet<Map.Entry<Boolean, T>>() {
+                @Override
+                public Iterator<Map.Entry<Boolean, T>> iterator() {
+
+                    return new Iterator<Map.Entry<Boolean, T>>() {
+                        int state = 0;
+
+                        @Override
+                        public boolean hasNext() {
+                            return state < 2;
+                        }
+
+                        @Override
+                        public Map.Entry<Boolean, T> next() {
+                            if (state >= 2)
+                                throw new NoSuchElementException();
+                            return (state++ == 0)
+                                   ? new SimpleImmutableEntry<>(false, forFalse)
+                                   : new SimpleImmutableEntry<>(true, forTrue);
+                        }
+                    };
+                }
+
+                @Override
+                public int size() {
+                    return 2;
+                }
+            };
+        }
+    }
+}
--- a/src/share/classes/java/util/stream/DoubleStream.java	Tue Apr 30 12:31:51 2013 -0700
+++ b/src/share/classes/java/util/stream/DoubleStream.java	Tue Apr 30 12:32:49 2013 -0700
@@ -24,15 +24,19 @@
  */
 package java.util.stream;
 
+import java.util.Arrays;
 import java.util.DoubleSummaryStatistics;
+import java.util.Objects;
 import java.util.OptionalDouble;
 import java.util.PrimitiveIterator;
 import java.util.Spliterator;
+import java.util.Spliterators;
 import java.util.function.BiConsumer;
 import java.util.function.DoubleBinaryOperator;
 import java.util.function.DoubleConsumer;
 import java.util.function.DoubleFunction;
 import java.util.function.DoublePredicate;
+import java.util.function.DoubleSupplier;
 import java.util.function.DoubleToIntFunction;
 import java.util.function.DoubleToLongFunction;
 import java.util.function.DoubleUnaryOperator;
@@ -649,4 +653,175 @@
 
     @Override
     Spliterator.OfDouble spliterator();
+
+
+    // Static factories
+
+    /**
+     * Returns a builder for a {@code DoubleStream}.
+     *
+     * @return a stream builder
+     */
+    public static StreamBuilder.OfDouble builder() {
+        return new Streams.DoubleStreamBuilderImpl();
+    }
+
+    /**
+     * Returns an empty sequential {@code DoubleStream}.
+     *
+     * @return an empty sequential stream
+     */
+    public static DoubleStream empty() {
+        return StreamSupport.doubleStream(Spliterators.emptyDoubleSpliterator());
+    }
+
+    /**
+     * Returns a sequential {@code DoubleStream} containing a single element.
+     *
+     * @param t the single element
+     * @return a singleton sequential stream
+     */
+    public static DoubleStream of(double t) {
+        return StreamSupport.doubleStream(new Streams.DoubleStreamBuilderImpl(t));
+    }
+
+    /**
+     * Returns a sequential stream whose elements are the specified values.
+     *
+     * @param values the elements of the new stream
+     * @return the new stream
+     */
+    public static DoubleStream of(double... values) {
+        return Arrays.stream(values);
+    }
+
+    /**
+     * Returns an infinite sequential {@code DoubleStream} produced by iterative
+     * application of a function {@code f} to an initial element {@code seed},
+     * producing a {@code Stream} consisting of {@code seed}, {@code f(seed)},
+     * {@code f(f(seed))}, etc.
+     *
+     * <p>The first element (position {@code 0}) in the {@code DoubleStream}
+     * will be the provided {@code seed}.  For {@code n > 0}, the element at
+     * position {@code n}, will be the result of applying the function {@code f}
+     *  to the element at position {@code n - 1}.
+     *
+     * @param seed the initial element
+     * @param f a function to be applied to to the previous element to produce
+     *          a new element
+     * @return a new sequential {@code DoubleStream}
+     */
+    public static DoubleStream iterate(final double seed, final DoubleUnaryOperator f) {
+        Objects.requireNonNull(f);
+        final PrimitiveIterator.OfDouble iterator = new PrimitiveIterator.OfDouble() {
+            double t = seed;
+
+            @Override
+            public boolean hasNext() {
+                return true;
+            }
+
+            @Override
+            public double nextDouble() {
+                double v = t;
+                t = f.applyAsDouble(t);
+                return v;
+            }
+        };
+        return StreamSupport.doubleStream(Spliterators.spliteratorUnknownSize(
+                iterator,
+                Spliterator.ORDERED | Spliterator.IMMUTABLE | Spliterator.NONNULL));
+    }
+
+    /**
+     * Returns a sequential {@code DoubleStream} where each element is
+     * generated by an {@code DoubleSupplier}.  This is suitable for generating
+     * constant streams, streams of random elements, etc.
+     *
+     * @param s the {@code DoubleSupplier} for generated elements
+     * @return a new sequential {@code DoubleStream}
+     */
+    public static DoubleStream generate(DoubleSupplier s) {
+        Objects.requireNonNull(s);
+        return StreamSupport.doubleStream(Spliterators.spliteratorUnknownSize(
+                new PrimitiveIterator.OfDouble() {
+                    @Override
+                    public boolean hasNext() { return true; }
+
+                    @Override
+                    public double nextDouble() { return s.getAsDouble(); }
+                },
+                Spliterator.ORDERED | Spliterator.IMMUTABLE | Spliterator.NONNULL));
+    }
+
+    /**
+     * Returns a sequential {@code DoubleStream} from {@code startInclusive} (inclusive)
+     * to {@code endExclusive} (exclusive) by an incremental step of 1.0.
+     *
+     * @implSpec
+     * The implementation behaves as if:
+     * <pre>{@code
+     *     doubleRange(startInclusive, endExclusive, 1.0);
+     * }</pre>
+     *
+     * @param startInclusive the (inclusive) initial value
+     * @param endExclusive the exclusive upper bound
+     * @return a sequential {@code DoubleStream} for the range of {@code double}
+     *         elements
+     */
+    public static DoubleStream range(double startInclusive, double endExclusive) {
+        return range(startInclusive, endExclusive, 1.0);
+    }
+
+    /**
+     * Returns a sequential {@code DoubleStream} from {@code startInclusive}
+     * (inclusive) to {@code endExclusive} (exclusive) by {@code step}. If
+     * {@code startInclusive} is greater than or equal to {@code
+     * endExclusive}, an empty stream is returned.
+     *
+     * An equivalent sequence of increasing values can be produced
+     * sequentially using a {@code for} loop as follows:
+     * <pre>{@code
+     *     long size = (long) Math.ceil((startInclusive - endExclusive) / step);
+     *     long i = 0
+     *     for (double v = startInclusive; i < size; i++, v = startInclusive + step * i) {
+     *         ...
+     *     }
+     * }</pre>
+     *
+     * @param startInclusive the (inclusive) initial value
+     * @param endExclusive the exclusive upper bound
+     * @param step the difference between consecutive values
+     * @return a sequential {@code DoubleStream} for tne range of {@code double}
+     *         elements
+     * @throws IllegalArgumentException if {@code step} is less than or equal to
+     *         0. is {@code NaN}, or the count of elements in the range would be
+     *         greater than {@code Long.MAX_VALUE}
+     */
+    public static DoubleStream range(double startInclusive, double endExclusive, double step) {
+        // @@@ Need to check for ranges that may not produce distinct values
+        //     such as when the step is very small
+        //     Also clarify the size of the range which may produce more or less
+        //     than expected
+        if (step <= 0 || Double.isNaN(step)) {
+            throw new IllegalArgumentException(String.format("Illegal step: %f", step));
+        } else {
+            double range = endExclusive - startInclusive;
+            if (range <= 0) {
+                return empty();
+            }
+            double size = Math.ceil((endExclusive - startInclusive) / step);
+            if (Double.isNaN(size)) {
+                throw new IllegalArgumentException(
+                        String.format("Illegal range: %f size is NaN", size));
+            } else if (size > Long.MAX_VALUE) {
+                throw new IllegalArgumentException(
+                        String.format("Illegal range: size %f > Long.MAX_VALUE", size));
+            } else {
+                return StreamSupport.doubleStream(
+                        new Streams.RangeDoubleSpliterator(
+                                startInclusive, endExclusive, step, 0, (long) size));
+            }
+        }
+    }
 }
--- a/src/share/classes/java/util/stream/IntStream.java	Tue Apr 30 12:31:51 2013 -0700
+++ b/src/share/classes/java/util/stream/IntStream.java	Tue Apr 30 12:32:49 2013 -0700
@@ -24,17 +24,21 @@
  */
 package java.util.stream;
 
+import java.util.Arrays;
 import java.util.IntSummaryStatistics;
+import java.util.Objects;
 import java.util.OptionalDouble;
 import java.util.OptionalInt;
 import java.util.PrimitiveIterator;
 import java.util.Spliterator;
+import java.util.Spliterators;
 import java.util.function.BiConsumer;
 import java.util.function.Function;
 import java.util.function.IntBinaryOperator;
 import java.util.function.IntConsumer;
 import java.util.function.IntFunction;
 import java.util.function.IntPredicate;
+import java.util.function.IntSupplier;
 import java.util.function.IntToDoubleFunction;
 import java.util.function.IntToLongFunction;
 import java.util.function.IntUnaryOperator;
@@ -652,4 +656,153 @@
 
     @Override
     Spliterator.OfInt spliterator();
+
+    // Static factories
+
+    /**
+     * Returns a builder for an {@code IntStream}.
+     *
+     * @return a stream builder
+     */
+    public static StreamBuilder.OfInt builder() {
+        return new Streams.IntStreamBuilderImpl();
+    }
+
+    /**
+     * Returns an empty sequential {@code IntStream}.
+     *
+     * @return an empty sequential stream
+     */
+    public static IntStream empty() {
+        return StreamSupport.intStream(Spliterators.emptyIntSpliterator());
+    }
+
+    /**
+     * Returns a sequential {@code IntStream} containing a single element.
+     *
+     * @param t the single element
+     * @return a singleton sequential stream
+     */
+    public static IntStream of(int t) {
+        return StreamSupport.intStream(new Streams.IntStreamBuilderImpl(t));
+    }
+
+    /**
+     * Returns a sequential stream whose elements are the specified values.
+     *
+     * @param values the elements of the new stream
+     * @return the new stream
+     */
+    public static IntStream of(int... values) {
+        return Arrays.stream(values);
+    }
+
+    /**
+     * Returns an infinite sequential {@code IntStream} produced by iterative
+     * application of a function {@code f} to an initial element {@code seed},
+     * producing a {@code Stream} consisting of {@code seed}, {@code f(seed)},
+     * {@code f(f(seed))}, etc.
+     *
+     * <p>The first element (position {@code 0}) in the {@code IntStream} will be
+     * the provided {@code seed}.  For {@code n > 0}, the element at position
+     * {@code n}, will be the result of applying the function {@code f} to the
+     * element at position {@code n - 1}.
+     *
+     * @param seed the initial element
+     * @param f a function to be applied to to the previous element to produce
+     *          a new element
+     * @return A new sequential {@code IntStream}
+     */
+    public static IntStream iterate(final int seed, final IntUnaryOperator f) {
+        Objects.requireNonNull(f);
+        final PrimitiveIterator.OfInt iterator = new PrimitiveIterator.OfInt() {
+            int t = seed;
+
+            @Override
+            public boolean hasNext() {
+                return true;
+            }
+
+            @Override
+            public int nextInt() {
+                int v = t;
+                t = f.applyAsInt(t);
+                return v;
+            }
+        };
+        return StreamSupport.intStream(Spliterators.spliteratorUnknownSize(
+                iterator,
+                Spliterator.ORDERED | Spliterator.IMMUTABLE | Spliterator.NONNULL));
+    }
+
+    /**
+     * Returns a sequential {@code IntStream} where each element is
+     * generated by an {@code IntSupplier}.  This is suitable for generating
+     * constant streams, streams of random elements, etc.
+     *
+     * @param s the {@code IntSupplier} for generated elements
+     * @return a new sequential {@code IntStream}
+     */
+    public static IntStream generate(IntSupplier s) {
+        Objects.requireNonNull(s);
+        return StreamSupport.intStream(Spliterators.spliteratorUnknownSize(
+                new PrimitiveIterator.OfInt() {
+                    @Override
+                    public boolean hasNext() { return true; }
+
+                    @Override
+                    public int nextInt() { return s.getAsInt(); }
+                },
+                Spliterator.ORDERED | Spliterator.IMMUTABLE | Spliterator.NONNULL));
+    }
+
+    /**
+     * Returns a sequential {@code IntStream} from {@code startInclusive}
+     * (inclusive) to {@code endExclusive} (exclusive) by an incremental step of
+     * 1.
+     *
+     * @implSpec
+     * The implementation behaves as if:
+     * <pre>{@code
+     *     intRange(startInclusive, endExclusive, 1);
+     * }</pre>
+     *
+     * @param startInclusive the (inclusive) initial value
+     * @param endExclusive the exclusive upper bound
+     * @return a sequential {@code IntStream} for the range of {@code int}
+     *         elements
+     */
+    public static IntStream range(int startInclusive, int endExclusive) {
+        return range(startInclusive, endExclusive, 1);
+    }
+
+    /**
+     * Returns a sequential {@code IntStream} from {@code startInclusive}
+     * (inclusive) to {@code endExclusive} (exclusive) by a positive {@code
+     * step}.  If {@code startInclusive} is greater than or equal to {@code
+     * endExclusive}, an empty stream is returned.
+     *
+     * <p>An equivalent sequence of increasing values can be produced
+     * sequentially using a {@code for} loop as follows:
+     * <pre>{@code
+     *     for (int i = startInclusive; i < endExclusive ; i += step) { ... }
+     * }</pre>
+     *
+     * @param startInclusive the (inclusive) initial value
+     * @param endExclusive the exclusive upper bound
+     * @param step the positive difference between consecutive values
+     * @return a sequential {@code IntStream} for the range of {@code int}
+     *         elements
+     * @throws IllegalArgumentException if {@code step} is less than or equal to
+     *                                  0
+     */
+    public static IntStream range(int startInclusive, int endExclusive, int step) {
+        if (step <= 0) {
+            throw new IllegalArgumentException(String.format("Illegal step: %d", step));
+        } else if (startInclusive >= endExclusive) {
+            return empty();
+        } else {
+            return StreamSupport.intStream(new Streams.RangeIntSpliterator(startInclusive, endExclusive, step));
+        }
+    }
 }
--- a/src/share/classes/java/util/stream/LongStream.java	Tue Apr 30 12:31:51 2013 -0700
+++ b/src/share/classes/java/util/stream/LongStream.java	Tue Apr 30 12:32:49 2013 -0700
@@ -24,17 +24,21 @@
  */
 package java.util.stream;
 
+import java.util.Arrays;
 import java.util.LongSummaryStatistics;
+import java.util.Objects;
 import java.util.OptionalDouble;
 import java.util.OptionalLong;
 import java.util.PrimitiveIterator;
 import java.util.Spliterator;
+import java.util.Spliterators;
 import java.util.function.BiConsumer;
 import java.util.function.Function;
 import java.util.function.LongBinaryOperator;
 import java.util.function.LongConsumer;
 import java.util.function.LongFunction;
 import java.util.function.LongPredicate;
+import java.util.function.LongSupplier;
 import java.util.function.LongToDoubleFunction;
 import java.util.function.LongToIntFunction;
 import java.util.function.LongUnaryOperator;
@@ -643,4 +647,153 @@
 
     @Override
     Spliterator.OfLong spliterator();
+
+    // Static factories
+
+    /**
+     * Returns a builder for a {@code LongStream}.
+     *
+     * @return a stream builder
+     */
+    public static StreamBuilder.OfLong builder() {
+        return new Streams.LongStreamBuilderImpl();
+    }
+
+    /**
+     * Returns an empty sequential {@code LongStream}.
+     *
+     * @return an empty sequential stream
+     */
+    public static LongStream empty() {
+        return StreamSupport.longStream(Spliterators.emptyLongSpliterator());
+    }
+
+    /**
+     * Returns a sequential {@code LongStream} containing a single element.
+     *
+     * @param t the single element
+     * @return a singleton sequential stream
+     */
+    public static LongStream of(long t) {
+        return StreamSupport.longStream(new Streams.LongStreamBuilderImpl(t));
+    }
+
+    /**
+     * Returns a sequential stream whose elements are the specified values.
+     *
+     * @param values the elements of the new stream
+     * @return the new stream
+     */
+    public static LongStream of(long... values) {
+        return Arrays.stream(values);
+    }
+
+    /**
+     * Returns an infinite sequential {@code LongStream} produced by iterative
+     * application of a function {@code f} to an initial element {@code seed},
+     * producing a {@code Stream} consisting of {@code seed}, {@code f(seed)},
+     * {@code f(f(seed))}, etc.
+     *
+     * <p>The first element (position {@code 0}) in the {@code LongStream} will
+     * be the provided {@code seed}.  For {@code n > 0}, the element at position
+     * {@code n}, will be the result of applying the function {@code f} to the
+     * element at position {@code n - 1}.
+     *
+     * @param seed the initial element
+     * @param f a function to be applied to to the previous element to produce
+     *          a new element
+     * @return a new sequential {@code LongStream}
+     */
+    public static LongStream iterate(final long seed, final LongUnaryOperator f) {
+        Objects.requireNonNull(f);
+        final PrimitiveIterator.OfLong iterator = new PrimitiveIterator.OfLong() {
+            long t = seed;
+
+            @Override
+            public boolean hasNext() {
+                return true;
+            }
+
+            @Override
+            public long nextLong() {
+                long v = t;
+                t = f.applyAsLong(t);
+                return v;
+            }
+        };
+        return StreamSupport.longStream(Spliterators.spliteratorUnknownSize(
+                iterator,
+                Spliterator.ORDERED | Spliterator.IMMUTABLE | Spliterator.NONNULL));
+    }
+
+    /**
+     * Returns a sequential {@code LongStream} where each element is generated
+     * by a {@code LongSupplier}.  This is suitable for generating constant
+     * streams, streams of random elements, etc.
+     *
+     * @param s the {@code LongSupplier} for generated elements
+     * @return a new sequential {@code LongStream}
+     */
+    public static LongStream generate(LongSupplier s) {
+        Objects.requireNonNull(s);
+        return StreamSupport.longStream(Spliterators.spliteratorUnknownSize(
+                new PrimitiveIterator.OfLong() {
+                    @Override
+                    public boolean hasNext() { return true; }
+
+                    @Override
+                    public long nextLong() { return s.getAsLong(); }
+                },
+                Spliterator.ORDERED | Spliterator.IMMUTABLE | Spliterator.NONNULL));
+    }
+
+    /**
+     * Returns a sequential {@code LongStream} from {@code startInclusive}
+     * (inclusive) to {@code endExclusive} (exclusive) by an incremental step of
+     * 1.
+     *
+     * @implSpec
+     * The implementation behaves as if:
+     * <pre>{@code
+     *     longRange(startInclusive, endExclusive, 1);
+     * }</pre>
+     *
+     * @param startInclusive the (inclusive) initial value
+     * @param endExclusive the exclusive upper bound
+     * @return a sequential {@code LongStream} for the range of {@code long}
+     *         elements
+     */
+    public static LongStream range(long startInclusive, final long endExclusive) {
+        return range(startInclusive, endExclusive, 1);
+    }
+
+    /**
+     * Returns a sequential {@code LongStream} from {@code startInclusive}
+     * (inclusive) to {@code endExclusive} (exclusive) by {@code step}. If
+     * {@code startInclusive} is greater than or equal to {@code
+     * endExclusive}, an empty stream is returned.
+     *
+     * <p>An equivalent sequence of increasing values can be produced
+     * sequentially using a {@code for} loop as follows:
+     * <pre>{@code
+     *     for (long i = startInclusive; i < endExclusive ; i += step) { ... }
+     * }</pre>
+     *
+     * @param startInclusive the (inclusive) initial value
+     * @param endExclusive the exclusive upper bound
+     * @param step the difference between consecutive values
+     * @return a sequential {@code LongStream} for the range of {@code long}
+     *         elements
+     * @throws IllegalArgumentException if {@code step} is less than or equal to
+     *                                  0
+     */
+    public static LongStream range(long startInclusive, final long endExclusive, final long step) {
+        if (step <= 0) {
+            throw new IllegalArgumentException(String.format("Illegal step: %d", step));
+        } else if (startInclusive >= endExclusive) {
+            return empty();
+        } else {
+            return StreamSupport.longStream(new Streams.RangeLongSpliterator(startInclusive, endExclusive, step));
+        }
+    }
 }
--- a/src/share/classes/java/util/stream/Stream.java	Tue Apr 30 12:31:51 2013 -0700
+++ b/src/share/classes/java/util/stream/Stream.java	Tue Apr 30 12:32:49 2013 -0700
@@ -24,8 +24,13 @@
  */
 package java.util.stream;
 
+import java.util.Arrays;
 import java.util.Comparator;
+import java.util.Iterator;
+import java.util.Objects;
 import java.util.Optional;
+import java.util.Spliterator;
+import java.util.Spliterators;
 import java.util.function.BiConsumer;
 import java.util.function.BiFunction;
 import java.util.function.BinaryOperator;
@@ -37,6 +42,7 @@
 import java.util.function.ToDoubleFunction;
 import java.util.function.ToIntFunction;
 import java.util.function.ToLongFunction;
+import java.util.function.UnaryOperator;
 
 // @@@ Specification to-do list @@@
 // - Describe the difference between sequential and parallel streams
@@ -779,4 +785,109 @@
      * @see #findFirst()
      */
     Optional<T> findAny();
+
+    // Static factories
+
+    /**
+     * Returns a builder for a {@code Stream}.
+     *
+     * @param <T> type of elements
+     * @return a stream builder
+     */
+    public static<T> StreamBuilder<T> builder() {
+        return new Streams.StreamBuilderImpl<>();
+    }
+
+    /**
+     * Returns an empty sequential {@code Stream}.
+     *
+     * @param <T> the type of stream elements
+     * @return an empty sequential stream
+     */
+    public static<T> Stream<T> empty() {
+        return StreamSupport.stream(Spliterators.<T>emptySpliterator());
+    }
+
+    /**
+     * Returns a sequential {@code Stream} containing a single element.
+     *
+     * @param t the single element
+     * @param <T> the type of stream elements
+     * @return a singleton sequential stream
+     */
+    public static<T> Stream<T> of(T t) {
+        return StreamSupport.stream(new Streams.StreamBuilderImpl<>(t));
+    }
+
+    /**
+     * Returns a sequential stream whose elements are the specified values.
+     *
+     * @param <T> the type of stream elements
+     * @param values the elements of the new stream
+     * @return the new stream
+     */
+    @SafeVarargs
+    public static<T> Stream<T> of(T... values) {
+        return Arrays.stream(values);
+    }
+
+    /**
+     * Returns an infinite sequential {@code Stream} produced by iterative
+     * application of a function {@code f} to an initial element {@code seed},
+     * producing a {@code Stream} consisting of {@code seed}, {@code f(seed)},
+     * {@code f(f(seed))}, etc.
+     *
+     * <p>The first element (position {@code 0}) in the {@code Stream} will be
+     * the provided {@code seed}.  For {@code n > 0}, the element at position
+     * {@code n}, will be the result of applying the function {@code f} to the
+     * element at position {@code n - 1}.
+     *
+     * @param <T> the type of stream elements
+     * @param seed the initial element
+     * @param f a function to be applied to to the previous element to produce
+     *          a new element
+     * @return a new sequential {@code Stream}
+     */
+    public static<T> Stream<T> iterate(final T seed, final UnaryOperator<T> f) {
+        Objects.requireNonNull(f);
+        final Iterator<T> iterator = new Iterator<T>() {
+            @SuppressWarnings("unchecked")
+            T t = (T) Streams.NONE;
+
+            @Override
+            public boolean hasNext() {
+                return true;
+            }
+
+            @Override
+            public T next() {
+                return t = (t == Streams.NONE) ? seed : f.apply(t);
+            }
+        };
+        return StreamSupport.stream(Spliterators.spliteratorUnknownSize(
+                iterator,
+                Spliterator.ORDERED | Spliterator.IMMUTABLE));
+    }
+
+    /**
+     * Returns a sequential {@code Stream} where each element is
+     * generated by a {@code Supplier}.  This is suitable for generating
+     * constant streams, streams of random elements, etc.
+     *
+     * @param <T> the type of stream elements
+     * @param s the {@code Supplier} of generated elements
+     * @return a new sequential {@code Stream}
+     */
+    public static<T> Stream<T> generate(Supplier<T> s) {
+        Objects.requireNonNull(s);
+        return StreamSupport.stream(Spliterators.spliteratorUnknownSize(
+                new Iterator<T>() {
+                    @Override
+                    public boolean hasNext() { return true; }
+
+                    @Override
+                    public T next() { return s.get(); }
+                },
+                Spliterator.ORDERED | Spliterator.IMMUTABLE));
+    }
 }
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/share/classes/java/util/stream/StreamBuilder.java	Tue Apr 30 12:32:49 2013 -0700
@@ -0,0 +1,265 @@
+/*
+ * Copyright (c) 2013, 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.stream;
+
+import java.util.function.Consumer;
+import java.util.function.DoubleConsumer;
+import java.util.function.IntConsumer;
+import java.util.function.LongConsumer;
+
+/**
+ * A mutable builder for a {@code Stream}.  This allows the creation of a
+ * {@code Stream} by generating elements individually and adding them to the
+ * {@code StreamBuilder} (without the copying overhead that comes from using
+ * an {@code ArrayList} as a temporary buffer.)
+ *
+ * <p>A {@code StreamBuilder} has a lifecycle, where it starts in a building
+ * phase, during which elements can be added, and then transitions to a built
+ * phase, after which elements may not be added.  The built phase begins
+ * when the {@link #build()}} method is called, which creates an ordered
+ * {@code Stream} whose elements are the elements that were added to the stream
+ * builder, in the order they were added.
+ *
+ * <p>Primitive specializations of {@code StreamBuilder} are provided
+ * for {@link OfInt int}, {@link OfLong long}, and {@link OfDouble double}
+ * values.
+ *
+ * @param <T> the type of stream elements
+ * @see Stream#builder()
+ * @since 1.8
+ */
+public interface StreamBuilder<T> extends Consumer<T> {
+
+    /**
+     * Adds an element to the stream being built.
+     *
+     * @throws IllegalStateException if the builder has already transitioned to
+     * the built state
+     */
+    @Override
+    void accept(T t);
+
+    /**
+     * Adds an element to the stream being built.
+     *
+     * @implSpec
+     * The default implementation behaves as if:
+     * <pre>{@code
+     *     accept(t)
+     *     return this;
+     * }</pre>
+     *
+     * @param t the element to add
+     * @return {@code this} builder
+     * @throws IllegalStateException if the builder has already transitioned to
+     * the built state
+     */
+    default StreamBuilder<T> add(T t) {
+        accept(t);
+        return this;
+    }
+
+    /**
+     * Builds the stream, transitioning this builder to the built state.
+     * An {@code IllegalStateException} is thrown if there are further attempts
+     * to operate on the builder after it has entered the built state.
+     *
+     * @return the built stream
+     * @throws IllegalStateException if the builder has already transitioned to
+     * the built state
+     */
+    Stream<T> build();
+
+    /**
+     * A mutable builder for an {@code IntStream}.
+     *
+     * <p>A stream builder has a lifecycle, where it starts in a building
+     * phase, during which elements can be added, and then transitions to a
+     * built phase, after which elements may not be added.  The built phase
+     * begins when the {@link #build()}} method is called, which creates an
+     * ordered stream whose elements are the elements that were added to the
+     * stream builder, in the order they were added.
+     *
+     * @see IntStream#builder()
+     * @since 1.8
+     */
+    interface OfInt extends IntConsumer {
+
+        /**
+         * Adds an element to the stream being built.
+         *
+         * @throws IllegalStateException if the builder has already transitioned
+         * to the built state
+         */
+        @Override
+        void accept(int t);
+
+        /**
+         * Adds an element to the stream being built.
+         *
+         * @implSpec
+         * The default implementation behaves as if:
+         * <pre>{@code
+         *     accept(t)
+         *     return this;
+         * }</pre>
+         *
+         * @param t the element to add
+         * @return {@code this} builder
+         * @throws IllegalStateException if the builder has already transitioned
+         * to the built state
+         */
+        default StreamBuilder.OfInt add(int t) {
+            accept(t);
+            return this;
+        }
+
+        /**
+         * Builds the stream, transitioning this builder to the built state.
+         * An {@code IllegalStateException} is thrown if there are further
+         * attempts to operate on the builder after it has entered the built
+         * state.
+         *
+         * @return the built stream
+         * @throws IllegalStateException if the builder has already transitioned to
+         * the built state
+         */
+        IntStream build();
+    }
+
+    /**
+     * A mutable builder for a {@code LongStream}.
+     *
+     * <p>A stream builder has a lifecycle, where it starts in a building
+     * phase, during which elements can be added, and then transitions to a
+     * built phase, after which elements may not be added.  The built phase
+     * begins when the {@link #build()}} method is called, which creates an
+     * ordered stream whose elements are the elements that were added to the
+     * stream builder, in the order they were added.
+     *
+     * @see LongStream#builder()
+     * @since 1.8
+     */
+    interface OfLong extends LongConsumer {
+
+        /**
+         * Adds an element to the stream being built.
+         *
+         * @throws IllegalStateException if the builder has already transitioned
+         * to the built state
+         */
+        @Override
+        void accept(long t);
+
+        /**
+         * Adds an element to the stream being built.
+         *
+         * @implSpec
+         * The default implementation behaves as if:
+         * <pre>{@code
+         *     accept(t)
+         *     return this;
+         * }</pre>
+         *
+         * @param t the element to add
+         * @return {@code this} builder
+         * @throws IllegalStateException if the builder has already transitioned
+         * to the built state
+         */
+        default StreamBuilder.OfLong add(long t) {
+            accept(t);
+            return this;
+        }
+
+        /**
+         * Builds the stream, transitioning this builder to the built state.
+         * An {@code IllegalStateException} is thrown if there are further
+         * attempts to operate on the builder after it has entered the built
+         * state.
+         *
+         * @return the built stream
+         * @throws IllegalStateException if the builder has already transitioned
+         * to the built state
+         */
+        LongStream build();
+    }
+
+    /**
+     * A mutable builder for a {@code DoubleStream}.
+     *
+     * @see LongStream#builder()
+     * @since 1.8
+     */
+    interface OfDouble extends DoubleConsumer {
+
+        /**
+         * Adds an element to the stream being built.
+         *
+         * <p>A stream builder  has a lifecycle, where it starts in a building
+         * phase, during which elements can be added, and then transitions to a
+         * built phase, after which elements may not be added.  The built phase
+         * begins when the {@link #build()}} method is called, which creates an
+         * ordered stream whose elements are the elements that were added to the
+         * stream builder, in the order they were added.
+         *
+         * @throws IllegalStateException if the builder has already transitioned
+         * to the built state
+         */
+        @Override
+        void accept(double t);
+
+        /**
+         * Adds an element to the stream being built.
+         *
+         * @implSpec
+         * The default implementation behaves as if:
+         * <pre>{@code
+         *     accept(t)
+         *     return this;
+         * }</pre>
+         *
+         * @param t the element to add
+         * @return {@code this} builder
+         * @throws IllegalStateException if the builder has already transitioned
+         * to the built state
+         */
+        default StreamBuilder.OfDouble add(double t) {
+            accept(t);
+            return this;
+        }
+
+        /**
+         * Builds the stream, transitioning this builder to the built state.
+         * An {@code IllegalStateException} is thrown if there are further
+         * attempts to operate on the builder after it has entered the built
+         * state.
+         *
+         * @return the built stream
+         * @throws IllegalStateException if the builder has already transitioned
+         * to the built state
+         */
+        DoubleStream build();
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/share/classes/java/util/stream/Streams.java	Tue Apr 30 12:32:49 2013 -0700
@@ -0,0 +1,656 @@
+/*
+ * Copyright (c) 2012, 2013, 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.stream;
+
+import java.util.Comparator;
+import java.util.Iterator;
+import java.util.Objects;
+import java.util.Spliterator;
+import java.util.Spliterators;
+import java.util.function.BiFunction;
+import java.util.function.Consumer;
+import java.util.function.DoubleConsumer;
+import java.util.function.IntConsumer;
+import java.util.function.LongConsumer;
+
+/**
+ * Utility methods for operating on and creating streams.
+ *
+ * <p>Unless otherwise stated, streams are created as sequential streams.  A
+ * sequential stream can be transformed into a parallel stream by calling the
+ * {@code parallel()} method on the created stream.
+ *
+ * @since 1.8
+ */
+class Streams {
+
+    private Streams() {
+        throw new Error("no instances");
+    }
+
+    /**
+     * An object instance representing no value, that cannot be an actual
+     * data element of a stream.  Used when processing streams that can contain
+     * {@code null} elements to distinguish between a {@code null} value and no
+     * value.
+     */
+    static final Object NONE = new Object();
+
+    /**
+     * An {@code int} range spliterator.
+     */
+    static final class RangeIntSpliterator implements Spliterator.OfInt {
+        private int from;
+        private final int upTo;
+        private final int step;
+
+        RangeIntSpliterator(int from, int upTo, int step) {
+            this.from = from;
+            this.upTo = upTo;
+            this.step = step;
+        }
+
+        @Override
+        public boolean tryAdvance(IntConsumer consumer) {
+            boolean hasNext = from < upTo;
+            if (hasNext) {
+                consumer.accept(from);
+                from += step;
+            }
+            return hasNext;
+        }
+
+        @Override
+        public void forEachRemaining(IntConsumer consumer) {
+            int hUpTo = upTo;
+            int hStep = step; // hoist accesses and checks from loop
+            for (int i = from; i < hUpTo; i += hStep)
+                consumer.accept(i);
+            from = upTo;
+        }
+
+        @Override
+        public long estimateSize() {
+            int d = upTo - from;
+            return (d / step) + ((d % step == 0) ? 0 : 1);
+        }
+
+        @Override
+        public int characteristics() {
+            return Spliterator.ORDERED | Spliterator.SIZED | Spliterator.SUBSIZED |
+                   Spliterator.IMMUTABLE | Spliterator.NONNULL |
+                   Spliterator.DISTINCT | Spliterator.SORTED;
+        }
+
+        @Override
+        public Comparator<? super Integer> getComparator() {
+            return null;
+        }
+
+        @Override
+        public Spliterator.OfInt trySplit() {
+            return estimateSize() <= 1
+                   ? null
+                   : new RangeIntSpliterator(from, from = from + midPoint(), step);
+        }
+
+        private int midPoint() {
+            // Size is known to be >= 2
+            int bisection = (upTo - from) / 2;
+            // If bisection > step then round down to nearest multiple of step
+            // otherwise round up to step
+            return bisection > step ? bisection - bisection % step : step;
+        }
+    }
+
+    /**
+     * A {@code long} range spliterator.
+     */
+    static final class RangeLongSpliterator implements Spliterator.OfLong {
+        private long from;
+        private final long upTo;
+        private final long step;
+
+        RangeLongSpliterator(long from, long upTo, long step) {
+            this.from = from;
+            this.upTo = upTo;
+            this.step = step;
+        }
+
+        @Override
+        public boolean tryAdvance(LongConsumer consumer) {
+            boolean hasNext = from < upTo;
+            if (hasNext) {
+                consumer.accept(from);
+                from += step;
+            }
+            return hasNext;
+        }
+
+        @Override
+        public void forEachRemaining(LongConsumer consumer) {
+            long hUpTo = upTo;
+            long hStep = step; // hoist accesses and checks from loop
+            for (long i = from; i < hUpTo; i += hStep)
+                consumer.accept(i);
+            from = upTo;
+        }
+
+        @Override
+        public long estimateSize() {
+            long d = upTo - from;
+            return (d / step) + ((d % step == 0) ? 0 : 1);
+        }
+
+        @Override
+        public int characteristics() {
+            return Spliterator.ORDERED | Spliterator.SIZED | Spliterator.SUBSIZED |
+                   Spliterator.IMMUTABLE | Spliterator.NONNULL |
+                   Spliterator.DISTINCT | Spliterator.SORTED;
+        }
+
+        @Override
+        public Comparator<? super Long> getComparator() {
+            return null;
+        }
+
+        @Override
+        public Spliterator.OfLong trySplit() {
+            return estimateSize() <= 1
+                   ? null
+                   : new RangeLongSpliterator(from, from = from + midPoint(), step);
+        }
+
+        private long midPoint() {
+            // Size is known to be >= 2
+            long bisection = (upTo - from) / 2;
+            // If bisection > step then round down to nearest multiple of step
+            // otherwise round up to step
+            return bisection > step ? bisection - bisection % step : step;
+        }
+    }
+
+    /**
+     * A {@code double} range spliterator.
+     *
+     * <p>The traversing and splitting logic is equivalent to that of
+     * {@code RangeLongSpliterator} for increasing values with a {@code step} of
+     * {@code 1}.
+     *
+     *  <p>A {@code double} value is calculated from the function
+     * {@code start + i * step} where {@code i} is the absolute position of the
+     * value when traversing an instance of this class that has not been split.
+     * This ensures the same values are produced at the same absolute positions
+     * regardless of how an instance of this class is split or traversed.
+     */
+    static final class RangeDoubleSpliterator implements Spliterator.OfDouble {
+        private final double from;
+        private final double upTo;
+        private final double step;
+
+        private long lFrom;
+        private final long lUpTo;
+
+        RangeDoubleSpliterator(double from, double upTo, double step, long lFrom, long lUpTo) {
+            this.from = from;
+            this.upTo = upTo;
+            this.step = step;
+            this.lFrom = lFrom;
+            this.lUpTo = lUpTo;
+        }
+
+        @Override
+        public boolean tryAdvance(DoubleConsumer consumer) {
+            boolean hasNext = lFrom < lUpTo;
+            if (hasNext) {
+                consumer.accept(from + lFrom * step);
+                lFrom++;
+            }
+            return hasNext;
+        }
+
+        @Override
+        public void forEachRemaining(DoubleConsumer consumer) {
+            double hOrigin = from;
+            double hStep = step;
+            long hLUpTo = lUpTo;
+            long i = lFrom;
+            for (; i < hLUpTo; i++) {
+                consumer.accept(hOrigin + i * hStep);
+            }
+            lFrom = i;
+        }
+
+        @Override
+        public long estimateSize() {
+            return lUpTo - lFrom;
+        }
+
+        @Override
+        public int characteristics() {
+            return Spliterator.ORDERED | Spliterator.SIZED | Spliterator.SUBSIZED |
+                   Spliterator.IMMUTABLE | Spliterator.NONNULL |
+                   Spliterator.DISTINCT | Spliterator.SORTED;
+        }
+
+        @Override
+        public Comparator<? super Double> getComparator() {
+            return null;
+        }
+
+        @Override
+        public Spliterator.OfDouble trySplit() {
+            return estimateSize() <= 1
+                   ? null
+                   : new RangeDoubleSpliterator(from, upTo, step, lFrom, lFrom = lFrom + midPoint());
+        }
+
+        private long midPoint() {
+            // Size is known to be >= 2
+            return (lUpTo - lFrom) / 2;
+        }
+    }
+
+    private static abstract class AbstractStreamBuilderImpl<T, S extends Spliterator<T>> implements Spliterator<T> {
+        // >= 0 when building, < 0 when built
+        // -1 == no elements
+        // -2 == one element, held by first
+        // -3 == two or more elements, held by buffer
+        int count;
+
+        // Spliterator implementation for 0 or 1 element
+        // count == -1 for no elements
+        // count == -2 for one element held by first
+
+        @Override
+        public S trySplit() {
+            return null;
+        }
+
+        @Override
+        public long estimateSize() {
+            return -count - 1;
+        }
+
+        @Override
+        public int characteristics() {
+            return Spliterator.SIZED | Spliterator.SUBSIZED |
+                   Spliterator.ORDERED | Spliterator.IMMUTABLE;
+        }
+    }
+
+    static final class StreamBuilderImpl<T>
+            extends AbstractStreamBuilderImpl<T, Spliterator<T>>
+            implements StreamBuilder<T> {
+        // The first element in the stream
+        // valid if count == 1
+        T first;
+
+        // The first and subsequent elements in the stream
+        // non-null if count == 2
+        SpinedBuffer<T> buffer;
+
+        /**
+         * Constructor for building a stream of 0 or more elements.
+         */
+        StreamBuilderImpl() { }
+
+        /**
+         * Constructor for a singleton stream.
+         *
+         * @param t the single element
+         */
+        StreamBuilderImpl(T t) {
+            first = t;
+            count = -2;
+        }
+
+        // StreamBuilder implementation
+
+        @Override
+        public void accept(T t) {
+            if (count == 0) {
+                first = t;
+                count++;
+            }
+            else if (count > 0) {
+                if (buffer == null) {
+                    buffer = new SpinedBuffer<>();
+                    buffer.accept(first);
+                    count++;
+                }
+
+                buffer.accept(t);
+            }
+            else {
+                throw new IllegalStateException();
+            }
+        }
+
+        public StreamBuilder<T> add(T t) {
+            accept(t);
+            return this;
+        }
+
+        @Override
+        public Stream<T> build() {
+            int c = count;
+            if (c >= 0) {
+                // Switch count to negative value signalling the builder is built
+                count = -count - 1;
+                // Use this spliterator if 0 or 1 elements, otherwise use
+                // the spliterator of the spined buffer
+                return (c < 2) ? StreamSupport.stream(this) : StreamSupport.stream(buffer.spliterator());
+            }
+
+            throw new IllegalStateException();
+        }
+
+        // Spliterator implementation for 0 or 1 element
+        // count == -1 for no elements
+        // count == -2 for one element held by first
+
+        @Override
+        public boolean tryAdvance(Consumer<? super T> action) {
+            if (count == -2) {
+                action.accept(first);
+                count = -1;
+                return true;
+            }
+            else {
+                return false;
+            }
+        }
+
+        @Override
+        public void forEachRemaining(Consumer<? super T> action) {
+            if (count == -2) {
+                action.accept(first);
+                count = -1;
+            }
+        }
+    }
+
+    static final class IntStreamBuilderImpl
+            extends AbstractStreamBuilderImpl<Integer, Spliterator.OfInt>
+            implements StreamBuilder.OfInt, Spliterator.OfInt {
+        // The first element in the stream
+        // valid if count == 1
+        int first;
+
+        // The first and subsequent elements in the stream
+        // non-null if count == 2
+        SpinedBuffer.OfInt buffer;
+
+        /**
+         * Constructor for building a stream of 0 or more elements.
+         */
+        IntStreamBuilderImpl() { }
+
+        /**
+         * Constructor for a singleton stream.
+         *
+         * @param t the single element
+         */
+        IntStreamBuilderImpl(int t) {
+            first = t;
+            count = -2;
+        }
+
+        // StreamBuilder implementation
+
+        @Override
+        public void accept(int t) {
+            if (count == 0) {
+                first = t;
+                count++;
+            }
+            else if (count > 0) {
+                if (buffer == null) {
+                    buffer = new SpinedBuffer.OfInt();
+                    buffer.accept(first);
+                    count++;
+                }
+
+                buffer.accept(t);
+            }
+            else {
+                throw new IllegalStateException();
+            }
+        }
+
+        @Override
+        public IntStream build() {
+            int c = count;
+            if (c >= 0) {
+                // Switch count to negative value signalling the builder is built
+                count = -count - 1;
+                // Use this spliterator if 0 or 1 elements, otherwise use
+                // the spliterator of the spined buffer
+                return (c < 2) ? StreamSupport.intStream(this) : StreamSupport.intStream(buffer.spliterator());
+            }
+
+            throw new IllegalStateException();
+        }
+
+        // Spliterator implementation for 0 or 1 element
+        // count == -1 for no elements
+        // count == -2 for one element held by first
+
+        @Override
+        public boolean tryAdvance(IntConsumer action) {
+            if (count == -2) {
+                action.accept(first);
+                count = -1;
+                return true;
+            }
+            else {
+                return false;
+            }
+        }
+
+        @Override
+        public void forEachRemaining(IntConsumer action) {
+            if (count == -2) {
+                action.accept(first);
+                count = -1;
+            }
+        }
+    }
+
+    static final class LongStreamBuilderImpl
+            extends AbstractStreamBuilderImpl<Long, Spliterator.OfLong>
+            implements StreamBuilder.OfLong, Spliterator.OfLong {
+        // The first element in the stream
+        // valid if count == 1
+        long first;
+
+        // The first and subsequent elements in the stream
+        // non-null if count == 2
+        SpinedBuffer.OfLong buffer;
+
+        /**
+         * Constructor for building a stream of 0 or more elements.
+         */
+        LongStreamBuilderImpl() { }
+
+        /**
+         * Constructor for a singleton stream.
+         *
+         * @param t the single element
+         */
+        LongStreamBuilderImpl(long t) {
+            first = t;
+            count = -2;
+        }
+
+        // StreamBuilder implementation
+
+        @Override
+        public void accept(long t) {
+            if (count == 0) {
+                first = t;
+                count++;
+            }
+            else if (count > 0) {
+                if (buffer == null) {
+                    buffer = new SpinedBuffer.OfLong();
+                    buffer.accept(first);
+                    count++;
+                }
+
+                buffer.accept(t);
+            }
+            else {
+                throw new IllegalStateException();
+            }
+        }
+
+        @Override
+        public LongStream build() {
+            int c = count;
+            if (c >= 0) {
+                // Switch count to negative value signalling the builder is built
+                count = -count - 1;
+                // Use this spliterator if 0 or 1 elements, otherwise use
+                // the spliterator of the spined buffer
+                return (c < 2) ? StreamSupport.longStream(this) : StreamSupport.longStream(buffer.spliterator());
+            }
+
+            throw new IllegalStateException();
+        }
+
+        // Spliterator implementation for 0 or 1 element
+        // count == -1 for no elements
+        // count == -2 for one element held by first
+
+        @Override
+        public boolean tryAdvance(LongConsumer action) {
+            if (count == -2) {
+                action.accept(first);
+                count = -1;
+                return true;
+            }
+            else {
+                return false;
+            }
+        }
+
+        @Override
+        public void forEachRemaining(LongConsumer action) {
+            if (count == -2) {
+                action.accept(first);
+                count = -1;
+            }
+        }
+    }
+
+    static final class DoubleStreamBuilderImpl
+            extends AbstractStreamBuilderImpl<Double, Spliterator.OfDouble>
+            implements StreamBuilder.OfDouble, Spliterator.OfDouble {
+        // The first element in the stream
+        // valid if count == 1
+        double first;
+
+        // The first and subsequent elements in the stream
+        // non-null if count == 2
+        SpinedBuffer.OfDouble buffer;
+
+        /**
+         * Constructor for building a stream of 0 or more elements.
+         */
+        DoubleStreamBuilderImpl() { }
+
+        /**
+         * Constructor for a singleton stream.
+         *
+         * @param t the single element
+         */
+        DoubleStreamBuilderImpl(double t) {
+            first = t;
+            count = -2;
+        }
+
+        // StreamBuilder implementation
+
+        @Override
+        public void accept(double t) {
+            if (count == 0) {
+                first = t;
+                count++;
+            }
+            else if (count > 0) {
+                if (buffer == null) {
+                    buffer = new SpinedBuffer.OfDouble();
+                    buffer.accept(first);
+                    count++;
+                }
+
+                buffer.accept(t);
+            }
+            else {
+                throw new IllegalStateException();
+            }
+        }
+
+        @Override
+        public DoubleStream build() {
+            int c = count;
+            if (c >= 0) {
+                // Switch count to negative value signalling the builder is built
+                count = -count - 1;
+                // Use this spliterator if 0 or 1 elements, otherwise use
+                // the spliterator of the spined buffer
+                return (c < 2) ? StreamSupport.doubleStream(this) : StreamSupport.doubleStream(buffer.spliterator());
+            }
+
+            throw new IllegalStateException();
+        }
+
+        // Spliterator implementation for 0 or 1 element
+        // count == -1 for no elements
+        // count == -2 for one element held by first
+
+        @Override
+        public boolean tryAdvance(DoubleConsumer action) {
+            if (count == -2) {
+                action.accept(first);
+                count = -1;
+                return true;
+            }
+            else {
+                return false;
+            }
+        }
+
+        @Override
+        public void forEachRemaining(DoubleConsumer action) {
+            if (count == -2) {
+                action.accept(first);
+                count = -1;
+            }
+        }
+    }
+}
--- a/src/share/classes/sun/management/AgentConfigurationError.java	Tue Apr 30 12:31:51 2013 -0700
+++ b/src/share/classes/sun/management/AgentConfigurationError.java	Tue Apr 30 12:32:49 2013 -0700
@@ -128,19 +128,13 @@
     public AgentConfigurationError(String error, String... params) {
         super();
         this.error = error;
-        this.params = new String[params.length];
-        for (int i = 0; i < params.length; i++) {
-            this.params[i] = params[i];
-        }
+        this.params = params.clone();
     }
 
     public AgentConfigurationError(String error, Throwable cause, String... params) {
         super(cause);
         this.error = error;
-        this.params = new String[params.length];
-        for (int i = 0; i < params.length; i++) {
-            this.params[i] = params[i];
-        }
+        this.params = params.clone();
     }
 
     public String getError() {
@@ -148,7 +142,7 @@
     }
 
     public String[] getParams() {
-        return params;
+        return params.clone();
     }
 
     private static final long serialVersionUID = 1211605593516195475L;
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/java/net/Inet6Address/serialize/Inet6AddressSerializationTest.java	Tue Apr 30 12:32:49 2013 -0700
@@ -0,0 +1,1122 @@
+/*
+ * Copyright (c) 2013, 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.
+ *
+ * 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.
+ */
+
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
+import java.io.FileNotFoundException;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.ObjectInputStream;
+import java.io.ObjectOutputStream;
+import java.io.PrintStream;
+import java.net.Inet6Address;
+import java.net.InetAddress;
+import java.net.NetworkInterface;
+import java.net.UnknownHostException;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Enumeration;
+import java.util.List;
+
+/**
+ * @test
+ * @bug 8007373
+ * @summary jdk7 backward compatibility serialization problem
+ */
+
+public class Inet6AddressSerializationTest {
+
+    static boolean failed;
+
+    public static final int LOOPBACK_SCOPE_ID = 0;
+
+    public static final byte[] IN6ADDR_ANY_INIT = { (byte) 0x00, (byte) 0x00,
+            (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00,
+            (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00,
+            (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00 };
+
+    public static final byte[] LOOPBACKIPV6ADDRESS = { (byte) 0x00,
+            (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00,
+            (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00,
+            (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x01 };
+
+    // fe80::21b:24ff:febd:f29c
+    public static final byte[] E1000G0IPV6ADDRESS = { (byte) 0xfe, (byte) 0x80,
+            (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00,
+            (byte) 0x00, (byte) 0x02, (byte) 0x1b, (byte) 0x24, (byte) 0xff,
+            (byte) 0xfe, (byte) 0xbd, (byte) 0xf2, (byte) 0x9c };
+
+    public static final String E1000G0HOSTNAME = "fe80:0:0:0:21b:24ff:febd:f29c%e1000g0";
+
+    public static final String LOCALHOSTNAME = "localhost";
+
+    public static final String NETWORK_IF_E1000G0 = "e1000g0";
+
+    public static final String NETWORK_IF_LO0 = "lo0";
+
+    public static final int SCOPE_ID_E1000G0 = 2;
+
+    public static final int SCOPE_ID_LO0 = 1;
+
+    public static final int SCOPE_ID_ZERO = 0;
+
+    public static void main(String[] args) throws Exception {
+        // args[0] == generate-loopback generates serial data for loopback if
+        // args[0] == generateAll generates serial data for interfaces with an
+        // IPV6 address binding
+
+        if (args.length != 0) {
+
+            if (args[0].equals("generate-loopback")) {
+
+                generateSerializedInet6AddressData(Inet6Address.getByAddress(
+                        InetAddress.getLoopbackAddress().getHostName(),
+                        LOOPBACKIPV6ADDRESS, LOOPBACK_SCOPE_ID), System.out,
+                        true);
+
+            } else {
+                generateAllInet6AddressSerializedData();
+            }
+        } else {
+            runTests();
+        }
+    }
+
+    private static void runTests() throws UnknownHostException, Exception,
+            IOException {
+        byte[] thisHostIPV6Address = null;
+        int scope_id = LOOPBACK_SCOPE_ID;
+
+        System.out.println("Hostname: "
+                + InetAddress.getLocalHost().getHostName());
+        System.out.println("LocalHost isLoopback : "
+                + InetAddress.getLocalHost().isLoopbackAddress());
+        thisHostIPV6Address = getThisHostIPV6Address(InetAddress.getLocalHost()
+                .getHostName());
+
+        if (thisHostIPV6Address == null) {
+            thisHostIPV6Address = IN6ADDR_ANY_INIT;
+        }
+
+        // testing JDK7 generated serialized loopback against locally generated
+        // loopback address
+        testInet6AddressSerialization(Inet6Address.getByAddress(InetAddress
+                .getLoopbackAddress().getHostName(), LOOPBACKIPV6ADDRESS,
+                scope_id), JDK7Inet6AddressSerialData);
+        // testing JDK8 generated serialized loopback against locally generated
+        // loopback address
+        testInet6AddressSerialization(Inet6Address.getByAddress(InetAddress
+                .getLoopbackAddress().getHostName(), LOOPBACKIPV6ADDRESS,
+                scope_id), JDK8Inet6AddressSerialData);
+        testInet6AddressSerialization(Inet6Address.getByAddress(InetAddress
+                .getLocalHost().getHostName(), IN6ADDR_ANY_INIT, scope_id),
+                null);
+        testInet6AddressSerialization(Inet6Address.getByAddress(InetAddress
+                .getLocalHost().getHostName(), thisHostIPV6Address, scope_id),
+                null);
+        testAllNetworkInterfaces();
+
+        // test against lo0
+        testSerializedLo0Inet6Address();
+
+        testSerializedE1000gInet6Address();
+
+        if (failed)
+            throw new RuntimeException("Some tests failed, check output");
+    }
+
+    private static byte[] getThisHostIPV6Address(String hostName)
+            throws Exception {
+        InetAddress[] thisHostIPAddresses = null;
+        try {
+            thisHostIPAddresses = InetAddress.getAllByName(InetAddress
+                    .getLocalHost().getHostName());
+        } catch (UnknownHostException uhEx) {
+            uhEx.printStackTrace();
+            throw uhEx;
+        }
+        byte[] thisHostIPV6Address = null;
+        for (InetAddress inetAddress : thisHostIPAddresses) {
+            if (inetAddress instanceof Inet6Address) {
+                if (inetAddress.getHostName().equals(hostName)) {
+                    thisHostIPV6Address = inetAddress.getAddress();
+                    break;
+                }
+            }
+        }
+        // System.err.println("getThisHostIPV6Address: address is "
+        // + Arrays.toString(thisHostIPV6Address));
+        return thisHostIPV6Address;
+    }
+
+    static void testAllNetworkInterfaces() throws Exception {
+        System.err.println("\n testAllNetworkInterfaces: \n ");
+        for (Enumeration<NetworkInterface> e = NetworkInterface
+                .getNetworkInterfaces(); e.hasMoreElements();) {
+            NetworkInterface netIF = e.nextElement();
+            for (Enumeration<InetAddress> iadrs = netIF.getInetAddresses(); iadrs
+                    .hasMoreElements();) {
+                InetAddress iadr = iadrs.nextElement();
+                if (iadr instanceof Inet6Address) {
+                    System.err.println("Test NetworkInterface:  " + netIF);
+                    Inet6Address i6adr = (Inet6Address) iadr;
+                    System.err.println("Testing with " + iadr);
+                    System.err.println(" scoped iface: "
+                            + i6adr.getScopedInterface());
+                    testInet6AddressSerialization(i6adr, null);
+                }
+            }
+        }
+    }
+
+    static void displayExpectedInet6Address(Inet6Address expectedInet6Address) {
+
+        String expectedHostName = expectedInet6Address.getHostName();
+        byte[] expectedAddress = expectedInet6Address.getAddress();
+        String expectedHostAddress = expectedInet6Address.getHostAddress();
+        int expectedScopeId = expectedInet6Address.getScopeId();
+        NetworkInterface expectedNetIf = expectedInet6Address
+                .getScopedInterface();
+
+        System.err.println("Excpected HostName: " + expectedHostName);
+        System.err.println("Expected Address: "
+                + Arrays.toString(expectedAddress));
+        System.err.println("Expected HostAddress: " + expectedHostAddress);
+        System.err.println("Expected Scope Id " + expectedScopeId);
+        System.err.println("Expected NetworkInterface " + expectedNetIf);
+        System.err.println("Expected Inet6Address " + expectedInet6Address);
+    }
+
+    // test serialization deserialization of Inet6Address
+    static void testInet6AddressSerialization(
+            Inet6Address expectedInet6Address, byte[] serializedAddress)
+            throws IOException {
+        System.err.println("\n testInet6AddressSerialization:  enter \n");
+
+        // displayExpectedInet6Address(expectedInet6Address);
+
+        byte[] serialData = serializedAddress != null ? serializedAddress
+                : generateSerializedInet6AddressData(expectedInet6Address,
+                        null, false);
+        try (ByteArrayInputStream bis = new ByteArrayInputStream(serialData);
+                ObjectInputStream oin = new ObjectInputStream(bis)) {
+            Inet6Address deserializedIPV6Addr = (Inet6Address) oin.readObject();
+            System.err.println("Deserialized Inet6Address "
+                    + deserializedIPV6Addr);
+            assertHostNameEqual(expectedInet6Address.getHostName(),
+                    deserializedIPV6Addr.getHostName());
+            assertHostAddressEqual(expectedInet6Address.getHostAddress(),
+                    deserializedIPV6Addr.getHostAddress());
+            assertAddressEqual(expectedInet6Address.getAddress(),
+                    deserializedIPV6Addr.getAddress());
+            assertScopeIdEqual(expectedInet6Address.getScopeId(),
+                    deserializedIPV6Addr.getScopeId());
+            assertNetworkInterfaceEqual(
+                    expectedInet6Address.getScopedInterface(),
+                    deserializedIPV6Addr.getScopedInterface());
+        } catch (Exception e) {
+            System.err.println("Exception caught during deserialization");
+            failed = true;
+            e.printStackTrace();
+        }
+    }
+
+    static void testSerializedE1000gInet6Address() throws IOException {
+        System.err.println("\n testSerializedE1000gInet6Address:  enter \n");
+        boolean testWithNetIf = true;
+        boolean useMockInet6Address = false;
+
+        NetworkInterface testNetIf = NetworkInterface
+                .getByName(NETWORK_IF_E1000G0);
+        Inet6Address expectedInet6Address = null;
+        if (testNetIf != null) {
+            System.err
+                    .println("\n testSerializedE1000gInet6Address:  using netif \n");
+            try {
+                expectedInet6Address = Inet6Address.getByAddress(
+                        E1000G0HOSTNAME, E1000G0IPV6ADDRESS, testNetIf);
+            } catch (UnknownHostException ukhEx) {
+                ukhEx.printStackTrace();
+                testWithNetIf = true;
+                useMockInet6Address = true;
+            }
+        } else {
+            System.err
+                    .println("\n testSerializedE1000gInet6Address:  using index \n");
+            try {
+                expectedInet6Address = Inet6Address.getByAddress(
+                        E1000G0HOSTNAME, E1000G0IPV6ADDRESS, SCOPE_ID_ZERO);
+            } catch (UnknownHostException ukhEx1) {
+                ukhEx1.printStackTrace();
+                useMockInet6Address = true;
+            }
+            testWithNetIf = false;
+        }
+
+        byte[] serializedAddress = SerialData_ifname_e1000g0;
+
+        // displayExpectedInet6Address(expectedInet6Address);
+
+        try (ByteArrayInputStream bis = new ByteArrayInputStream(
+                serializedAddress);
+                ObjectInputStream oin = new ObjectInputStream(bis)) {
+            Inet6Address deserializedIPV6Addr = (Inet6Address) oin.readObject();
+            System.err.println("Deserialized Inet6Address "
+                    + deserializedIPV6Addr);
+
+            if (!useMockInet6Address) {
+                assertHostNameEqual(expectedInet6Address.getHostName(),
+                        deserializedIPV6Addr.getHostName());
+                if (testWithNetIf) {
+                    assertHostAddressEqual(
+                            expectedInet6Address.getHostAddress(),
+                            deserializedIPV6Addr.getHostAddress());
+                } else {
+                    assertHostAddressEqual(
+                            MockE1000g0Inet6Address.getBareHostAddress(),
+                            deserializedIPV6Addr.getHostAddress());
+                }
+                assertAddressEqual(expectedInet6Address.getAddress(),
+                        deserializedIPV6Addr.getAddress());
+                assertScopeIdEqual(expectedInet6Address.getScopeId(),
+                        deserializedIPV6Addr.getScopeId());
+                if (testWithNetIf) {
+                    assertNetworkInterfaceEqual(
+                            expectedInet6Address.getScopedInterface(),
+                            deserializedIPV6Addr.getScopedInterface());
+                } else {
+                    assertNetworkInterfaceEqual(null,
+                            deserializedIPV6Addr.getScopedInterface());
+                }
+            } else { // use MockLo0Inet6Address
+                assertHostNameEqual(MockE1000g0Inet6Address.getHostName(),
+                        deserializedIPV6Addr.getHostName());
+                if (testWithNetIf) {
+                    assertHostAddressEqual(
+                            MockE1000g0Inet6Address.getHostAddress(),
+                            deserializedIPV6Addr.getHostAddress());
+                } else {
+                    assertHostAddressEqual(
+                            MockE1000g0Inet6Address.getHostAddressWithIndex(),
+                            deserializedIPV6Addr.getHostAddress());
+                }
+                assertAddressEqual(MockE1000g0Inet6Address.getAddress(),
+                        deserializedIPV6Addr.getAddress());
+                if (testWithNetIf) {
+                assertScopeIdEqual(MockE1000g0Inet6Address.getScopeId(),
+                        deserializedIPV6Addr.getScopeId());
+                } else {
+                    assertScopeIdEqual(MockE1000g0Inet6Address.getScopeZero(),
+                            deserializedIPV6Addr.getScopeId());
+                }
+                assertNetworkInterfaceNameEqual(
+                        MockE1000g0Inet6Address.getScopeIfName(),
+                        deserializedIPV6Addr.getScopedInterface());
+            }
+        } catch (Exception e) {
+            System.err.println("Exception caught during deserialization");
+            failed = true;
+            e.printStackTrace();
+        }
+    }
+
+    static void testSerializedLo0Inet6Address() throws IOException {
+        System.err.println("\n testSerializedLo0Inet6Address:  enter \n");
+        boolean testWithNetIf = true;
+        boolean useMockInet6Address = false;
+
+        NetworkInterface testNetIf = NetworkInterface.getByName(NETWORK_IF_LO0);
+        Inet6Address expectedInet6Address = null;
+        if (testNetIf != null) {
+            System.err
+                    .println("\n testSerializedLo0Inet6Address:  using netif \n");
+            try {
+                expectedInet6Address = Inet6Address.getByAddress(LOCALHOSTNAME,
+                        LOOPBACKIPV6ADDRESS, testNetIf);
+            } catch (UnknownHostException ukhEx) {
+                ukhEx.printStackTrace();
+                testWithNetIf = true;
+                useMockInet6Address = true;
+            }
+        } else {
+            System.err
+                    .println("\n testSerializedLo0Inet6Address:  using index \n");
+            try {
+                expectedInet6Address = Inet6Address.getByAddress(LOCALHOSTNAME,
+                        LOOPBACKIPV6ADDRESS, SCOPE_ID_ZERO);
+            } catch (UnknownHostException ukhEx1) {
+                ukhEx1.printStackTrace();
+                useMockInet6Address = true;
+            }
+            testWithNetIf = false;
+        }
+
+        // displayExpectedInet6Address(expectedInet6Address);
+
+        byte[] serializedAddress = SerialData_ifname_lo0;
+
+        try (ByteArrayInputStream bis = new ByteArrayInputStream(
+                serializedAddress);
+                ObjectInputStream oin = new ObjectInputStream(bis)) {
+            Inet6Address deserializedIPV6Addr = (Inet6Address) oin.readObject();
+            System.err.println("Deserialized Inet6Address "
+                    + deserializedIPV6Addr);
+            if (!useMockInet6Address) {
+                assertHostNameEqual(expectedInet6Address.getHostName(),
+                        deserializedIPV6Addr.getHostName());
+                if (testWithNetIf) {
+                    assertHostAddressEqual(
+                            expectedInet6Address.getHostAddress(),
+                            deserializedIPV6Addr.getHostAddress());
+                } else {
+                    assertHostAddressEqual(
+                            MockLo0Inet6Address.getBareHostAddress(),
+                            deserializedIPV6Addr.getHostAddress());
+                }
+                assertAddressEqual(expectedInet6Address.getAddress(),
+                        deserializedIPV6Addr.getAddress());
+                assertScopeIdEqual(expectedInet6Address.getScopeId(),
+                        deserializedIPV6Addr.getScopeId());
+                if (testWithNetIf) {
+                    assertNetworkInterfaceEqual(
+                            expectedInet6Address.getScopedInterface(),
+                            deserializedIPV6Addr.getScopedInterface());
+                } else {
+                    assertNetworkInterfaceEqual(null,
+                            deserializedIPV6Addr.getScopedInterface());
+                }
+            } else { // use MockLo0Inet6Address
+                assertHostNameEqual(MockLo0Inet6Address.getHostName(),
+                        deserializedIPV6Addr.getHostName());
+                if (testWithNetIf) {
+                    assertHostAddressEqual(
+                            MockLo0Inet6Address.getHostAddress(),
+                            deserializedIPV6Addr.getHostAddress());
+                } else {
+                    assertHostAddressEqual(
+                            MockLo0Inet6Address.getHostAddressWithIndex(),
+                            deserializedIPV6Addr.getHostAddress());
+                }
+                assertAddressEqual(MockLo0Inet6Address.getAddress(),
+                        deserializedIPV6Addr.getAddress());
+                if (testWithNetIf) {
+                assertScopeIdEqual(MockLo0Inet6Address.getScopeId(),
+                        deserializedIPV6Addr.getScopeId());
+                } else {
+                    assertScopeIdEqual(MockLo0Inet6Address.getScopeZero(),
+                            deserializedIPV6Addr.getScopeId());
+                }
+                assertNetworkInterfaceNameEqual(
+                        MockLo0Inet6Address.getScopeIfName(),
+                        deserializedIPV6Addr.getScopedInterface());
+            }
+        } catch (Exception e) {
+            System.err.println("Exception caught during deserialization");
+            failed = true;
+            e.printStackTrace();
+        }
+    }
+
+    static List<Inet6Address> getAllInet6Addresses() throws Exception {
+        // System.err.println("\n getAllInet6Addresses: \n ");
+        ArrayList<Inet6Address> inet6Addresses = new ArrayList<Inet6Address>();
+        for (Enumeration<NetworkInterface> e = NetworkInterface
+                .getNetworkInterfaces(); e.hasMoreElements();) {
+            NetworkInterface netIF = e.nextElement();
+            for (Enumeration<InetAddress> iadrs = netIF.getInetAddresses(); iadrs
+                    .hasMoreElements();) {
+                InetAddress iadr = iadrs.nextElement();
+                if (iadr instanceof Inet6Address) {
+                    System.err.println("Test NetworkInterface:  " + netIF);
+                    Inet6Address i6adr = (Inet6Address) iadr;
+                    System.err.println(" address " + iadr);
+                    System.err.println(" scoped iface: "
+                            + i6adr.getScopedInterface());
+                    // using this to actually set the hostName for an
+                    // InetAddress
+                    // created through the NetworkInterface
+                    // have found that the fabricated instances has a null
+                    // hostName
+                    System.err.println(" hostName: " + i6adr.getHostName());
+                    inet6Addresses.add(i6adr);
+                }
+            }
+        }
+        return inet6Addresses;
+    }
+
+    static void assertHostNameEqual(String expectedHostName,
+            String deserializedHostName) {
+        System.err
+                .println("Inet6AddressSerializationTest.assertHostNameEqual:");
+        if (expectedHostName == null) {
+            if (deserializedHostName == null) {
+                // ok, do nothing.
+            } else {
+                System.err.println("Error checking " + " HostName, expected:"
+                        + expectedHostName + ", got :" + deserializedHostName);
+                failed = true;
+            }
+        } else if (!expectedHostName.equals(deserializedHostName)) {
+            System.err.println("Error checking "
+                    + // versionStr +
+                    " HostName, expected:" + expectedHostName + ", got :"
+                    + deserializedHostName);
+            failed = true;
+        } else {
+            System.err.println("HostName equality "
+                    + // versionStr +
+                    " HostName, expected:" + expectedHostName + ", got :"
+                    + deserializedHostName);
+        }
+    }
+
+    static void assertHostAddressEqual(String expectedHostAddress,
+            String deserializedHostAddress) {
+        System.err
+                .println("Inet6AddressSerializationTest.assertHostAddressEqual:");
+        if (expectedHostAddress == null) {
+            if (deserializedHostAddress == null) {
+                // ok, do nothing.
+            } else {
+                System.err.println("Error checking "
+                        + " HostAddress, expected: " + expectedHostAddress
+                        + ", got: " + deserializedHostAddress);
+                failed = true;
+            }
+        } else if (!expectedHostAddress.equals(deserializedHostAddress)) {
+            System.err.println("Error checking "
+                    + // versionStr +
+                    " HostAddress, expected: " + expectedHostAddress
+                    + ", got: " + deserializedHostAddress);
+            failed = true;
+        } else {
+            System.err.println("HostAddress equality "
+                    + // versionStr +
+                    " HostAddress, expected: " + expectedHostAddress
+                    + ", got: " + deserializedHostAddress);
+        }
+    }
+
+    static void assertAddressEqual(byte[] expectedAddress,
+            byte[] deserializedAddress) {
+        System.err.println("Inet6AddressSerializationTest.assertAddressEqual:");
+        if (expectedAddress == null) {
+            if (deserializedAddress == null) {
+                // ok, do nothing.
+            } else {
+                System.err.println("Error checking " + " Address, expected:"
+                        + Arrays.toString(expectedAddress) + ", got: "
+                        + Arrays.toString(deserializedAddress));
+                failed = true;
+            }
+        } else if (!Arrays.equals(expectedAddress, deserializedAddress)) {
+            System.err.println("Error checking "
+                    + // versionStr +
+                    " Address, expected: " + Arrays.toString(expectedAddress)
+                    + ", got: " + Arrays.toString(deserializedAddress));
+            failed = true;
+        } else {
+            System.err.println("Address equality "
+                    + // versionStr +
+                    " Address, expected: " + Arrays.toString(expectedAddress)
+                    + ", got: " + Arrays.toString(deserializedAddress));
+        }
+    }
+
+    static void assertScopeIdEqual(int expectedScopeId, int deserializedScopeId) {
+        System.err.println("Inet6AddressSerializationTest.assertScopeIdEqual:");
+        if (expectedScopeId != deserializedScopeId) {
+            System.err.println("Error checking " + " ScopeId, expected:"
+                    + expectedScopeId + ", got: " + deserializedScopeId);
+            failed = true;
+        } else {
+            System.err.println("ScopeId equality "
+                    + // versionStr +
+                    " ScopeId, expected: " + expectedScopeId + ", got: "
+                    + deserializedScopeId);
+        }
+    }
+
+    static void assertNetworkInterfaceNameEqual(String expectedNetworkIfName,
+            NetworkInterface deserializedNetworkInterface) {
+
+        if (deserializedNetworkInterface != null) {
+            String deserializedNetworkIfName = deserializedNetworkInterface
+                    .getName();
+            System.err
+                    .println("Inet6AddressSerializationTest.assertHostNameEqual:");
+            if (expectedNetworkIfName == null) {
+                if (deserializedNetworkIfName == null) {
+                    // ok, do nothing.
+                } else {
+                    System.err.println("Error checking "
+                            + " NetworkIfName, expected: "
+                            + expectedNetworkIfName + ", got: "
+                            + deserializedNetworkIfName);
+                    failed = true;
+                }
+            } else if (!expectedNetworkIfName.equals(deserializedNetworkIfName)) {
+                System.err.println("Error checking "
+                        + " NetworkIfName, expected: " + expectedNetworkIfName
+                        + ", got: " + deserializedNetworkIfName);
+                failed = true;
+            } else {
+                System.err.println("NetworkIfName equality "
+                        + " NetworkIfName, expected: " + expectedNetworkIfName
+                        + ", got: " + deserializedNetworkIfName);
+            }
+        } else {
+            System.err
+                    .println("Warning "
+                            + " NetworkInterface  expected, but is null - ifname not relevant on deserializing host");
+        }
+    }
+
+    static void assertNetworkInterfaceEqual(
+            NetworkInterface expectedNetworkInterface,
+            NetworkInterface deserializedNetworkInterface) {
+        System.err
+                .println("Inet6AddressSerializationTest.assertNetworkInterfaceEqual:");
+        if (expectedNetworkInterface == null) {
+            if (deserializedNetworkInterface == null) {
+                // ok, do nothing.
+                System.err.println("Network Interface equality "
+                        + " NetworkInterface, expected:"
+                        + expectedNetworkInterface + ", got :"
+                        + deserializedNetworkInterface);
+            } else {
+                System.err.println("Error checking "
+                        + " NetworkInterface, expected:"
+                        + expectedNetworkInterface + ", got :"
+                        + deserializedNetworkInterface);
+                failed = true;
+            }
+        } else if (!expectedNetworkInterface
+                .equals(deserializedNetworkInterface)) {
+            System.err.println("Error checking "
+                    + // versionStr +
+                    " NetworkInterface, expected:" + expectedNetworkInterface
+                    + ", got :" + deserializedNetworkInterface);
+            failed = true;
+        } else {
+            System.err.println("Network Interface equality "
+                    + " NetworkInterface, expected:" + expectedNetworkInterface
+                    + ", got :" + deserializedNetworkInterface);
+        }
+    }
+
+    static void equal(Object expected, Object got) {
+        if (expected == null) {
+            if (got == null) {
+                // ok, do nothing.
+            } else {
+                System.err.println("Error checking "
+                        + " serial data, expected:" + expected + ", got :"
+                        + got);
+                failed = true;
+            }
+        } else if (!expected.equals(got)) {
+            System.err.println("Error checking " + // versionStr +
+                    " serial data, expected:" + expected + ", got :" + got);
+            failed = true;
+        }
+    }
+
+    // Used to generate serialData.
+    static byte[] generateSerializedInet6AddressData(Inet6Address addr,
+            PrintStream out, boolean outputToFile) throws IOException {
+        ByteArrayOutputStream bos = new ByteArrayOutputStream();
+        try (ObjectOutputStream oos = new ObjectOutputStream(bos)) {
+            oos.writeObject(addr);
+        }
+
+        String ifname = getIfName(addr);
+        byte[] ba = bos.toByteArray();
+        if (out != null) {
+            out.format("static final byte[] SerialData" + ifname + " = {\n");
+            for (int i = 0; i < ba.length; i++) {
+                out.format(" (byte)0x%02X", ba[i]);
+                if (i != (ba.length - 1))
+                    out.format(",");
+                if (((i + 1) % 6) == 0)
+                    out.format("\n");
+            }
+            out.format(" };\n \n");
+        }
+        if (outputToFile) {
+            serializeInet6AddressToFile(addr);
+        }
+        return ba;
+    }
+
+    private static String getIfName(Inet6Address inet6Addr) {
+        String ifname;
+        if (inet6Addr.getScopedInterface() != null) {
+            ifname = "_ifname_" + inet6Addr.getScopedInterface().getName();
+        } else {
+            ifname = "_ifname_"
+                    + Integer.valueOf(inet6Addr.getScopeId()).toString();
+        }
+        return ifname;
+    }
+
+    static void generateAllInet6AddressSerializedData() throws IOException {
+        // System.err.println("generateAllInet6AddressSerializedData: enter ....");
+
+        List<Inet6Address> inet6Addresses;
+
+        try {
+            inet6Addresses = getAllInet6Addresses();
+        } catch (Exception e) {
+            e.printStackTrace();
+            throw new IOException(e);
+        }
+
+        for (Inet6Address inet6Address : inet6Addresses) {
+            generateSerializedInet6AddressData(inet6Address, System.out, true);
+        }
+    }
+
+    static void serializeInet6AddressToFile(Inet6Address inet6Addr) {
+
+        // System.err
+        // .println("serializeInet6AddressToIPV6AddressFile: enter ....");
+
+        FileOutputStream fOut = null;
+        String inet6AddressOutputFilename = null;
+        inet6AddressOutputFilename = createOutputFileName(inet6Addr);
+        try {
+            fOut = new FileOutputStream(inet6AddressOutputFilename);
+        } catch (FileNotFoundException fnfEx) {
+
+            fnfEx.printStackTrace();
+        }
+        ObjectOutputStream ooStream = null;
+        try {
+            if (fOut != null) {
+                ooStream = new ObjectOutputStream(fOut);
+            } else {
+                System.err.println("Problem initilising Object output stream ");
+                System.exit(-1);
+            }
+
+        } catch (IOException e) {
+            e.printStackTrace();
+            System.exit(-1);
+        }
+
+        // serialise the last Inet6Address
+        /*
+         * System.err
+         * .println("serializeInet6AddressToIPV6AddressFile scoped iface:  \n" +
+         * inet6Addr.getScopedInterface());
+         */
+        try {
+            ooStream.writeObject(inet6Addr);
+        } catch (Exception ex) {
+            ex.printStackTrace();
+            System.exit(-1);
+        }
+
+        try {
+            ooStream.close();
+        } catch (IOException e) {
+            e.printStackTrace();
+        }
+    }
+
+    private static String createOutputFileName(Inet6Address inet6Addr) {
+        String inet6AddressOutputFilename;
+        if (inet6Addr.getScopedInterface() != null) {
+            inet6AddressOutputFilename = "IPV6Address_"
+                    + inet6Addr.getScopedInterface().getName() + ".out";
+        } else {
+            inet6AddressOutputFilename = "IPV6Address_"
+                    + Integer.valueOf(inet6Addr.getScopeId()).toString()
+                    + ".out";
+        }
+        return inet6AddressOutputFilename;
+    }
+
+    // --- Generated data ---
+    // JDK7 output java Inet6AddressSerializationTest generate.
+
+    // loopback lo0 interface on Solaris 10
+
+    static final byte[] JDK7Inet6AddressSerialData = { (byte) 0xAC,
+            (byte) 0xED, (byte) 0x00, (byte) 0x05, (byte) 0x73, (byte) 0x72,
+            (byte) 0x00, (byte) 0x15, (byte) 0x6A, (byte) 0x61, (byte) 0x76,
+            (byte) 0x61, (byte) 0x2E, (byte) 0x6E, (byte) 0x65, (byte) 0x74,
+            (byte) 0x2E, (byte) 0x49, (byte) 0x6E, (byte) 0x65, (byte) 0x74,
+            (byte) 0x36, (byte) 0x41, (byte) 0x64, (byte) 0x64, (byte) 0x72,
+            (byte) 0x65, (byte) 0x73, (byte) 0x73, (byte) 0x5F, (byte) 0x7C,
+            (byte) 0x20, (byte) 0x81, (byte) 0x52, (byte) 0x2C, (byte) 0x80,
+            (byte) 0x21, (byte) 0x03, (byte) 0x00, (byte) 0x05, (byte) 0x49,
+            (byte) 0x00, (byte) 0x08, (byte) 0x73, (byte) 0x63, (byte) 0x6F,
+            (byte) 0x70, (byte) 0x65, (byte) 0x5F, (byte) 0x69, (byte) 0x64,
+            (byte) 0x5A, (byte) 0x00, (byte) 0x0C, (byte) 0x73, (byte) 0x63,
+            (byte) 0x6F, (byte) 0x70, (byte) 0x65, (byte) 0x5F, (byte) 0x69,
+            (byte) 0x64, (byte) 0x5F, (byte) 0x73, (byte) 0x65, (byte) 0x74,
+            (byte) 0x5A, (byte) 0x00, (byte) 0x10, (byte) 0x73, (byte) 0x63,
+            (byte) 0x6F, (byte) 0x70, (byte) 0x65, (byte) 0x5F, (byte) 0x69,
+            (byte) 0x66, (byte) 0x6E, (byte) 0x61, (byte) 0x6D, (byte) 0x65,
+            (byte) 0x5F, (byte) 0x73, (byte) 0x65, (byte) 0x74, (byte) 0x4C,
+            (byte) 0x00, (byte) 0x06, (byte) 0x69, (byte) 0x66, (byte) 0x6E,
+            (byte) 0x61, (byte) 0x6D, (byte) 0x65, (byte) 0x74, (byte) 0x00,
+            (byte) 0x12, (byte) 0x4C, (byte) 0x6A, (byte) 0x61, (byte) 0x76,
+            (byte) 0x61, (byte) 0x2F, (byte) 0x6C, (byte) 0x61, (byte) 0x6E,
+            (byte) 0x67, (byte) 0x2F, (byte) 0x53, (byte) 0x74, (byte) 0x72,
+            (byte) 0x69, (byte) 0x6E, (byte) 0x67, (byte) 0x3B, (byte) 0x5B,
+            (byte) 0x00, (byte) 0x09, (byte) 0x69, (byte) 0x70, (byte) 0x61,
+            (byte) 0x64, (byte) 0x64, (byte) 0x72, (byte) 0x65, (byte) 0x73,
+            (byte) 0x73, (byte) 0x74, (byte) 0x00, (byte) 0x02, (byte) 0x5B,
+            (byte) 0x42, (byte) 0x78, (byte) 0x72, (byte) 0x00, (byte) 0x14,
+            (byte) 0x6A, (byte) 0x61, (byte) 0x76, (byte) 0x61, (byte) 0x2E,
+            (byte) 0x6E, (byte) 0x65, (byte) 0x74, (byte) 0x2E, (byte) 0x49,
+            (byte) 0x6E, (byte) 0x65, (byte) 0x74, (byte) 0x41, (byte) 0x64,
+            (byte) 0x64, (byte) 0x72, (byte) 0x65, (byte) 0x73, (byte) 0x73,
+            (byte) 0x2D, (byte) 0x9B, (byte) 0x57, (byte) 0xAF, (byte) 0x9F,
+            (byte) 0xE3, (byte) 0xEB, (byte) 0xDB, (byte) 0x02, (byte) 0x00,
+            (byte) 0x03, (byte) 0x49, (byte) 0x00, (byte) 0x07, (byte) 0x61,
+            (byte) 0x64, (byte) 0x64, (byte) 0x72, (byte) 0x65, (byte) 0x73,
+            (byte) 0x73, (byte) 0x49, (byte) 0x00, (byte) 0x06, (byte) 0x66,
+            (byte) 0x61, (byte) 0x6D, (byte) 0x69, (byte) 0x6C, (byte) 0x79,
+            (byte) 0x4C, (byte) 0x00, (byte) 0x08, (byte) 0x68, (byte) 0x6F,
+            (byte) 0x73, (byte) 0x74, (byte) 0x4E, (byte) 0x61, (byte) 0x6D,
+            (byte) 0x65, (byte) 0x71, (byte) 0x00, (byte) 0x7E, (byte) 0x00,
+            (byte) 0x01, (byte) 0x78, (byte) 0x70, (byte) 0x00, (byte) 0x00,
+            (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00,
+            (byte) 0x02, (byte) 0x74, (byte) 0x00, (byte) 0x09, (byte) 0x6C,
+            (byte) 0x6F, (byte) 0x63, (byte) 0x61, (byte) 0x6C, (byte) 0x68,
+            (byte) 0x6F, (byte) 0x73, (byte) 0x74, (byte) 0x00, (byte) 0x00,
+            (byte) 0x00, (byte) 0x00, (byte) 0x01, (byte) 0x00, (byte) 0x70,
+            (byte) 0x75, (byte) 0x72, (byte) 0x00, (byte) 0x02, (byte) 0x5B,
+            (byte) 0x42, (byte) 0xAC, (byte) 0xF3, (byte) 0x17, (byte) 0xF8,
+            (byte) 0x06, (byte) 0x08, (byte) 0x54, (byte) 0xE0, (byte) 0x02,
+            (byte) 0x00, (byte) 0x00, (byte) 0x78, (byte) 0x70, (byte) 0x00,
+            (byte) 0x00, (byte) 0x00, (byte) 0x10, (byte) 0x00, (byte) 0x00,
+            (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00,
+            (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00,
+            (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x01, (byte) 0x78 };
+
+    // JDK8 output java Inet6AddressSerializationTest generate.
+    // loopback lo0 interface on Solaris 10
+
+    static final byte[] JDK8Inet6AddressSerialData = { (byte) 0xAC,
+            (byte) 0xED, (byte) 0x00, (byte) 0x05, (byte) 0x73, (byte) 0x72,
+            (byte) 0x00, (byte) 0x15, (byte) 0x6A, (byte) 0x61, (byte) 0x76,
+            (byte) 0x61, (byte) 0x2E, (byte) 0x6E, (byte) 0x65, (byte) 0x74,
+            (byte) 0x2E, (byte) 0x49, (byte) 0x6E, (byte) 0x65, (byte) 0x74,
+            (byte) 0x36, (byte) 0x41, (byte) 0x64, (byte) 0x64, (byte) 0x72,
+            (byte) 0x65, (byte) 0x73, (byte) 0x73, (byte) 0x5F, (byte) 0x7C,
+            (byte) 0x20, (byte) 0x81, (byte) 0x52, (byte) 0x2C, (byte) 0x80,
+            (byte) 0x21, (byte) 0x03, (byte) 0x00, (byte) 0x05, (byte) 0x49,
+            (byte) 0x00, (byte) 0x08, (byte) 0x73, (byte) 0x63, (byte) 0x6F,
+            (byte) 0x70, (byte) 0x65, (byte) 0x5F, (byte) 0x69, (byte) 0x64,
+            (byte) 0x5A, (byte) 0x00, (byte) 0x0C, (byte) 0x73, (byte) 0x63,
+            (byte) 0x6F, (byte) 0x70, (byte) 0x65, (byte) 0x5F, (byte) 0x69,
+            (byte) 0x64, (byte) 0x5F, (byte) 0x73, (byte) 0x65, (byte) 0x74,
+            (byte) 0x5A, (byte) 0x00, (byte) 0x10, (byte) 0x73, (byte) 0x63,
+            (byte) 0x6F, (byte) 0x70, (byte) 0x65, (byte) 0x5F, (byte) 0x69,
+            (byte) 0x66, (byte) 0x6E, (byte) 0x61, (byte) 0x6D, (byte) 0x65,
+            (byte) 0x5F, (byte) 0x73, (byte) 0x65, (byte) 0x74, (byte) 0x4C,
+            (byte) 0x00, (byte) 0x06, (byte) 0x69, (byte) 0x66, (byte) 0x6E,
+            (byte) 0x61, (byte) 0x6D, (byte) 0x65, (byte) 0x74, (byte) 0x00,
+            (byte) 0x12, (byte) 0x4C, (byte) 0x6A, (byte) 0x61, (byte) 0x76,
+            (byte) 0x61, (byte) 0x2F, (byte) 0x6C, (byte) 0x61, (byte) 0x6E,
+            (byte) 0x67, (byte) 0x2F, (byte) 0x53, (byte) 0x74, (byte) 0x72,
+            (byte) 0x69, (byte) 0x6E, (byte) 0x67, (byte) 0x3B, (byte) 0x5B,
+            (byte) 0x00, (byte) 0x09, (byte) 0x69, (byte) 0x70, (byte) 0x61,
+            (byte) 0x64, (byte) 0x64, (byte) 0x72, (byte) 0x65, (byte) 0x73,
+            (byte) 0x73, (byte) 0x74, (byte) 0x00, (byte) 0x02, (byte) 0x5B,
+            (byte) 0x42, (byte) 0x78, (byte) 0x72, (byte) 0x00, (byte) 0x14,
+            (byte) 0x6A, (byte) 0x61, (byte) 0x76, (byte) 0x61, (byte) 0x2E,
+            (byte) 0x6E, (byte) 0x65, (byte) 0x74, (byte) 0x2E, (byte) 0x49,
+            (byte) 0x6E, (byte) 0x65, (byte) 0x74, (byte) 0x41, (byte) 0x64,
+            (byte) 0x64, (byte) 0x72, (byte) 0x65, (byte) 0x73, (byte) 0x73,
+            (byte) 0x2D, (byte) 0x9B, (byte) 0x57, (byte) 0xAF, (byte) 0x9F,
+            (byte) 0xE3, (byte) 0xEB, (byte) 0xDB, (byte) 0x02, (byte) 0x00,
+            (byte) 0x03, (byte) 0x49, (byte) 0x00, (byte) 0x07, (byte) 0x61,
+            (byte) 0x64, (byte) 0x64, (byte) 0x72, (byte) 0x65, (byte) 0x73,
+            (byte) 0x73, (byte) 0x49, (byte) 0x00, (byte) 0x06, (byte) 0x66,
+            (byte) 0x61, (byte) 0x6D, (byte) 0x69, (byte) 0x6C, (byte) 0x79,
+            (byte) 0x4C, (byte) 0x00, (byte) 0x08, (byte) 0x68, (byte) 0x6F,
+            (byte) 0x73, (byte) 0x74, (byte) 0x4E, (byte) 0x61, (byte) 0x6D,
+            (byte) 0x65, (byte) 0x71, (byte) 0x00, (byte) 0x7E, (byte) 0x00,
+            (byte) 0x01, (byte) 0x78, (byte) 0x70, (byte) 0x00, (byte) 0x00,
+            (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00,
+            (byte) 0x02, (byte) 0x74, (byte) 0x00, (byte) 0x09, (byte) 0x6C,
+            (byte) 0x6F, (byte) 0x63, (byte) 0x61, (byte) 0x6C, (byte) 0x68,
+            (byte) 0x6F, (byte) 0x73, (byte) 0x74, (byte) 0x00, (byte) 0x00,
+            (byte) 0x00, (byte) 0x00, (byte) 0x01, (byte) 0x00, (byte) 0x70,
+            (byte) 0x75, (byte) 0x72, (byte) 0x00, (byte) 0x02, (byte) 0x5B,
+            (byte) 0x42, (byte) 0xAC, (byte) 0xF3, (byte) 0x17, (byte) 0xF8,
+            (byte) 0x06, (byte) 0x08, (byte) 0x54, (byte) 0xE0, (byte) 0x02,
+            (byte) 0x00, (byte) 0x00, (byte) 0x78, (byte) 0x70, (byte) 0x00,
+            (byte) 0x00, (byte) 0x00, (byte) 0x10, (byte) 0x00, (byte) 0x00,
+            (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00,
+            (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00,
+            (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x01, (byte) 0x78 };
+
+    // java Inet6AddressSerializationTest generateAll produces this inet6address
+    // serial data
+    // jdk8 generated serialization of on address fe80:0:0:0:21b:24ff:febd:f29c
+    // net if e1000g0
+
+    static final byte[] SerialData_ifname_e1000g0 = { (byte) 0xAC, (byte) 0xED,
+            (byte) 0x00, (byte) 0x05, (byte) 0x73, (byte) 0x72, (byte) 0x00,
+            (byte) 0x15, (byte) 0x6A, (byte) 0x61, (byte) 0x76, (byte) 0x61,
+            (byte) 0x2E, (byte) 0x6E, (byte) 0x65, (byte) 0x74, (byte) 0x2E,
+            (byte) 0x49, (byte) 0x6E, (byte) 0x65, (byte) 0x74, (byte) 0x36,
+            (byte) 0x41, (byte) 0x64, (byte) 0x64, (byte) 0x72, (byte) 0x65,
+            (byte) 0x73, (byte) 0x73, (byte) 0x5F, (byte) 0x7C, (byte) 0x20,
+            (byte) 0x81, (byte) 0x52, (byte) 0x2C, (byte) 0x80, (byte) 0x21,
+            (byte) 0x03, (byte) 0x00, (byte) 0x05, (byte) 0x49, (byte) 0x00,
+            (byte) 0x08, (byte) 0x73, (byte) 0x63, (byte) 0x6F, (byte) 0x70,
+            (byte) 0x65, (byte) 0x5F, (byte) 0x69, (byte) 0x64, (byte) 0x5A,
+            (byte) 0x00, (byte) 0x0C, (byte) 0x73, (byte) 0x63, (byte) 0x6F,
+            (byte) 0x70, (byte) 0x65, (byte) 0x5F, (byte) 0x69, (byte) 0x64,
+            (byte) 0x5F, (byte) 0x73, (byte) 0x65, (byte) 0x74, (byte) 0x5A,
+            (byte) 0x00, (byte) 0x10, (byte) 0x73, (byte) 0x63, (byte) 0x6F,
+            (byte) 0x70, (byte) 0x65, (byte) 0x5F, (byte) 0x69, (byte) 0x66,
+            (byte) 0x6E, (byte) 0x61, (byte) 0x6D, (byte) 0x65, (byte) 0x5F,
+            (byte) 0x73, (byte) 0x65, (byte) 0x74, (byte) 0x4C, (byte) 0x00,
+            (byte) 0x06, (byte) 0x69, (byte) 0x66, (byte) 0x6E, (byte) 0x61,
+            (byte) 0x6D, (byte) 0x65, (byte) 0x74, (byte) 0x00, (byte) 0x12,
+            (byte) 0x4C, (byte) 0x6A, (byte) 0x61, (byte) 0x76, (byte) 0x61,
+            (byte) 0x2F, (byte) 0x6C, (byte) 0x61, (byte) 0x6E, (byte) 0x67,
+            (byte) 0x2F, (byte) 0x53, (byte) 0x74, (byte) 0x72, (byte) 0x69,
+            (byte) 0x6E, (byte) 0x67, (byte) 0x3B, (byte) 0x5B, (byte) 0x00,
+            (byte) 0x09, (byte) 0x69, (byte) 0x70, (byte) 0x61, (byte) 0x64,
+            (byte) 0x64, (byte) 0x72, (byte) 0x65, (byte) 0x73, (byte) 0x73,
+            (byte) 0x74, (byte) 0x00, (byte) 0x02, (byte) 0x5B, (byte) 0x42,
+            (byte) 0x78, (byte) 0x72, (byte) 0x00, (byte) 0x14, (byte) 0x6A,
+            (byte) 0x61, (byte) 0x76, (byte) 0x61, (byte) 0x2E, (byte) 0x6E,
+            (byte) 0x65, (byte) 0x74, (byte) 0x2E, (byte) 0x49, (byte) 0x6E,
+            (byte) 0x65, (byte) 0x74, (byte) 0x41, (byte) 0x64, (byte) 0x64,
+            (byte) 0x72, (byte) 0x65, (byte) 0x73, (byte) 0x73, (byte) 0x2D,
+            (byte) 0x9B, (byte) 0x57, (byte) 0xAF, (byte) 0x9F, (byte) 0xE3,
+            (byte) 0xEB, (byte) 0xDB, (byte) 0x02, (byte) 0x00, (byte) 0x03,
+            (byte) 0x49, (byte) 0x00, (byte) 0x07, (byte) 0x61, (byte) 0x64,
+            (byte) 0x64, (byte) 0x72, (byte) 0x65, (byte) 0x73, (byte) 0x73,
+            (byte) 0x49, (byte) 0x00, (byte) 0x06, (byte) 0x66, (byte) 0x61,
+            (byte) 0x6D, (byte) 0x69, (byte) 0x6C, (byte) 0x79, (byte) 0x4C,
+            (byte) 0x00, (byte) 0x08, (byte) 0x68, (byte) 0x6F, (byte) 0x73,
+            (byte) 0x74, (byte) 0x4E, (byte) 0x61, (byte) 0x6D, (byte) 0x65,
+            (byte) 0x71, (byte) 0x00, (byte) 0x7E, (byte) 0x00, (byte) 0x01,
+            (byte) 0x78, (byte) 0x70, (byte) 0x00, (byte) 0x00, (byte) 0x00,
+            (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x02,
+            (byte) 0x74, (byte) 0x00, (byte) 0x25, (byte) 0x66, (byte) 0x65,
+            (byte) 0x38, (byte) 0x30, (byte) 0x3A, (byte) 0x30, (byte) 0x3A,
+            (byte) 0x30, (byte) 0x3A, (byte) 0x30, (byte) 0x3A, (byte) 0x32,
+            (byte) 0x31, (byte) 0x62, (byte) 0x3A, (byte) 0x32, (byte) 0x34,
+            (byte) 0x66, (byte) 0x66, (byte) 0x3A, (byte) 0x66, (byte) 0x65,
+            (byte) 0x62, (byte) 0x64, (byte) 0x3A, (byte) 0x66, (byte) 0x32,
+            (byte) 0x39, (byte) 0x63, (byte) 0x25, (byte) 0x65, (byte) 0x31,
+            (byte) 0x30, (byte) 0x30, (byte) 0x30, (byte) 0x67, (byte) 0x30,
+            (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x02, (byte) 0x01,
+            (byte) 0x01, (byte) 0x74, (byte) 0x00, (byte) 0x07, (byte) 0x65,
+            (byte) 0x31, (byte) 0x30, (byte) 0x30, (byte) 0x30, (byte) 0x67,
+            (byte) 0x30, (byte) 0x75, (byte) 0x72, (byte) 0x00, (byte) 0x02,
+            (byte) 0x5B, (byte) 0x42, (byte) 0xAC, (byte) 0xF3, (byte) 0x17,
+            (byte) 0xF8, (byte) 0x06, (byte) 0x08, (byte) 0x54, (byte) 0xE0,
+            (byte) 0x02, (byte) 0x00, (byte) 0x00, (byte) 0x78, (byte) 0x70,
+            (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x10, (byte) 0xFE,
+            (byte) 0x80, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00,
+            (byte) 0x00, (byte) 0x00, (byte) 0x02, (byte) 0x1B, (byte) 0x24,
+            (byte) 0xFF, (byte) 0xFE, (byte) 0xBD, (byte) 0xF2, (byte) 0x9C,
+            (byte) 0x78 };
+
+    // jdk8 generated serialization of address 0::1 on net if lo0 hostname
+    // localhost scope_id 1
+
+    static final byte[] SerialData_ifname_lo0 = { (byte) 0xAC, (byte) 0xED,
+            (byte) 0x00, (byte) 0x05, (byte) 0x73, (byte) 0x72, (byte) 0x00,
+            (byte) 0x15, (byte) 0x6A, (byte) 0x61, (byte) 0x76, (byte) 0x61,
+            (byte) 0x2E, (byte) 0x6E, (byte) 0x65, (byte) 0x74, (byte) 0x2E,
+            (byte) 0x49, (byte) 0x6E, (byte) 0x65, (byte) 0x74, (byte) 0x36,
+            (byte) 0x41, (byte) 0x64, (byte) 0x64, (byte) 0x72, (byte) 0x65,
+            (byte) 0x73, (byte) 0x73, (byte) 0x5F, (byte) 0x7C, (byte) 0x20,
+            (byte) 0x81, (byte) 0x52, (byte) 0x2C, (byte) 0x80, (byte) 0x21,
+            (byte) 0x03, (byte) 0x00, (byte) 0x05, (byte) 0x49, (byte) 0x00,
+            (byte) 0x08, (byte) 0x73, (byte) 0x63, (byte) 0x6F, (byte) 0x70,
+            (byte) 0x65, (byte) 0x5F, (byte) 0x69, (byte) 0x64, (byte) 0x5A,
+            (byte) 0x00, (byte) 0x0C, (byte) 0x73, (byte) 0x63, (byte) 0x6F,
+            (byte) 0x70, (byte) 0x65, (byte) 0x5F, (byte) 0x69, (byte) 0x64,
+            (byte) 0x5F, (byte) 0x73, (byte) 0x65, (byte) 0x74, (byte) 0x5A,
+            (byte) 0x00, (byte) 0x10, (byte) 0x73, (byte) 0x63, (byte) 0x6F,
+            (byte) 0x70, (byte) 0x65, (byte) 0x5F, (byte) 0x69, (byte) 0x66,
+            (byte) 0x6E, (byte) 0x61, (byte) 0x6D, (byte) 0x65, (byte) 0x5F,
+            (byte) 0x73, (byte) 0x65, (byte) 0x74, (byte) 0x4C, (byte) 0x00,
+            (byte) 0x06, (byte) 0x69, (byte) 0x66, (byte) 0x6E, (byte) 0x61,
+            (byte) 0x6D, (byte) 0x65, (byte) 0x74, (byte) 0x00, (byte) 0x12,
+            (byte) 0x4C, (byte) 0x6A, (byte) 0x61, (byte) 0x76, (byte) 0x61,
+            (byte) 0x2F, (byte) 0x6C, (byte) 0x61, (byte) 0x6E, (byte) 0x67,
+            (byte) 0x2F, (byte) 0x53, (byte) 0x74, (byte) 0x72, (byte) 0x69,
+            (byte) 0x6E, (byte) 0x67, (byte) 0x3B, (byte) 0x5B, (byte) 0x00,
+            (byte) 0x09, (byte) 0x69, (byte) 0x70, (byte) 0x61, (byte) 0x64,
+            (byte) 0x64, (byte) 0x72, (byte) 0x65, (byte) 0x73, (byte) 0x73,
+            (byte) 0x74, (byte) 0x00, (byte) 0x02, (byte) 0x5B, (byte) 0x42,
+            (byte) 0x78, (byte) 0x72, (byte) 0x00, (byte) 0x14, (byte) 0x6A,
+            (byte) 0x61, (byte) 0x76, (byte) 0x61, (byte) 0x2E, (byte) 0x6E,
+            (byte) 0x65, (byte) 0x74, (byte) 0x2E, (byte) 0x49, (byte) 0x6E,
+            (byte) 0x65, (byte) 0x74, (byte) 0x41, (byte) 0x64, (byte) 0x64,
+            (byte) 0x72, (byte) 0x65, (byte) 0x73, (byte) 0x73, (byte) 0x2D,
+            (byte) 0x9B, (byte) 0x57, (byte) 0xAF, (byte) 0x9F, (byte) 0xE3,
+            (byte) 0xEB, (byte) 0xDB, (byte) 0x02, (byte) 0x00, (byte) 0x03,
+            (byte) 0x49, (byte) 0x00, (byte) 0x07, (byte) 0x61, (byte) 0x64,
+            (byte) 0x64, (byte) 0x72, (byte) 0x65, (byte) 0x73, (byte) 0x73,
+            (byte) 0x49, (byte) 0x00, (byte) 0x06, (byte) 0x66, (byte) 0x61,
+            (byte) 0x6D, (byte) 0x69, (byte) 0x6C, (byte) 0x79, (byte) 0x4C,
+            (byte) 0x00, (byte) 0x08, (byte) 0x68, (byte) 0x6F, (byte) 0x73,
+            (byte) 0x74, (byte) 0x4E, (byte) 0x61, (byte) 0x6D, (byte) 0x65,
+            (byte) 0x71, (byte) 0x00, (byte) 0x7E, (byte) 0x00, (byte) 0x01,
+            (byte) 0x78, (byte) 0x70, (byte) 0x00, (byte) 0x00, (byte) 0x00,
+            (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x02,
+            (byte) 0x74, (byte) 0x00, (byte) 0x09, (byte) 0x6C, (byte) 0x6F,
+            (byte) 0x63, (byte) 0x61, (byte) 0x6C, (byte) 0x68, (byte) 0x6F,
+            (byte) 0x73, (byte) 0x74, (byte) 0x00, (byte) 0x00, (byte) 0x00,
+            (byte) 0x01, (byte) 0x01, (byte) 0x01, (byte) 0x74, (byte) 0x00,
+            (byte) 0x03, (byte) 0x6C, (byte) 0x6F, (byte) 0x30, (byte) 0x75,
+            (byte) 0x72, (byte) 0x00, (byte) 0x02, (byte) 0x5B, (byte) 0x42,
+            (byte) 0xAC, (byte) 0xF3, (byte) 0x17, (byte) 0xF8, (byte) 0x06,
+            (byte) 0x08, (byte) 0x54, (byte) 0xE0, (byte) 0x02, (byte) 0x00,
+            (byte) 0x00, (byte) 0x78, (byte) 0x70, (byte) 0x00, (byte) 0x00,
+            (byte) 0x00, (byte) 0x10, (byte) 0x00, (byte) 0x00, (byte) 0x00,
+            (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00,
+            (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00,
+            (byte) 0x00, (byte) 0x00, (byte) 0x01, (byte) 0x78 };
+
+}
+
+class MockLo0Inet6Address {
+
+    private static final byte[] LOOPBACKIPV6ADDRESS = { (byte) 0x00,
+            (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00,
+            (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00,
+            (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x01 };
+
+    private static final String LOCALHOSTNAME = "localhost";
+
+    private static final String LO0HOSTADDRESS = "0:0:0:0:0:0:0:1%lo0";
+
+    private static final String BARE_LO0HOSTADDRESS = "0:0:0:0:0:0:0:1";
+
+    private static final String LO0HOSTADDRESS_WITHINDEX = "0:0:0:0:0:0:0:1%1";
+
+    private static final int SCOPE_ID_LO0 = 1;
+
+    private static final int SCOPE_ID_ZERO = 0;
+
+    public static final String NETWORK_IF_LO0 = "lo0";
+
+    static String getHostName() {
+        return LOCALHOSTNAME;
+    }
+
+    static String getHostAddress() {
+        return LO0HOSTADDRESS;
+    }
+
+    static String getBareHostAddress() {
+        return BARE_LO0HOSTADDRESS;
+    }
+
+    static String getHostAddressWithIndex() {
+        return LO0HOSTADDRESS_WITHINDEX;
+    }
+
+    static byte[] getAddress() {
+        return LOOPBACKIPV6ADDRESS;
+    }
+
+    static int getScopeId() {
+        return SCOPE_ID_LO0;
+    }
+
+    static int getScopeZero() {
+        return SCOPE_ID_ZERO;
+    }
+
+    static String getScopeIfName() {
+        return NETWORK_IF_LO0;
+    }
+
+}
+
+class MockE1000g0Inet6Address {
+
+    // fe80::21b:24ff:febd:f29c
+    private static final byte[] E1000G0IPV6ADDRESS = { (byte) 0xfe,
+            (byte) 0x80, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00,
+            (byte) 0x00, (byte) 0x00, (byte) 0x02, (byte) 0x1b, (byte) 0x24,
+            (byte) 0xff, (byte) 0xfe, (byte) 0xbd, (byte) 0xf2, (byte) 0x9c };
+
+    private static final String E1000G0HOSTNAME = "fe80:0:0:0:21b:24ff:febd:f29c%e1000g0";
+
+    private static final String BARE_E1000G0HOSTADDRESS = "fe80:0:0:0:21b:24ff:febd:f29c";
+
+    private static final String E1000G0HOSTADDRESS_WITHINDEX = "fe80:0:0:0:21b:24ff:febd:f29c%2";
+
+    private static final String E1000G0HOSTADDRESS = "fe80:0:0:0:21b:24ff:febd:f29c%e1000g0";
+
+    private static final String NETWORK_IF_E1000G0 = "e1000g0";
+
+    private static final int SCOPE_ID_E1000G0 = 2;
+
+    private static final int SCOPE_ID_ZERO = 0;
+
+    static String getHostName() {
+        return E1000G0HOSTNAME;
+    }
+
+    static String getHostAddress() {
+        return E1000G0HOSTADDRESS;
+    }
+
+    static String getHostAddressWithIndex() {
+        return E1000G0HOSTADDRESS_WITHINDEX;
+    }
+
+    static String getBareHostAddress() {
+        return BARE_E1000G0HOSTADDRESS;
+    }
+
+    static byte[] getAddress() {
+        return E1000G0IPV6ADDRESS;
+    }
+
+    static int getScopeId() {
+        return SCOPE_ID_E1000G0;
+    }
+
+    static int getScopeZero() {
+        return SCOPE_ID_ZERO;
+    }
+
+    static String getScopeIfName() {
+        return NETWORK_IF_E1000G0;
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/java/util/Arrays/SetAllTest.java	Tue Apr 30 12:32:49 2013 -0700
@@ -0,0 +1,281 @@
+/*
+ * Copyright (c) 2013, 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.
+ *
+ * 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.
+ */
+
+/*
+ * @test
+ * @bug 8012650
+ * @summary Unit test for setAll, parallelSetAll variants
+ * @run testng SetAllTest
+ */
+
+import org.testng.annotations.DataProvider;
+import org.testng.annotations.Test;
+
+import java.util.Arrays;
+import java.util.function.IntFunction;
+import java.util.function.IntToDoubleFunction;
+import java.util.function.IntToLongFunction;
+import java.util.function.IntUnaryOperator;
+
+import static org.testng.Assert.assertEquals;
+import static org.testng.Assert.assertTrue;
+import static org.testng.Assert.assertSame;
+import static org.testng.Assert.fail;
+
+@Test
+public class SetAllTest {
+    private static final IntFunction<String> toString = i -> "N" + Integer.valueOf(i);
+    private static final IntFunction<String> fillString = i -> "X";
+    private static final String[] r0 = {};
+    private static final String[] r1 = { "N0" };
+    private static final String[] r10 = { "N0", "N1", "N2", "N3", "N4", "N5", "N6", "N7", "N8", "N9" };
+
+    private Object[][] stringData = new Object[][] {
+        { "empty", 0, toString, r0 },
+        { "one", 1, toString, r1 },
+        { "ten", 10, toString, r10 },
+        { "fill", 3, fillString, new String[] { "X", "X", "X" }}
+    };
+
+    private static final IntUnaryOperator toInt = i -> i << 1;
+    private static final IntUnaryOperator fillInt = i -> 99;
+    private static final int[] ir0 = {};
+    private static final int[] ir1 = { 0 };
+    private static final int[] ir10 = { 0, 2, 4, 6, 8, 10, 12, 14, 16, 18 };
+    private Object[][] intData = new Object[][] {
+        { "empty", 0, toInt, ir0 },
+        { "one", 1, toInt, ir1 },
+        { "ten", 10, toInt, ir10 },
+        { "fill", 3, fillInt, new int[] { 99, 99, 99 }}
+    };
+
+    private static final IntToLongFunction toLong = i -> i << 1;
+    private static final IntToLongFunction fillLong = i -> 9999L;
+    private static final long[] lr0 = {};
+    private static final long[] lr1 = { 0L };
+    private static final long[] lr10 = { 0L, 2L, 4L, 6L, 8L, 10L, 12L, 14L, 16L, 18L };
+    private Object[][] longData = new Object[][] {
+        { "empty", 0, toLong, lr0 },
+        { "one", 1, toLong, lr1 },
+        { "ten", 10, toLong, lr10 },
+        { "fill", 3, fillLong, new long[] { 9999L, 9999L, 9999L }}
+    };
+
+    private static final IntToDoubleFunction toDouble = i -> i * 1.1;
+    private static final IntToDoubleFunction fillDouble = i -> 3.14;
+    private static final double[] dr0 = {};
+    private static final double[] dr1 = { 0.0 };
+    private static final double[] dr10 = { 0.0, 1.1, 2.2, 3.3, 4.4, 5.5, 6.6, 7.7, 8.8, 9.9 };
+    private Object[][] doubleData = new Object[][] {
+        { "empty", 0, toDouble, dr0 },
+        { "one", 1, toDouble, dr1 },
+        { "ten", 10, toDouble, dr10 },
+        { "fill", 3, fillDouble, new double[] { 3.14, 3.14, 3.14 }}
+    };
+
+    @DataProvider(name="string")
+    public Object[][] stringTests() { return stringData; }
+
+    @DataProvider(name="int")
+    public Object[][] intTests() { return intData; }
+
+    @DataProvider(name="long")
+    public Object[][] longTests() { return longData; }
+
+    @DataProvider(name="double")
+    public Object[][] doubleTests() { return doubleData; }
+
+    @Test(dataProvider = "string")
+    public void testSetAllString(String name, int size, IntFunction<String> generator, String[] expected) {
+        String[] result = new String[size];
+        Arrays.setAll(result, generator);
+        assertEquals(result, expected, "setAll(String[], IntFunction<String>) case " + name + " failed.");
+
+        // ensure fresh array
+        result = new String[size];
+        Arrays.parallelSetAll(result, generator);
+        assertEquals(result, expected, "parallelSetAll(String[], IntFunction<String>) case " + name + " failed.");
+    }
+
+    @Test(dataProvider = "int")
+    public void testSetAllInt(String name, int size, IntUnaryOperator generator, int[] expected) {
+        int[] result = new int[size];
+        Arrays.setAll(result, generator);
+        assertEquals(result, expected, "setAll(int[], IntUnaryOperator) case " + name + " failed.");
+
+        // ensure fresh array
+        result = new int[size];
+        Arrays.parallelSetAll(result, generator);
+        assertEquals(result, expected, "parallelSetAll(int[], IntUnaryOperator) case " + name + " failed.");
+    }
+
+    @Test(dataProvider = "long")
+    public void testSetAllLong(String name, int size, IntToLongFunction generator, long[] expected) {
+        long[] result = new long[size];
+        Arrays.setAll(result, generator);
+        assertEquals(result, expected, "setAll(long[], IntToLongFunction) case " + name + " failed.");
+
+        // ensure fresh array
+        result = new long[size];
+        Arrays.parallelSetAll(result, generator);
+        assertEquals(result, expected, "parallelSetAll(long[], IntToLongFunction) case " + name + " failed.");
+    }
+
+    private void assertDoubleArrayEquals(double[] actual, double[] expected, double delta, String msg) {
+        if (actual.length != expected.length) {
+            fail(msg + ": length mismatch, expected " + expected.length + ", got " + actual.length);
+        }
+
+        for (int i = 0; i < actual.length; i++) {
+            assertEquals(actual[i], expected[i], delta, msg + "(mismatch at index " + i + ")");
+        }
+    }
+
+    @Test(dataProvider = "double")
+    public void testSetAllDouble(String name, int size, IntToDoubleFunction generator, double[] expected) {
+        double[] result = new double[size];
+        Arrays.setAll(result, generator);
+        assertDoubleArrayEquals(result, expected, 0.05, "setAll(double[], IntToDoubleFunction) case " + name + " failed.");
+
+        // ensure fresh array
+        result = new double[size];
+        Arrays.parallelSetAll(result, generator);
+        assertDoubleArrayEquals(result, expected, 0.05, "setAll(double[], IntToDoubleFunction) case " + name + " failed.");
+    }
+
+    @Test
+    public void testStringSetNulls() {
+        String[] ar = new String[2];
+        try {
+            Arrays.setAll(null, i -> "X");
+            fail("Arrays.setAll(null, foo) should throw NPE");
+        } catch (NullPointerException npe) {
+            // expected
+        }
+        try {
+            Arrays.parallelSetAll(null, i -> "X");
+            fail("Arrays.parallelSetAll(null, foo) should throw NPE");
+        } catch (NullPointerException npe) {
+            // expected
+        }
+        try {
+            Arrays.setAll(ar, null);
+            fail("Arrays.setAll(array, null) should throw NPE");
+        } catch (NullPointerException npe) {
+            // expected
+        }
+        try {
+            Arrays.parallelSetAll(ar, null);
+            fail("Arrays.parallelSetAll(array, null) should throw NPE");
+        } catch (NullPointerException npe) {
+            // expected
+        }
+    }
+
+    @Test
+    public void testIntSetNulls() {
+        int[] ar = new int[2];
+        try {
+            Arrays.setAll(null, (IntUnaryOperator) i -> i);
+            fail("Arrays.setAll(null, foo) should throw NPE");
+        } catch (NullPointerException npe) {
+            // expected
+        }
+        try {
+            Arrays.parallelSetAll(null, (IntUnaryOperator) i -> i);
+            fail("Arrays.parallelSetAll(null, foo) should throw NPE");
+        } catch (NullPointerException npe) {
+            // expected
+        }
+        try {
+            Arrays.setAll(ar, null);
+            fail("Arrays.setAll(array, null) should throw NPE");
+        } catch (NullPointerException npe) {
+            // expected
+        }
+        try {
+            Arrays.parallelSetAll(ar, null);
+            fail("Arrays.parallelSetAll(array, null) should throw NPE");
+        } catch (NullPointerException npe) {
+            // expected
+        }
+    }
+
+    @Test
+    public void testLongSetNulls() {
+        long[] ar = new long[2];
+        try {
+            Arrays.setAll(null, (IntToLongFunction) i -> Long.MAX_VALUE);
+            fail("Arrays.setAll(null, foo) should throw NPE");
+        } catch (NullPointerException npe) {
+            // expected
+        }
+        try {
+            Arrays.parallelSetAll(null, (IntToLongFunction) i -> Long.MAX_VALUE);
+            fail("Arrays.parallelSetAll(null, foo) should throw NPE");
+        } catch (NullPointerException npe) {
+            // expected
+        }
+        try {
+            Arrays.setAll(ar, null);
+            fail("Arrays.setAll(array, null) should throw NPE");
+        } catch (NullPointerException npe) {
+            // expected
+        }
+        try {
+            Arrays.parallelSetAll(ar, null);
+            fail("Arrays.parallelSetAll(array, null) should throw NPE");
+        } catch (NullPointerException npe) {
+            // expected
+        }
+    }
+
+    @Test
+    public void testDoubleSetNulls() {
+        double[] ar = new double[2];
+        try {
+            Arrays.setAll(null, (IntToDoubleFunction) i -> Math.E);
+            fail("Arrays.setAll(null, foo) should throw NPE");
+        } catch (NullPointerException npe) {
+            // expected
+        }
+        try {
+            Arrays.parallelSetAll(null, (IntToDoubleFunction) i -> Math.E);
+            fail("Arrays.parallelSetAll(null, foo) should throw NPE");
+        } catch (NullPointerException npe) {
+            // expected
+        }
+        try {
+            Arrays.setAll(ar, null);
+            fail("Arrays.setAll(array, null) should throw NPE");
+        } catch (NullPointerException npe) {
+            // expected
+        }
+        try {
+            Arrays.parallelSetAll(ar, null);
+            fail("Arrays.parallelSetAll(array, null) should throw NPE");
+        } catch (NullPointerException npe) {
+            // expected
+        }
+    }
+}
\ No newline at end of file