8050820: Please add java.util.Optional.stream() to convert Optional<T> to Stream<T>
authorpsandoz
Mon, 02 Feb 2015 14:19:12 +0100
changeset 28754 8fe59917548d
parent 28753 764648da0e46
child 28755 204aa673becb
8050820: Please add java.util.Optional.stream() to convert Optional<T> to Stream<T> Reviewed-by: alundblad, forax, chegar, jrose
jdk/src/java.base/share/classes/java/util/Optional.java
jdk/src/java.base/share/classes/java/util/OptionalDouble.java
jdk/src/java.base/share/classes/java/util/OptionalInt.java
jdk/src/java.base/share/classes/java/util/OptionalLong.java
jdk/test/java/util/Optional/Basic.java
jdk/test/java/util/Optional/BasicDouble.java
jdk/test/java/util/Optional/BasicInt.java
jdk/test/java/util/Optional/BasicLong.java
--- a/jdk/src/java.base/share/classes/java/util/Optional.java	Mon Feb 02 14:19:00 2015 +0100
+++ b/jdk/src/java.base/share/classes/java/util/Optional.java	Mon Feb 02 14:19:12 2015 +0100
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2012, 2013, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2012, 2015, 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
@@ -28,6 +28,7 @@
 import java.util.function.Function;
 import java.util.function.Predicate;
 import java.util.function.Supplier;
