You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@groovy.apache.org by em...@apache.org on 2021/04/28 21:05:21 UTC

[groovy] branch stream-dgms created (now bb452cb)

This is an automated email from the ASF dual-hosted git repository.

emilles pushed a change to branch stream-dgms
in repository https://gitbox.apache.org/repos/asf/groovy.git.


      at bb452cb  Move stream-related extension methods to StreamGroovyMethods

This branch includes the following new commits:

     new bb452cb  Move stream-related extension methods to StreamGroovyMethods

The 1 revisions listed above as "new" are entirely new to this
repository and will be described in separate emails.  The revisions
listed as "add" were already present in the repository and have only
been added to this reference.


[groovy] 01/01: Move stream-related extension methods to StreamGroovyMethods

Posted by em...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

emilles pushed a commit to branch stream-dgms
in repository https://gitbox.apache.org/repos/asf/groovy.git

commit bb452cb5df1663efde738db3bae3deb68ccf6020
Author: Eric Milles <er...@thomsonreuters.com>
AuthorDate: Wed Apr 28 16:04:39 2021 -0500

    Move stream-related extension methods to StreamGroovyMethods
---
 .../groovy/runtime/DefaultGroovyMethods.java       |  20 +-
 .../groovy/runtime/StreamGroovyMethods.java        | 486 ++++++++++++++
 .../typehandling/DefaultTypeTransformation.java    |   4 +-
 .../vmplugin/v8/PluginDefaultGroovyMethods.java    | 702 +++++----------------
 4 files changed, 645 insertions(+), 567 deletions(-)

diff --git a/src/main/java/org/codehaus/groovy/runtime/DefaultGroovyMethods.java b/src/main/java/org/codehaus/groovy/runtime/DefaultGroovyMethods.java
index c756d84..d58862c 100644
--- a/src/main/java/org/codehaus/groovy/runtime/DefaultGroovyMethods.java
+++ b/src/main/java/org/codehaus/groovy/runtime/DefaultGroovyMethods.java
@@ -219,15 +219,17 @@ public class DefaultGroovyMethods extends DefaultGroovyMethodsSupport {
             ProcessGroovyMethods.class,
             ResourceGroovyMethods.class,
             SocketGroovyMethods.class,
-            StringGroovyMethods.class//,
-            // Below are registered as module extension classes
-//            DateUtilExtensions.class,
-//            DateTimeStaticExtensions.class,
-//            DateTimeExtensions.class,
-//            SqlExtensions.class,
-//            SwingGroovyMethods.class,
-//            XmlExtensions.class,
-//            NioExtensions.class
+            StreamGroovyMethods.class,
+            StringGroovyMethods.class,
+            /* registered extensions:
+            DateUtilExtensions.class,
+            DateTimeExtensions.class,
+            DateTimeStaticExtensions.class,
+            NioExtensions.class,
+            SqlExtensions.class,
+            SwingGroovyMethods.class,
+            XmlExtensions.class,
+            */
     };
     private static final Object[] EMPTY_OBJECT_ARRAY = new Object[0];
     private static final NumberAwareComparator<Comparable> COMPARABLE_NUMBER_AWARE_COMPARATOR = new NumberAwareComparator<>();
