--- a/jdk/src/share/classes/java/net/Inet6Address.java Tue Apr 30 12:31:51 2013 -0700
+++ b/jdk/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/jdk/src/share/classes/java/sql/Driver.java Tue Apr 30 12:31:51 2013 -0700
+++ b/jdk/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/jdk/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/jdk/src/share/classes/java/sql/DriverManager.java Tue Apr 30 12:31:51 2013 -0700
+++ b/jdk/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/jdk/src/share/classes/java/sql/SQLPermission.java Tue Apr 30 12:31:51 2013 -0700
+++ b/jdk/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/jdk/src/share/classes/java/util/Arrays.java Tue Apr 30 12:31:51 2013 -0700
+++ b/jdk/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 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 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
- * @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
+ * @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 Spliterator.OfDouble spliterator(double[] array, int fromIndex, int toIndex) {
- return Spliterators.spliterator(array, fromIndex, toIndex,
- Spliterator.ORDERED | Spliterator.IMMUTABLE);
+ 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/jdk/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/jdk/src/share/classes/java/util/stream/DoubleStream.java Tue Apr 30 12:31:51 2013 -0700
+++ b/jdk/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/jdk/src/share/classes/java/util/stream/IntStream.java Tue Apr 30 12:31:51 2013 -0700
+++ b/jdk/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/jdk/src/share/classes/java/util/stream/LongStream.java Tue Apr 30 12:31:51 2013 -0700
+++ b/jdk/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/jdk/src/share/classes/java/util/stream/Stream.java Tue Apr 30 12:31:51 2013 -0700
+++ b/jdk/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/jdk/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/jdk/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/jdk/src/share/classes/sun/management/AgentConfigurationError.java Tue Apr 30 12:31:51 2013 -0700
+++ b/jdk/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/jdk/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/jdk/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