+import java.util.stream.Stream;
 
 /**
  * A container object which may or may not contain a non-null value.
@@ -155,8 +156,9 @@
      * null
      */
     public void ifPresent(Consumer<? super T> consumer) {
-        if (value != null)
+        if (value != null) {
             consumer.accept(value);
+        }
     }
 
     /**
@@ -172,10 +174,11 @@
      */
     public Optional<T> filter(Predicate<? super T> predicate) {
         Objects.requireNonNull(predicate);
-        if (!isPresent())
+        if (!isPresent()) {
             return this;
-        else
+        } else {
             return predicate.test(value) ? this : empty();
+        }
     }
 
     /**
@@ -209,9 +212,9 @@
      */
     public<U> Optional<U> map(Function<? super T, ? extends U> mapper) {
         Objects.requireNonNull(mapper);
-        if (!isPresent())
+        if (!isPresent()) {
             return empty();
-        else {
+        } else {
             return Optional.ofNullable(mapper.apply(value));
         }
     }
@@ -235,14 +238,37 @@
      */
     public<U> Optional<U> flatMap(Function<? super T, Optional<U>> mapper) {
         Objects.requireNonNull(mapper);
-        if (!isPresent())
+        if (!isPresent()) {
             return empty();
-        else {
+        } else {
             return Objects.requireNonNull(mapper.apply(value));
         }
     }
 
     /**
+     * If a value is present return a sequential {@link Stream} containing only
+     * that value, otherwise return an empty {@code Stream}.
+     *
+     * @apiNote This method can be used to transform a {@code Stream} of
+     * optional elements to a {@code Stream} of present value elements:
+     *
+     * <pre>{@code
+     *     Stream<Optional<T>> os = ..
+     *     Stream<T> s = os.flatMap(Optional::stream)
+     * }</pre>
+     *
+     * @return the optional value as a {@code Stream}
+     * @since 1.9
+     */
+    public Stream<T> stream() {
+        if (!isPresent()) {
+            return Stream.empty();
+        } else {
+            return Stream.of(value);
+        }
+    }
+
+    /**
      * Return the value if present, otherwise return {@code other}.
      *
      * @param other the value to be returned if there is no value present, may
--- a/jdk/src/java.base/share/classes/java/util/OptionalDouble.java	Mon Feb 02 14:19:00 2015 +0100
+++ b/jdk/src/java.base/share/classes/java/util/OptionalDouble.java	Mon Feb 02 14:19:12 2015 +0100
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2012, 2013, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2012, 2015, 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
@@ -27,6 +27,7 @@
 import java.util.function.DoubleConsumer;
 import java.util.function.DoubleSupplier;
 import java.util.function.Supplier;
+import java.util.stream.DoubleStream;
 
 /**
  * A container object which may or may not contain a {@code double} value.
@@ -138,8 +139,32 @@
      * null
      */
     public void ifPresent(DoubleConsumer consumer) {
-        if (isPresent)
+        if (isPresent) {
             consumer.accept(value);
+        }
+    }
+
+    /**
+     * If a value is present return a sequential {@link DoubleStream} containing
+     * only that value, otherwise return an empty {@code DoubleStream}.
+     *
+     * @apiNote This method can be used to transform a {@code Stream} of
+     * optional doubles to a {@code DoubleStream} of present doubles:
+     *
+     * <pre>{@code
+     *     Stream<OptionalDouble> os = ..
+     *     DoubleStream s = os.flatMapToDouble(OptionalDouble::stream)
+     * }</pre>
+     *
+     * @return the optional value as a {@code DoubleStream}
+     * @since 1.9
+     */
+    public DoubleStream stream() {
+        if (isPresent) {
+            return DoubleStream.of(value);
+        } else {
+            return DoubleStream.empty();
+        }
     }
 
     /**
--- a/jdk/src/java.base/share/classes/java/util/OptionalInt.java	Mon Feb 02 14:19:00 2015 +0100
+++ b/jdk/src/java.base/share/classes/java/util/OptionalInt.java	Mon Feb 02 14:19:12 2015 +0100
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2012, 2013, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2012, 2015, 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
@@ -27,6 +27,7 @@
 import java.util.function.IntConsumer;
 import java.util.function.IntSupplier;
 import java.util.function.Supplier;
+import java.util.stream.IntStream;
 
 /**
  * A container object which may or may not contain a {@code int} value.
@@ -138,8 +139,32 @@
      * null
      */
     public void ifPresent(IntConsumer consumer) {
-        if (isPresent)
+        if (isPresent) {
             consumer.accept(value);
+        }
+    }
+
+    /**
+     * If a value is present return a sequential {@link IntStream} containing
+     * only that value, otherwise return an empty {@code IntStream}.
+     *
+     * @apiNote This method can be used to transform a {@code Stream} of
+     * optional integers to an {@code IntStream} of present integers:
+     *
+     * <pre>{@code
+     *     Stream<OptionalInt> os = ..
+     *     IntStream s = os.flatMapToInt(OptionalInt::stream)
+     * }</pre>
+     *
+     * @return the optional value as an {@code IntStream}
+     * @since 1.9
+     */
+    public IntStream stream() {
+        if (isPresent) {
+            return IntStream.of(value);
+        } else {
+            return IntStream.empty();
+        }
     }
 
     /**
--- a/jdk/src/java.base/share/classes/java/util/OptionalLong.java	Mon Feb 02 14:19:00 2015 +0100
+++ b/jdk/src/java.base/share/classes/java/util/OptionalLong.java	Mon Feb 02 14:19:12 2015 +0100
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2012, 2013, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2012, 2015, 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
@@ -27,6 +27,7 @@
 import java.util.function.LongConsumer;
 import java.util.function.LongSupplier;
 import java.util.function.Supplier;
+import java.util.stream.LongStream;
 
 /**
  * A container object which may or may not contain a {@code long} value.
@@ -138,8 +139,32 @@
      * null
      */
     public void ifPresent(LongConsumer consumer) {
-        if (isPresent)
+        if (isPresent) {
             consumer.accept(value);
+        }
+    }
+
+    /**
+     * If a value is present return a sequential {@link LongStream} containing
+     * only that value, otherwise return an empty {@code LongStream}.
+     *
+     * @apiNote This method can be used to transform a {@code Stream} of
+     * optional longs to a {@code LongStream} of present longs:
+     *
+     * <pre>{@code
+     *     Stream<OptionalLong> os = ..
+     *     LongStream s = os.flatMapToLong(OptionalLong::stream)
+     * }</pre>
+     *
+     * @return the optional value as a {@code LongStream}
+     * @since 1.9
+     */
+    public LongStream stream() {
+        if (isPresent) {
+            return LongStream.of(value);
+        } else {
+            return LongStream.empty();
+        }
     }
 
     /**
--- a/jdk/test/java/util/Optional/Basic.java	Mon Feb 02 14:19:00 2015 +0100
+++ b/jdk/test/java/util/Optional/Basic.java	Mon Feb 02 14:19:12 2015 +0100
@@ -29,6 +29,7 @@
 
 import java.util.NoSuchElementException;
 import java.util.Optional;
+import java.util.stream.Stream;
 
 import static org.testng.Assert.*;
 import org.testng.annotations.Test;
@@ -54,8 +55,8 @@
         assertSame(null, empty.orElse(null));
         RuntimeException orElse = new RuntimeException() { };
         assertSame(Boolean.FALSE, empty.orElse(Boolean.FALSE));
-        assertSame(null, empty.orElseGet(()-> null));
-        assertSame(Boolean.FALSE, empty.orElseGet(()-> Boolean.FALSE));
+        assertSame(null, empty.orElseGet(() -> null));
+        assertSame(Boolean.FALSE, empty.orElseGet(() -> Boolean.FALSE));
     }
 
     @Test(expectedExceptions=NoSuchElementException.class)
@@ -104,15 +105,15 @@
         try {
             present.ifPresent(v -> { throw new ObscureException(); });
             fail();
-        } catch(ObscureException expected) {
+        } catch (ObscureException expected) {
 
         }
         assertSame(Boolean.TRUE, present.orElse(null));
         assertSame(Boolean.TRUE, present.orElse(Boolean.FALSE));
         assertSame(Boolean.TRUE, present.orElseGet(null));
-        assertSame(Boolean.TRUE, present.orElseGet(()-> null));
-        assertSame(Boolean.TRUE, present.orElseGet(()-> Boolean.FALSE));
-        assertSame(Boolean.TRUE, present.<RuntimeException>orElseThrow( null));
+        assertSame(Boolean.TRUE, present.orElseGet(() -> null));
+        assertSame(Boolean.TRUE, present.orElseGet(() -> Boolean.FALSE));
+        assertSame(Boolean.TRUE, present.<RuntimeException>orElseThrow(null));
         assertSame(Boolean.TRUE, present.<RuntimeException>orElseThrow(ObscureException::new));
     }
 
@@ -226,6 +227,26 @@
         assertSame(l, fixture);
     }
 
+    @Test(groups = "unit")
+    public void testStream() {
+        {
+            Stream<String> s = Optional.<String>empty().stream();
+            assertFalse(s.isParallel());
+
+            Object[] es = s.toArray();
+            assertEquals(es.length, 0);
+        }
+
+        {
+            Stream<String> s = Optional.of("Duke").stream();
+            assertFalse(s.isParallel());
+
+            String[] es = s.toArray(String[]::new);
+            assertEquals(es.length, 1);
+            assertEquals(es[0], "Duke");
+        }
+    }
+
     private static class ObscureException extends RuntimeException {
 
     }
--- a/jdk/test/java/util/Optional/BasicDouble.java	Mon Feb 02 14:19:00 2015 +0100
+++ b/jdk/test/java/util/Optional/BasicDouble.java	Mon Feb 02 14:19:12 2015 +0100
@@ -29,6 +29,7 @@
 
 import java.util.NoSuchElementException;
 import java.util.OptionalDouble;
+import java.util.stream.DoubleStream;
 
 import static org.testng.Assert.*;
 import org.testng.annotations.Test;
@@ -109,6 +110,26 @@
         assertEquals(1.0, present.<RuntimeException>orElseThrow(ObscureException::new));
     }
 
+    @Test(groups = "unit")
+    public void testStream() {
+        {
+            DoubleStream s = OptionalDouble.empty().stream();
+            assertFalse(s.isParallel());
+
+            double[] es = s.toArray();
+            assertEquals(es.length, 0);
+        }
+
+        {
+            DoubleStream s = OptionalDouble.of(42.0).stream();
+            assertFalse(s.isParallel());
+
+            double[] es = s.toArray();
+            assertEquals(es.length, 1);
+            assertEquals(es[0], 42.0);
+        }
+    }
+
     private static class ObscureException extends RuntimeException {
 
     }
--- a/jdk/test/java/util/Optional/BasicInt.java	Mon Feb 02 14:19:00 2015 +0100
+++ b/jdk/test/java/util/Optional/BasicInt.java	Mon Feb 02 14:19:12 2015 +0100
@@ -29,6 +29,7 @@
 
 import java.util.NoSuchElementException;
 import java.util.OptionalInt;
+import java.util.stream.IntStream;
 
 import static org.testng.Assert.*;
 import org.testng.annotations.Test;
@@ -53,36 +54,36 @@
         assertEquals(2, empty.orElseGet(()-> 2));
     }
 
-        @Test(expectedExceptions=NoSuchElementException.class)
-        public void testEmptyGet() {
-            OptionalInt empty = OptionalInt.empty();
+    @Test(expectedExceptions=NoSuchElementException.class)
+    public void testEmptyGet() {
+        OptionalInt empty = OptionalInt.empty();
 
-            int got = empty.getAsInt();
-        }
+        int got = empty.getAsInt();
+    }
 
-        @Test(expectedExceptions=NullPointerException.class)
-        public void testEmptyOrElseGetNull() {
-            OptionalInt empty = OptionalInt.empty();
+    @Test(expectedExceptions=NullPointerException.class)
+    public void testEmptyOrElseGetNull() {
+        OptionalInt empty = OptionalInt.empty();
 
-            int got = empty.orElseGet(null);
-        }
+        int got = empty.orElseGet(null);
+    }
 
-        @Test(expectedExceptions=NullPointerException.class)
-        public void testEmptyOrElseThrowNull() throws Throwable {
-            OptionalInt empty = OptionalInt.empty();
+    @Test(expectedExceptions=NullPointerException.class)
+    public void testEmptyOrElseThrowNull() throws Throwable {
+        OptionalInt empty = OptionalInt.empty();
 
-            int got = empty.orElseThrow(null);
-        }
+        int got = empty.orElseThrow(null);
+    }
 
-        @Test(expectedExceptions=ObscureException.class)
-        public void testEmptyOrElseThrow() throws Exception {
-            OptionalInt empty = OptionalInt.empty();
+    @Test(expectedExceptions=ObscureException.class)
+    public void testEmptyOrElseThrow() throws Exception {
+        OptionalInt empty = OptionalInt.empty();
 
-            int got = empty.orElseThrow(ObscureException::new);
-        }
+        int got = empty.orElseThrow(ObscureException::new);
+    }
 
-        @Test(groups = "unit")
-        public void testPresent() {
+    @Test(groups = "unit")
+    public void testPresent() {
         OptionalInt empty = OptionalInt.empty();
         OptionalInt present = OptionalInt.of(1);
 
@@ -109,6 +110,26 @@
         assertEquals(1, present.<RuntimeException>orElseThrow(ObscureException::new));
     }
 
+    @Test(groups = "unit")
+    public void testStream() {
+        {
+            IntStream s = OptionalInt.empty().stream();
+            assertFalse(s.isParallel());
+
+            int[] es = s.toArray();
+            assertEquals(es.length, 0);
+        }
+
+        {
+            IntStream s = OptionalInt.of(42).stream();
+            assertFalse(s.isParallel());
+
+            int[] es = OptionalInt.of(42).stream().toArray();
+            assertEquals(es.length, 1);
+            assertEquals(es[0], 42);
+        }
+    }
+
     private static class ObscureException extends RuntimeException {
 
     }
--- a/jdk/test/java/util/Optional/BasicLong.java	Mon Feb 02 14:19:00 2015 +0100
+++ b/jdk/test/java/util/Optional/BasicLong.java	Mon Feb 02 14:19:12 2015 +0100
@@ -29,6 +29,7 @@
 
 import java.util.NoSuchElementException;
 import java.util.OptionalLong;
+import java.util.stream.LongStream;
 
 import static org.testng.Assert.*;
 import org.testng.annotations.Test;
@@ -109,6 +110,24 @@
         assertEquals(1, present.<RuntimeException>orElseThrow(ObscureException::new));
     }
 
+    @Test(groups = "unit")
+    public void testStream() {
+        {
+            LongStream s = OptionalLong.empty().stream();
+
+            long[] es = s.toArray();
+            assertEquals(es.length, 0);
+        }
+
+        {
+            LongStream s = OptionalLong.of(42L).stream();
+
+            long[] es = s.toArray();
+            assertEquals(es.length, 1);
+            assertEquals(es[0], 42L);
+        }
+    }
+
     private static class ObscureException extends RuntimeException {
 
     }