diff --git a/src/main/java/org/codehaus/groovy/runtime/StreamGroovyMethods.java b/src/main/java/org/codehaus/groovy/runtime/StreamGroovyMethods.java
new file mode 100644
index 0000000..7ecfc19
--- /dev/null
+++ b/src/main/java/org/codehaus/groovy/runtime/StreamGroovyMethods.java
@@ -0,0 +1,486 @@
+package org.codehaus.groovy.runtime;
+
+import java.lang.reflect.Array;
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.Enumeration;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Optional;
+import java.util.OptionalDouble;
+import java.util.OptionalInt;
+import java.util.OptionalLong;
+import java.util.Set;
+import java.util.Spliterator;
+import java.util.Spliterators;
+import java.util.function.Consumer;
+import java.util.stream.BaseStream;
+import java.util.stream.Collectors;
+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;
+
+public class StreamGroovyMethods {
+
+    private StreamGroovyMethods() {
+    }
+
+    /**
+     * TODO
+     *
+     * <pre class="groovyTestCase">
+     * import java.util.stream.Stream
+     * assert (Stream.of(1) + Stream.&lt;Integer>empty()).toList() == [1]
+     * assert (Stream.of(1) + Stream.of(2)).toList() == [1,2]
+     * assert (Stream.of(1) + [2].stream()).toList() == [1,2]
+     * </pre>
+     *
+     * @since 4.0.0
+     */
+    public static <T> Stream<T> plus(final Stream<? extends T> lhs, final Stream<? extends T> rhs) {
+        return Stream.concat(lhs, rhs);
+    }
+
+    /**
+     * TODO
+     *
+     * <pre class="groovyTestCase">
+     * import java.util.stream.Stream
+     * assert (Stream.of(1) + [2]).toList() == [1,2]
+     * assert (Stream.of(1) + []).toList() == [1]
+     * </pre>
+     *
+     * @since 4.0.0
+     */
+    public static <T> Stream<T> plus(final Stream<? extends T> lhs, final Collection<? extends T> rhs) {
+        return Stream.concat(lhs, rhs.stream());
+    }
+
+    /**
+     * TODO
+     *
+     * <pre class="groovyTestCase">
+     * import java.util.stream.Stream
+     * assert (Stream.of(1) + [2]).toList() == [1,2]
+     * assert (Stream.of(1) + []).toList() == [1]
+     * </pre>
+     *
+     * @since 4.0.0
+     */
+    public static <T> Stream<T> plus(final Stream<? extends T> lhs, final Iterable<? extends T> rhs) {
+        return Stream.concat(lhs, stream(rhs));
+    }
+
+    //--------------------------------------------------------------------------
+
+    /**
+     * Returns a sequential {@link Stream} containing a single element.
+     *
+     * <pre class="groovyTestCase">
+     * def item = 'string'
+     * assert item.stream().toList() == ['string']
+     * assert item.stream().findFirst().isPresent()
+     * </pre>
+     *
+     * @since 3.0.0
+     */
+    public static <T> Stream<T> stream(final T self) {
+        return Stream.of(self);
+    }
+
+    /**
+     * Returns a sequential {@link Stream} with the specified array as its
+     * source.
+     *
+     * @param <T> The type of the array elements
+     * @param self The array, assumed to be unmodified during use
+     * @return a {@code Stream} for the array
+     *
+     * @since 2.5.0
+     */
+    public static <T> Stream<T> stream(final T[] self) {
+        return Arrays.stream(self);
+    }
+
+    /**
+     * Returns a sequential {@link Stream} with the specified array as its
+     * source.
+     *
+     * @param self The array, assumed to be unmodified during use
+     * @return a {@code Stream} for the array
+     *
+     * @since 2.5.0
+     */
+    public static Stream<Integer> stream(final int[] self) {
+        return Arrays.stream(self).boxed();
+    }
+
+    /**
+     * Returns a sequential {@link Stream} with the specified array as its
+     * source.
+     *
+     * @param self The array, assumed to be unmodified during use
+     * @return a {@code Stream} for the array
+     *
+     * @since 2.5.0
+     */
+    public static Stream<Long> stream(final long[] self) {
+        return Arrays.stream(self).boxed();
+    }
+
+    /**
+     * Returns a sequential {@link Stream} with the specified array as its
+     * source.
+     *
+     * @param self The array, assumed to be unmodified during use
+     * @return a {@code Stream} for the array
+     *
+     * @since 2.5.0
+     */
+    public static Stream<Double> stream(final double[] self) {
+        return Arrays.stream(self).boxed();
+    }
+
+    /**
+     * Returns a sequential {@link Stream} with the specified array as its
+     * source.
+     *
+     * @param self The array, assumed to be unmodified during use
+     * @return a {@code Stream} for the array
+     *
+     * @since 2.5.0
+     */
+    public static Stream<Character> stream(final char[] self) {
+        return IntStream.range(0, self.length).mapToObj(i -> self[i]);
+    }
+
+    /**
+     * Returns a sequential {@link Stream} with the specified array as its
+     * source.
+     *
+     * @param self The array, assumed to be unmodified during use
+     * @return a {@code Stream} for the array
+     *
+     * @since 2.5.0
+     */
+    public static Stream<Byte> stream(final byte[] self) {
+        return IntStream.range(0, self.length).mapToObj(i -> self[i]);
+    }
+
+    /**
+     * Returns a sequential {@link Stream} with the specified array as its
+     * source.
+     *
+     * @param self The array, assumed to be unmodified during use
+     * @return a {@code Stream} for the array
+     *
+     * @since 2.5.0
+     */
+    public static Stream<Short> stream(final short[] self) {
+        return IntStream.range(0, self.length).mapToObj(i -> self[i]);
+    }
+
+    /**
+     * Returns a sequential {@link Stream} with the specified array as its
+     * source.
+     *
+     * @param self The array, assumed to be unmodified during use
+     * @return a {@code Stream} for the array
+     *
+     * @since 2.5.0
+     */
+    public static Stream<Boolean> stream(final boolean[] self) {
+        return IntStream.range(0, self.length).mapToObj(i -> self[i]);
+    }
+
+    /**
+     * Returns a sequential {@link Stream} with the specified array as its
+     * source.
+     *
+     * @param self The array, assumed to be unmodified during use
+     * @return a {@code Stream} for the array
+     *
+     * @since 2.5.0
+     */
+    public static Stream<Float> stream(final float[] self) {
+        return IntStream.range(0, self.length).mapToObj(i -> self[i]);
+    }
+
+    /**
+     * Returns a sequential {@link Stream} with the specified element(s) as its
+     * source.
+     * <pre class="groovyTestCase">
+     * def tokens = new StringTokenizer('one two')
+     * assert tokens.stream().toList() == ['one', 'two']
+     * </pre>
+     *
+     * @since 3.0.0
+     */
+    public static <T> Stream<T> stream(final Enumeration<T> self) {
+        return stream(new Spliterators.AbstractSpliterator<T>(Long.MAX_VALUE, Spliterator.ORDERED) {
+            @Override
+            public void forEachRemaining(final Consumer<? super T> action) {
+                while (self.hasMoreElements()) {
+                    action.accept(self.nextElement());
+                }
+            }
+            @Override
+            public boolean tryAdvance(final Consumer<? super T> action) {
+                if (self.hasMoreElements()) {
+                    action.accept(self.nextElement());
+                    return true;
+                }
+                return false;
+            }
+        });
+    }
+
+    /**
+     * Returns a sequential {@link Stream} with the specified element(s) as its
+     * source.
+     *
+     * <pre class="groovyTestCase">
+     * class Items implements Iterable<String> {
+     *   Iterator&lt;String> iterator() {
+     *     ['one', 'two'].iterator()
+     *   }
+     * }
+     * def items = new Items()
+     * assert items.stream().toList() == ['one', 'two']
+     * </pre>
+     *
+     * @since 3.0.0
+     */
+    public static <T> Stream<T> stream(final Iterable<T> self) {
+        return StreamSupport.stream(self.spliterator(), false);
+    }
+
+    /**
+     * Returns a sequential {@link Stream} with the specified element(s) as its
+     * source.
+     *
+     * <pre class="groovyTestCase">
+     * [].iterator().stream().toList().isEmpty()
+     * ['one', 'two'].iterator().stream().toList() == ['one', 'two']
+     * </pre>
+     *
+     * @since 3.0.0
+     */
+    public static <T> Stream<T> stream(final Iterator<T> self) {
+        return stream(Spliterators.spliteratorUnknownSize(self, Spliterator.ORDERED));
+    }
+
+    /**
+     * Returns a sequential {@link Stream} with the specified element(s) as its
+     * source.
+     *
+     * <pre class="groovyTestCase">
+     * assert [].spliterator().stream().toList().isEmpty()
+     * assert ['one', 'two'].spliterator().stream().toList() == ['one', 'two']
+     * </pre>
+     *
+     * @since 3.0.0
+     */
+    public static <T> Stream<T> stream(final Spliterator<T> self) {
+        return StreamSupport.stream(self, false);
+    }
+
+    /**
+     * Returns an empty sequential {@link Stream}.
+     *
+     * <pre class="groovyTestCase">
+     * def item = null
+     * assert item.stream().toList() == []
+     * assert !item.stream().findFirst().isPresent()
+     * </pre>
+     *
+     * @since 3.0.0
+     */
+    public static <T> Stream<T> stream(final NullObject self) {
+        return Stream.empty();
+    }
+
+    /**
+     * If a value is present in the {@link Optional}, returns a {@link Stream}
+     * with the value as its source or else an empty stream.
+     *
+     * @since 3.0.0
+     */
+    public static <T> Stream<T> stream(final Optional<T> self) {
+        return self.map(Stream::of).orElseGet(Stream::empty);
+    }
+
+    //
+
+    /**
+     * If a value is present in the {@link OptionalInt}, returns an {@link IntStream}
+     * with the value as its source or else an empty stream.
+     *
+     * @since 3.0.0
+     */
+    public static IntStream stream(final OptionalInt self) {
+        if (!self.isPresent()) {
+            return IntStream.empty();
+        }
+        return IntStream.of(self.getAsInt());
+    }
+
+    /**
+     * If a value is present in the {@link OptionalLong}, returns a {@link LongStream}
+     * with the value as its source or else an empty stream.
+     *
+     * @since 3.0.0
+     */
+    public static LongStream stream(final OptionalLong self) {
+        if (!self.isPresent()) {
+            return LongStream.empty();
+        }
+        return LongStream.of(self.getAsLong());
+    }
+
+    /**
+     * If a value is present in the {@link OptionalDouble}, returns a {@link DoubleStream}
+     * with the value as its source or else an empty stream.
+     *
+     * @since 3.0.0
+     */
+    public static DoubleStream stream(final OptionalDouble self) {
+        if (!self.isPresent()) {
+            return DoubleStream.empty();
+        }
+        return DoubleStream.of(self.getAsDouble());
+    }
+
+    /**
+     * Returns a sequential {@link IntStream} with the specified array as its
+     * source.
+     *
+     * @param self The array, assumed to be unmodified during use
+     * @return a {@code Stream} for the array
+     *
+     * @since 3.0.8
+     */
+    public static IntStream intStream(final int[] self) {
+        return Arrays.stream(self);
+    }
+
+    /**
+     * Returns a sequential {@link LongStream} with the specified array as its
+     * source.
+     *
+     * @param self The array, assumed to be unmodified during use
+     * @return a {@code Stream} for the array
+     *
+     * @since 3.0.8
+     */
+    public static LongStream longStream(final long[] self) {
+        return Arrays.stream(self);
+    }
+
+    /**
+     * Returns a sequential {@link DoubleStream} with the specified array as its
+     * source.
+     *
+     * @param self The array, assumed to be unmodified during use
+     * @return a {@code Stream} for the array
+     *
+     * @since 3.0.8
+     */
+    public static DoubleStream doubleStream(final double[] self) {
+        return Arrays.stream(self);
+    }
+
+    //--------------------------------------------------------------------------
+
+    /**
+     * Returns an array containing the elements of the stream.
+     * <pre class="groovyTestCase">
+     * import static groovy.test.GroovyAssert.shouldFail
+     *
+     * assert Arrays.equals([].stream().toArray(Object), new Object[0])
+     * assert Arrays.equals([].stream().toArray(String), new String[0])
+     * assert Arrays.equals([].stream().toArray(String[]), new String[0][])
+     * assert Arrays.equals(['x'].stream().toArray(Object), ['x'].toArray())
+     * assert Arrays.equals(['x'].stream().toArray(String), ['x'] as String[])
+     * assert Arrays.deepEquals([['x'] as String[]].stream().toArray(String[]), [['x'] as String[]] as String[][])
+     * assert Arrays.equals(['x'].stream().toArray(CharSequence), ['x'] as CharSequence[])
+     *
+     * shouldFail(ArrayStoreException) {
+     *     ['x'].stream().toArray(Thread)
+     * }
+     *
+     * shouldFail(IllegalArgumentException) {
+     *     ['x'].stream().toArray((Class) null)
+     * }
+     *
+     * // Stream#toArray(IntFunction) should still be used for closure literal:
+     * assert Arrays.equals(['x'].stream().toArray { n -&gt; new String[n] }, ['x'] as String[])
+     *
+     * // Stream#toArray(IntFunction) should still be used for method reference:
+     * assert Arrays.equals(['x'].stream().toArray(String[]::new), ['x'] as String[])
+     * </pre>
+     *
+     * @param self the stream
+     * @param type the array element type
+     *
+     * @since 3.0.4
+     */
+    public static <T> T[] toArray(final Stream<? extends T> self, final Class<T> type) {
+        if (type == null) throw new IllegalArgumentException("type cannot be null");
+        return self.toArray(length -> (T[]) Array.newInstance(type, length));
+    }
+
+    /**
+     * Accumulates the elements of stream into a new List.
+     *
+     * @param self the stream
+     * @param <T> the type of element
+     * @return a new {@code java.util.List} instance
+     *
+     * @since 2.5.0
+     */
+    public static <T> List<T> toList(final Stream<T> self) {
+        return self.collect(Collectors.toList());
+    }
+
+    /**
+     * Accumulates the elements of stream into a new List.
+     *
+     * @param self the {@code java.util.stream.BaseStream}
+     * @param <T> the type of element
+     * @return a new {@code java.util.List} instance
+     *
+     * @since 2.5.0
+     */
+    public static <T> List<T> toList(final BaseStream<T, ? extends BaseStream> self) {
+        return stream(self.iterator()).collect(Collectors.toList());
+    }
+
+    /**
+     * Accumulates the elements of stream into a new Set.
+     *
+     * @param self the stream
+     * @param <T> the type of element
+     * @return a new {@code java.util.Set} instance
+     *
+     * @since 2.5.0
+     */
+    public static <T> Set<T> toSet(final Stream<T> self) {
+        return self.collect(Collectors.toSet());
+    }
+
+    /**
+     * Accumulates the elements of stream into a new Set.
+     *
+     * @param self the {@code java.util.stream.BaseStream}
+     * @param <T> the type of element
+     * @return a new {@code java.util.Set} instance
+     *
+     * @since 2.5.0
+     */
+    public static <T> Set<T> toSet(final BaseStream<T, ? extends BaseStream> self) {
+        return stream(self.iterator()).collect(Collectors.toSet());
+    }
+}
diff --git a/src/main/java/org/codehaus/groovy/runtime/typehandling/DefaultTypeTransformation.java b/src/main/java/org/codehaus/groovy/runtime/typehandling/DefaultTypeTransformation.java
index c96e4f9..503d782 100644
--- a/src/main/java/org/codehaus/groovy/runtime/typehandling/DefaultTypeTransformation.java
+++ b/src/main/java/org/codehaus/groovy/runtime/typehandling/DefaultTypeTransformation.java
@@ -30,8 +30,8 @@ import org.codehaus.groovy.runtime.IteratorClosureAdapter;
 import org.codehaus.groovy.runtime.MethodClosure;
 import org.codehaus.groovy.runtime.NullObject;
 import org.codehaus.groovy.runtime.ResourceGroovyMethods;
+import org.codehaus.groovy.runtime.StreamGroovyMethods;
 import org.codehaus.groovy.runtime.StringGroovyMethods;
-import org.codehaus.groovy.vmplugin.v8.PluginDefaultGroovyMethods;
 
 import java.io.File;
 import java.io.IOException;
@@ -476,7 +476,7 @@ public class DefaultTypeTransformation {
         } else if (value.getClass().isArray()) {
             return arrayAsCollection(value);
         } else if (value instanceof BaseStream) {
-            return PluginDefaultGroovyMethods.toList((BaseStream) value);
+            return StreamGroovyMethods.toList((BaseStream) value);
         } else if (value instanceof MethodClosure) {
             MethodClosure method = (MethodClosure) value;
             IteratorClosureAdapter adapter = new IteratorClosureAdapter(method.getDelegate());
diff --git a/src/main/java/org/codehaus/groovy/vmplugin/v8/PluginDefaultGroovyMethods.java b/src/main/java/org/codehaus/groovy/vmplugin/v8/PluginDefaultGroovyMethods.java
index 106d209..6ed4d6c 100644
--- a/src/main/java/org/codehaus/groovy/vmplugin/v8/PluginDefaultGroovyMethods.java
+++ b/src/main/java/org/codehaus/groovy/vmplugin/v8/PluginDefaultGroovyMethods.java
@@ -26,29 +26,19 @@ import groovy.transform.stc.ClosureParams;
 import groovy.transform.stc.FirstParam;
 import org.codehaus.groovy.runtime.DefaultGroovyMethodsSupport;
 import org.codehaus.groovy.runtime.InvokerHelper;
-import org.codehaus.groovy.runtime.NullObject;
 import org.codehaus.groovy.runtime.RangeInfo;
 
-import java.lang.management.ManagementFactory;
-import java.lang.reflect.Array;
 import java.lang.reflect.Method;
 import java.util.Arrays;
-import java.util.Enumeration;
-import java.util.Iterator;
-import java.util.List;
 import java.util.Objects;
 import java.util.Optional;
 import java.util.OptionalDouble;
 import java.util.OptionalInt;
 import java.util.OptionalLong;
-import java.util.Set;
-import java.util.Spliterator;
-import java.util.Spliterators;
 import java.util.concurrent.ExecutionException;
 import java.util.concurrent.Future;
 import java.util.concurrent.TimeUnit;
 import java.util.concurrent.TimeoutException;
-import java.util.function.Consumer;
 import java.util.function.DoubleFunction;
 import java.util.function.DoublePredicate;
 import java.util.function.IntFunction;
@@ -59,13 +49,6 @@ import java.util.function.Supplier;
 import java.util.function.ToDoubleFunction;
 import java.util.function.ToIntFunction;
 import java.util.function.ToLongFunction;
-import java.util.stream.BaseStream;
-import java.util.stream.Collectors;
-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;
 
 /**
  * Defines new Groovy methods which appear on standard Java 8 classes within the
@@ -75,10 +58,116 @@ import java.util.stream.StreamSupport;
  */
 public class PluginDefaultGroovyMethods extends DefaultGroovyMethodsSupport {
 
-    // No instances, static methods only
     private PluginDefaultGroovyMethods() {
     }
 
+    //--------------------------------------------------------------------------
+    // Enum
+
+    /**
+     * Overloads the {@code ++} operator for enums. It will invoke Groovy's
+     * default next behaviour for enums that do not have their own next method.
+     *
+     * @param self an Enum
+     * @return the next defined enum from the enum class
+     *
+     * @since 1.5.2
+     */
+    public static Object next(final Enum self) {
+        for (Method method : self.getClass().getMethods()) {
+            if (method.getName().equals("next") && method.getParameterCount() == 0) {
+                return InvokerHelper.invokeMethod(self, "next", InvokerHelper.EMPTY_ARGS);
+            }
+        }
+        Object[] values = (Object[]) InvokerHelper.invokeStaticMethod(self.getClass(), "values", InvokerHelper.EMPTY_ARGS);
+        int index = Arrays.asList(values).indexOf(self);
+        return values[index < values.length - 1 ? index + 1 : 0];
+    }
+
+    /**
+     * Overloads the {@code --} operator for enums. It will invoke Groovy's
+     * default previous behaviour for enums that do not have their own previous method.
+     *
+     * @param self an Enum
+     * @return the previous defined enum from the enum class
+     *
+     * @since 1.5.2
+     */
+    public static Object previous(final Enum self) {
+        for (Method method : self.getClass().getMethods()) {
+            if (method.getName().equals("previous") && method.getParameterCount() == 0) {
+                return InvokerHelper.invokeMethod(self, "previous", InvokerHelper.EMPTY_ARGS);
+            }
+        }
+        Object[] values = (Object[]) InvokerHelper.invokeStaticMethod(self.getClass(), "values", InvokerHelper.EMPTY_ARGS);
+        int index = Arrays.asList(values).indexOf(self);
+        return values[index > 0 ? index - 1 : values.length - 1];
+    }
+
+    //--------------------------------------------------------------------------
+    // Future
+
+    /**
+     * Returns a Future asynchronously returning a transformed result.
+     * <pre class="_temp_disabled_groovyTestCase">
+     * import java.util.concurrent.*
+     * def executor = Executors.newSingleThreadExecutor()
+     * Future<String> foobar = executor.submit{ "foobar" }
+     * Future<Integer> foobarSize = foobar.collect{ it.size() }
+     * assert foobarSize.get() == 6
+     * executor.shutdown()
+     * </pre>
+     *
+     * @param self      a Future
+     * @param transform the closure used to transform the Future value
+     * @return a Future allowing the transformed value to be obtained asynchronously
+     *
+     * @since 3.0.0
+     */
+    public static <S,T> Future<T> collect(final Future<S> self, @ClosureParams(FirstParam.FirstGenericType.class) final Closure<T> transform) {
+        Objects.requireNonNull(self);
+        Objects.requireNonNull(transform);
+        return new TransformedFuture<T>(self, transform);
+    }
+
+    private static class TransformedFuture<E> implements Future<E> {
+        private final Future delegate;
+        private final Closure<E> transform;
+
+        private TransformedFuture(final Future delegate, final Closure<E> transform) {
+            this.delegate = delegate;
+            this.transform = transform;
+        }
+
+        @Override
+        public boolean cancel(final boolean mayInterruptIfRunning) {
+            return delegate.cancel(mayInterruptIfRunning);
+        }
+
+        @Override
+        public boolean isCancelled() {
+            return delegate.isCancelled();
+        }
+
+        @Override
+        public boolean isDone() {
+            return delegate.isDone();
+        }
+
+        @Override
+        public E get() throws InterruptedException, ExecutionException {
+            return transform.call(delegate.get());
+        }
+
+        @Override
+        public E get(final long timeout, final TimeUnit unit) throws InterruptedException, ExecutionException, TimeoutException {
+            return transform.call(delegate.get(timeout, unit));
+        }
+    }
+
+    //--------------------------------------------------------------------------
+    // Optional
+
     /**
      * Coerce an {@code Optional} instance to a {@code boolean} value.
      * <pre class="groovyTestCase">
@@ -135,6 +224,26 @@ public class PluginDefaultGroovyMethods extends DefaultGroovyMethodsSupport {
     }
 
     /**
+     * If the optional contains a value, returns an optional containing the transformed value obtained using the <code>transform</code> closure
+     * or otherwise an empty optional.
+     * <pre class="groovyTestCase">
+     * assert Optional.of("foobar").collect{ it.size() }.get() == 6
+     * assert !Optional.empty().collect{ it.size() }.isPresent()
+     * </pre>
+     *
+     * @param self      an Optional
+     * @param transform the closure used to transform the optional value if present
+     * @return an Optional containing the transformed value or empty if the optional is empty or the transform returns null
+     *
+     * @since 3.0.0
+     */
+    public static <S,T> Optional<T> collect(final Optional<S> self, @ClosureParams(FirstParam.FirstGenericType.class) final Closure<T> transform) {
+        Objects.requireNonNull(self);
+        Objects.requireNonNull(transform);
+        return self.map(transform::call);
+    }
+
+    /**
      * Tests given value against specified type and changes generics of result.
      * This is equivalent to: <code>self.filter(it -&gt; it instanceof Type).map(it -&gt; (Type) it)</code>
      * <pre class="groovyTestCase">
@@ -310,87 +419,36 @@ public class PluginDefaultGroovyMethods extends DefaultGroovyMethodsSupport {
     }
 
     /**
-     * If the optional contains a value, returns an optional containing the transformed value obtained using the <code>transform</code> closure
-     * or otherwise an empty optional.
-     * <pre class="groovyTestCase">
-     * assert Optional.of("foobar").collect{ it.size() }.get() == 6
-     * assert !Optional.empty().collect{ it.size() }.isPresent()
-     * </pre>
-     *
-     * @param self      an Optional
-     * @param transform the closure used to transform the optional value if present
-     * @return an Optional containing the transformed value or empty if the optional is empty or the transform returns null
+     * Provide similar functionality to JDK9 {@code or} on JDK8.
      *
-     * @since 3.0.0
+     * @since 3.0.6
      */
-    public static <S,T> Optional<T> collect(final Optional<S> self, @ClosureParams(FirstParam.FirstGenericType.class) final Closure<T> transform) {
-        Objects.requireNonNull(self);
-        Objects.requireNonNull(transform);
-        return self.map(transform::call);
+    public static <T> Optional<T> orOptional(final Optional<T> self, final Supplier<? extends Optional<? extends T>> supplier) {
+        if (self.isPresent()) {
+            return self;
+        }
+        return (Optional<T>) supplier.get();
     }
 
-    /**
-     * Returns a Future asynchronously returning a transformed result.
-     * <pre class="_temp_disabled_groovyTestCase">
-     * import java.util.concurrent.*
-     * def executor = Executors.newSingleThreadExecutor()
-     * Future<String> foobar = executor.submit{ "foobar" }
-     * Future<Integer> foobarSize = foobar.collect{ it.size() }
-     * assert foobarSize.get() == 6
-     * executor.shutdown()
-     * </pre>
-     *
-     * @param self      a Future
-     * @param transform the closure used to transform the Future value
-     * @return a Future allowing the transformed value to be obtained asynchronously
-     *
-     * @since 3.0.0
-     */
-    public static <S,T> Future<T> collect(final Future<S> self, @ClosureParams(FirstParam.FirstGenericType.class) final Closure<T> transform) {
-        Objects.requireNonNull(self);
-        Objects.requireNonNull(transform);
-        return new TransformedFuture<T>(self, transform);
-    }
+    //--------------------------------------------------------------------------
+    // Runtime
 
     /**
-     * Overloads the {@code ++} operator for enums. It will invoke Groovy's
-     * default next behaviour for enums that do not have their own next method.
-     *
-     * @param self an Enum
-     * @return the next defined enum from the enum class
+     * Get the pid of the current Java process.
      *
-     * @since 1.5.2
+     * @since 4.0.0
      */
-    public static Object next(final Enum self) {
-        for (Method method : self.getClass().getMethods()) {
-            if (method.getName().equals("next") && method.getParameterCount() == 0) {
-                return InvokerHelper.invokeMethod(self, "next", InvokerHelper.EMPTY_ARGS);
-            }
+    public static String getPid(final Runtime self) {
+        String name = java.lang.management.ManagementFactory.getRuntimeMXBean().getName();
+        int index = name.indexOf('@');
+        if (index == -1) { // should never happen
+            return name;
         }
-        Object[] values = (Object[]) InvokerHelper.invokeStaticMethod(self.getClass(), "values", InvokerHelper.EMPTY_ARGS);
-        int index = Arrays.asList(values).indexOf(self);
-        return values[index < values.length - 1 ? index + 1 : 0];
+        return name.substring(0, index);
     }
 
-    /**
-     * Overloads the {@code --} operator for enums. It will invoke Groovy's
-     * default previous behaviour for enums that do not have their own previous method.
-     *
-     * @param self an Enum
-     * @return the previous defined enum from the enum class
-     *
-     * @since 1.5.2
-     */
-    public static Object previous(final Enum self) {
-        for (Method method : self.getClass().getMethods()) {
-            if (method.getName().equals("previous") && method.getParameterCount() == 0) {
-                return InvokerHelper.invokeMethod(self, "previous", InvokerHelper.EMPTY_ARGS);
-            }
-        }
-        Object[] values = (Object[]) InvokerHelper.invokeStaticMethod(self.getClass(), "values", InvokerHelper.EMPTY_ARGS);
-        int index = Arrays.asList(values).indexOf(self);
-        return values[index > 0 ? index - 1 : values.length - 1];
-    }
+    //--------------------------------------------------------------------------
+    // StringBuilder
 
     /**
      * Provides the standard Groovy <code>size()</code> method for <code>StringBuilder</code>.
@@ -471,472 +529,4 @@ public class PluginDefaultGroovyMethods extends DefaultGroovyMethodsSupport {
     public static String plus(final StringBuilder self, final String value) {
         return self + value;
     }
-
-    private static class TransformedFuture<E> implements Future<E> {
-        private final Future delegate;
-        private final Closure<E> transform;
-
-        private TransformedFuture(final Future delegate, final Closure<E> transform) {
-            this.delegate = delegate;
-            this.transform = transform;
-        }
-
-        @Override
-        public boolean cancel(final boolean mayInterruptIfRunning) {
-            return delegate.cancel(mayInterruptIfRunning);
-        }
-
-        @Override
-        public boolean isCancelled() {
-            return delegate.isCancelled();
-        }
-
-        @Override
-        public boolean isDone() {
-            return delegate.isDone();
-        }
-
-        @Override
-        public E get() throws InterruptedException, ExecutionException {
-            return transform.call(delegate.get());
-        }
-
-        @Override
-        public E get(final long timeout, final TimeUnit unit) throws InterruptedException, ExecutionException, TimeoutException {
-            return transform.call(delegate.get(timeout, unit));
-        }
-    }
-
-    /**
-     * Returns an array containing the elements of the stream.
-     * <pre class="groovyTestCase">
-     * import static groovy.test.GroovyAssert.shouldFail
-     *
-     * assert Arrays.equals([].stream().toArray(Object), new Object[0])
-     * assert Arrays.equals([].stream().toArray(String), new String[0])
-     * assert Arrays.equals([].stream().toArray(String[]), new String[0][])
-     * assert Arrays.equals(['x'].stream().toArray(Object), ['x'].toArray())
-     * assert Arrays.equals(['x'].stream().toArray(String), ['x'] as String[])
-     * assert Arrays.deepEquals([['x'] as String[]].stream().toArray(String[]), [['x'] as String[]] as String[][])
-     * assert Arrays.equals(['x'].stream().toArray(CharSequence), ['x'] as CharSequence[])
-     *
-     * shouldFail(ArrayStoreException) {
-     *     ['x'].stream().toArray(Thread)
-     * }
-     *
-     * shouldFail(IllegalArgumentException) {
-     *     ['x'].stream().toArray((Class) null)
-     * }
-     *
-     * // Stream#toArray(IntFunction) should still be used for closure literal:
-     * assert Arrays.equals(['x'].stream().toArray { n -&gt; new String[n] }, ['x'] as String[])
-     *
-     * // Stream#toArray(IntFunction) should still be used for method reference:
-     * assert Arrays.equals(['x'].stream().toArray(String[]::new), ['x'] as String[])
-     * </pre>
-     *
-     * @param self the stream
-     * @param type the array element type
-     *
-     * @since 3.0.4
-     */
-    public static <T> T[] toArray(final Stream<? extends T> self, final Class<T> type) {
-        if (type == null) throw new IllegalArgumentException("type cannot be null");
-        return self.toArray(length -> (T[]) Array.newInstance(type, length));
-    }
-
-    /**
-     * Accumulates the elements of stream into a new List.
-     *
-     * @param self the stream
-     * @param <T> the type of element
-     * @return a new {@code java.util.List} instance
-     *
-     * @since 2.5.0
-     */
-    public static <T> List<T> toList(final Stream<T> self) {
-        return self.collect(Collectors.toList());
-    }
-
-    /**
-     * Accumulates the elements of stream into a new Set.
-     *
-     * @param self the stream
-     * @param <T> the type of element
-     * @return a new {@code java.util.Set} instance
-     *
-     * @since 2.5.0
-     */
-    public static <T> Set<T> toSet(final Stream<T> self) {
-        return self.collect(Collectors.toSet());
-    }
-
-    /**
-     * Accumulates the elements of stream into a new List.
-     *
-     * @param self the {@code java.util.stream.BaseStream}
-     * @param <T> the type of element
-     * @return a new {@code java.util.List} instance
-     *
-     * @since 2.5.0
-     */
-    public static <T> List<T> toList(final BaseStream<T, ? extends BaseStream> self) {
-        return stream(self.iterator()).collect(Collectors.toList());
-    }
-
-    /**
-     * Accumulates the elements of stream into a new Set.
-     *
-     * @param self the {@code java.util.stream.BaseStream}
-     * @param <T> the type of element
-     * @return a new {@code java.util.Set} instance
-     *
-     * @since 2.5.0
-     */
-    public static <T> Set<T> toSet(final BaseStream<T, ? extends BaseStream> self) {
-        return stream(self.iterator()).collect(Collectors.toSet());
-    }
-
-    /**
-     * Returns an empty sequential {@link Stream}.
-     *
-     * <pre class="groovyTestCase">
-     * def item = null
-     * assert item.stream().toList() == []
-     * assert !item.stream().findFirst().isPresent()
-     * </pre>
-     *
-     * @since 3.0.0
-     */
-    public static <T> Stream<T> stream(final NullObject self) {
-        return Stream.empty();
-    }
-
-    /**
-     * Returns a sequential {@link Stream} containing a single element.
-     *
-     * <pre class="groovyTestCase">
-     * def item = 'string'
-     * assert item.stream().toList() == ['string']
-     * assert item.stream().findFirst().isPresent()
-     * </pre>
-     *
-     * @since 3.0.0
-     */
-    public static <T> Stream<T> stream(final T self) {
-        return Stream.of(self);
-    }
-
-    /**
-     * Returns a sequential {@link Stream} with the specified array as its
-     * source.
-     *
-     * @param <T> The type of the array elements
-     * @param self The array, assumed to be unmodified during use
-     * @return a {@code Stream} for the array
-     *
-     * @since 2.5.0
-     */
-    public static <T> Stream<T> stream(final T[] self) {
-        return Arrays.stream(self);
-    }
-
-    /**
-     * Returns a sequential {@link Stream} with the specified array as its
-     * source.
-     *
-     * @param self The array, assumed to be unmodified during use
-     * @return a {@code Stream} for the array
-     *
-     * @since 2.5.0
-     */
-    public static Stream<Integer> stream(final int[] self) {
-        return Arrays.stream(self).boxed();
-    }
-
-    /**
-     * Returns a sequential {@link IntStream} with the specified array as its
-     * source.
-     *
-     * @param self The array, assumed to be unmodified during use
-     * @return a {@code Stream} for the array
-     *
-     * @since 3.0.8
-     */
-    public static IntStream intStream(final int[] self) {
-        return Arrays.stream(self);
-    }
-
-    /**
-     * Returns a sequential {@link Stream} with the specified array as its
-     * source.
-     *
-     * @param self The array, assumed to be unmodified during use
-     * @return a {@code Stream} for the array
-     *
-     * @since 2.5.0
-     */
-    public static Stream<Long> stream(final long[] self) {
-        return Arrays.stream(self).boxed();
-    }
-
-    /**
-     * Returns a sequential {@link LongStream} with the specified array as its
-     * source.
-     *
-     * @param self The array, assumed to be unmodified during use
-     * @return a {@code Stream} for the array
-     *
-     * @since 3.0.8
-     */
-    public static LongStream longStream(final long[] self) {
-        return Arrays.stream(self);
-    }
-
-    /**
-     * Returns a sequential {@link Stream} with the specified array as its
-     * source.
-     *
-     * @param self The array, assumed to be unmodified during use
-     * @return a {@code Stream} for the array
-     *
-     * @since 2.5.0
-     */
-    public static Stream<Double> stream(final double[] self) {
-        return Arrays.stream(self).boxed();
-    }
-
-    /**
-     * Returns a sequential {@link DoubleStream} with the specified array as its
-     * source.
-     *
-     * @param self The array, assumed to be unmodified during use
-     * @return a {@code Stream} for the array
-     *
-     * @since 3.0.8
-     */
-    public static DoubleStream doubleStream(final double[] self) {
-        return Arrays.stream(self);
-    }
-
-    /**
-     * Returns a sequential {@link Stream} with the specified array as its
-     * source.
-     *
-     * @param self The array, assumed to be unmodified during use
-     * @return a {@code Stream} for the array
-     *
-     * @since 2.5.0
-     */
-    public static Stream<Character> stream(final char[] self) {
-        return IntStream.range(0, self.length).mapToObj(i -> self[i]);
-    }
-
-    /**
-     * Returns a sequential {@link Stream} with the specified array as its
-     * source.
-     *
-     * @param self The array, assumed to be unmodified during use
-     * @return a {@code Stream} for the array
-     *
-     * @since 2.5.0
-     */
-    public static Stream<Byte> stream(final byte[] self) {
-        return IntStream.range(0, self.length).mapToObj(i -> self[i]);
-    }
-
-    /**
-     * Returns a sequential {@link Stream} with the specified array as its
-     * source.
-     *
-     * @param self The array, assumed to be unmodified during use
-     * @return a {@code Stream} for the array
-     *
-     * @since 2.5.0
-     */
-    public static Stream<Short> stream(final short[] self) {
-        return IntStream.range(0, self.length).mapToObj(i -> self[i]);
-    }
-
-    /**
-     * Returns a sequential {@link Stream} with the specified array as its
-     * source.
-     *
-     * @param self The array, assumed to be unmodified during use
-     * @return a {@code Stream} for the array
-     *
-     * @since 2.5.0
-     */
-    public static Stream<Boolean> stream(final boolean[] self) {
-        return IntStream.range(0, self.length).mapToObj(i -> self[i]);
-    }
-
-    /**
-     * Returns a sequential {@link Stream} with the specified array as its
-     * source.
-     *
-     * @param self The array, assumed to be unmodified during use
-     * @return a {@code Stream} for the array
-     *
-     * @since 2.5.0
-     */
-    public static Stream<Float> stream(final float[] self) {
-        return IntStream.range(0, self.length).mapToObj(i -> self[i]);
-    }
-
-    /**
-     * Returns a sequential {@link Stream} with the specified element(s) as its
-     * source.
-     * <pre class="groovyTestCase">
-     * def tokens = new StringTokenizer('one two')
-     * assert tokens.stream().toList() == ['one', 'two']
-     * </pre>
-     *
-     * @since 3.0.0
-     */
-    public static <T> Stream<T> stream(final Enumeration<T> self) {
-        return stream(new Spliterators.AbstractSpliterator<T>(Long.MAX_VALUE, Spliterator.ORDERED) {
-            @Override
-            public void forEachRemaining(final Consumer<? super T> action) {
-                while (self.hasMoreElements()) {
-                    action.accept(self.nextElement());
-                }
-            }
-            @Override
-            public boolean tryAdvance(final Consumer<? super T> action) {
-                if (self.hasMoreElements()) {
-                    action.accept(self.nextElement());
-                    return true;
-                }
-                return false;
-            }
-        });
-    }
-
-    /**
-     * Returns a sequential {@link Stream} with the specified element(s) as its
-     * source.
-     *
-     * <pre class="groovyTestCase">
-     * class Items implements Iterable<String> {
-     *   Iterator<String> iterator() {
-     *     ['one', 'two'].iterator()
-     *   }
-     * }
-     * def items = new Items()
-     * assert items.stream().toList() == ['one', 'two']
-     * </pre>
-     *
-     * @since 3.0.0
-     */
-    public static <T> Stream<T> stream(final Iterable<T> self) {
-        return StreamSupport.stream(self.spliterator(), false);
-    }
-
-    /**
-     * Returns a sequential {@link Stream} with the specified element(s) as its
-     * source.
-     *
-     * <pre class="groovyTestCase">
-     * [].iterator().stream().toList().isEmpty()
-     * ['one', 'two'].iterator().stream().toList() == ['one', 'two']
-     * </pre>
-     *
-     * @since 3.0.0
-     */
-    public static <T> Stream<T> stream(final Iterator<T> self) {
-        return stream(Spliterators.spliteratorUnknownSize(self, Spliterator.ORDERED));
-    }
-
-    /**
-     * Returns a sequential {@link Stream} with the specified element(s) as its
-     * source.
-     *
-     * <pre class="groovyTestCase">
-     * assert [].spliterator().stream().toList().isEmpty()
-     * assert ['one', 'two'].spliterator().stream().toList() == ['one', 'two']
-     * </pre>
-     *
-     * @since 3.0.0
-     */
-    public static <T> Stream<T> stream(final Spliterator<T> self) {
-        return StreamSupport.stream(self, false);
-    }
-
-    /**
-     * If a value is present in the {@link Optional}, returns a {@link Stream}
-     * with the value as its source or else an empty stream.
-     *
-     * @since 3.0.0
-     */
-    public static <T> Stream<T> stream(final Optional<T> self) {
-        return self.map(Stream::of).orElseGet(Stream::empty);
-    }
-
-    /**
-     * If a value is present in the {@link OptionalInt}, returns an {@link IntStream}
-     * with the value as its source or else an empty stream.
-     *
-     * @since 3.0.0
-     */
-    public static IntStream stream(final OptionalInt self) {
-        if (!self.isPresent()) {
-            return IntStream.empty();
-        }
-        return IntStream.of(self.getAsInt());
-    }
-
-    /**
-     * If a value is present in the {@link OptionalLong}, returns a {@link LongStream}
-     * with the value as its source or else an empty stream.
-     *
-     * @since 3.0.0
-     */
-    public static LongStream stream(final OptionalLong self) {
-        if (!self.isPresent()) {
-            return LongStream.empty();
-        }
-        return LongStream.of(self.getAsLong());
-    }
-
-    /**
-     * If a value is present in the {@link OptionalDouble}, returns a {@link DoubleStream}
-     * with the value as its source or else an empty stream.
-     *
-     * @since 3.0.0
-     */
-    public static DoubleStream stream(final OptionalDouble self) {
-        if (!self.isPresent()) {
-            return DoubleStream.empty();
-        }
-        return DoubleStream.of(self.getAsDouble());
-    }
-
-    /**
-     * Provide similar functionality to JDK9 {@code or} on JDK8.
-     *
-     * @since 3.0.6
-     */
-    public static <T> Optional<T> orOptional(Optional<T> self, Supplier<? extends Optional<? extends T>> supplier) {
-        if (self.isPresent()) {
-            return self;
-        }
-        return (Optional<T>) supplier.get();
-    }
-
-    /**
-     * Get the pid of the current Java process
-     *
-     * @param self
-     * @return the pid
-     * @since 4.0.0
-     */
-    public static String getPid(Runtime self) {
-        String name = ManagementFactory.getRuntimeMXBean().getName();
-        int index = name.indexOf('@');
-        if (-1 == index) { // should never happen
-            return name;
-        }
-        return name.substring(0, index);
-    }
 }