From dd21d2c4db8295f15c8c5c401c12908e8240c1b6 Mon Sep 17 00:00:00 2001 From: Paul Sandoz Date: Mon, 2 Feb 2015 14:19:12 +0100 Subject: [PATCH] 8050820: Please add java.util.Optional.stream() to convert Optional to Stream Reviewed-by: alundblad, forax, chegar, jrose --- .../share/classes/java/util/Optional.java | 42 +++++++++--- .../classes/java/util/OptionalDouble.java | 29 ++++++++- .../share/classes/java/util/OptionalInt.java | 29 ++++++++- .../share/classes/java/util/OptionalLong.java | 29 ++++++++- jdk/test/java/util/Optional/Basic.java | 33 ++++++++-- jdk/test/java/util/Optional/BasicDouble.java | 21 ++++++ jdk/test/java/util/Optional/BasicInt.java | 65 ++++++++++++------- jdk/test/java/util/Optional/BasicLong.java | 19 ++++++ 8 files changed, 225 insertions(+), 42 deletions(-) diff --git a/jdk/src/java.base/share/classes/java/util/Optional.java b/jdk/src/java.base/share/classes/java/util/Optional.java index d471058ec16..eb8301b2361 100644 --- a/jdk/src/java.base/share/classes/java/util/Optional.java +++ b/jdk/src/java.base/share/classes/java/util/Optional.java @@ -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.Consumer; 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 @@ public final class Optional { * null */ public void ifPresent(Consumer consumer) { - if (value != null) + if (value != null) { consumer.accept(value); + } } /** @@ -172,10 +174,11 @@ public final class Optional { */ public Optional filter(Predicate predicate) { Objects.requireNonNull(predicate); - if (!isPresent()) + if (!isPresent()) { return this; - else + } else { return predicate.test(value) ? this : empty(); + } } /** @@ -209,9 +212,9 @@ public final class Optional { */ public Optional map(Function mapper) { Objects.requireNonNull(mapper); - if (!isPresent()) + if (!isPresent()) { return empty(); - else { + } else { return Optional.ofNullable(mapper.apply(value)); } } @@ -235,13 +238,36 @@ public final class Optional { */ public Optional flatMap(Function> 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: + * + *
{@code
+     *     Stream> os = ..
+     *     Stream s = os.flatMap(Optional::stream)
+     * }
+ * + * @return the optional value as a {@code Stream} + * @since 1.9 + */ + public Stream stream() { + if (!isPresent()) { + return Stream.empty(); + } else { + return Stream.of(value); + } + } + /** * Return the value if present, otherwise return {@code other}. * diff --git a/jdk/src/java.base/share/classes/java/util/OptionalDouble.java b/jdk/src/java.base/share/classes/java/util/OptionalDouble.java index 8cd7d9f32da..e699c53d517 100644 --- a/jdk/src/java.base/share/classes/java/util/OptionalDouble.java +++ b/jdk/src/java.base/share/classes/java/util/OptionalDouble.java @@ -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 @@ package java.util; 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 @@ public final class OptionalDouble { * 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: + * + *
{@code
+     *     Stream os = ..
+     *     DoubleStream s = os.flatMapToDouble(OptionalDouble::stream)
+     * }
+ * + * @return the optional value as a {@code DoubleStream} + * @since 1.9 + */ + public DoubleStream stream() { + if (isPresent) { + return DoubleStream.of(value); + } else { + return DoubleStream.empty(); + } } /** diff --git a/jdk/src/java.base/share/classes/java/util/OptionalInt.java b/jdk/src/java.base/share/classes/java/util/OptionalInt.java index d7dc88c7b83..d8d9382633d 100644 --- a/jdk/src/java.base/share/classes/java/util/OptionalInt.java +++ b/jdk/src/java.base/share/classes/java/util/OptionalInt.java @@ -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 @@ package java.util; 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 @@ public final class OptionalInt { * 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: + * + *
{@code
+     *     Stream os = ..
+     *     IntStream s = os.flatMapToInt(OptionalInt::stream)
+     * }
+ * + * @return the optional value as an {@code IntStream} + * @since 1.9 + */ + public IntStream stream() { + if (isPresent) { + return IntStream.of(value); + } else { + return IntStream.empty(); + } } /** diff --git a/jdk/src/java.base/share/classes/java/util/OptionalLong.java b/jdk/src/java.base/share/classes/java/util/OptionalLong.java index 540d50a2751..4e2a44873b3 100644 --- a/jdk/src/java.base/share/classes/java/util/OptionalLong.java +++ b/jdk/src/java.base/share/classes/java/util/OptionalLong.java @@ -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 @@ package java.util; 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 @@ public final class OptionalLong { * 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: + * + *
{@code
+     *     Stream os = ..
+     *     LongStream s = os.flatMapToLong(OptionalLong::stream)
+     * }
+ * + * @return the optional value as a {@code LongStream} + * @since 1.9 + */ + public LongStream stream() { + if (isPresent) { + return LongStream.of(value); + } else { + return LongStream.empty(); + } } /** diff --git a/jdk/test/java/util/Optional/Basic.java b/jdk/test/java/util/Optional/Basic.java index dc05ff97a78..f37397d90b9 100644 --- a/jdk/test/java/util/Optional/Basic.java +++ b/jdk/test/java/util/Optional/Basic.java @@ -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 @@ public class Basic { 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 @@ public class Basic { 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.orElseThrow( null)); + assertSame(Boolean.TRUE, present.orElseGet(() -> null)); + assertSame(Boolean.TRUE, present.orElseGet(() -> Boolean.FALSE)); + assertSame(Boolean.TRUE, present.orElseThrow(null)); assertSame(Boolean.TRUE, present.orElseThrow(ObscureException::new)); } @@ -226,6 +227,26 @@ public class Basic { assertSame(l, fixture); } + @Test(groups = "unit") + public void testStream() { + { + Stream s = Optional.empty().stream(); + assertFalse(s.isParallel()); + + Object[] es = s.toArray(); + assertEquals(es.length, 0); + } + + { + Stream 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 { } diff --git a/jdk/test/java/util/Optional/BasicDouble.java b/jdk/test/java/util/Optional/BasicDouble.java index 841dd459e78..df8ae9e0431 100644 --- a/jdk/test/java/util/Optional/BasicDouble.java +++ b/jdk/test/java/util/Optional/BasicDouble.java @@ -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 @@ public class BasicDouble { assertEquals(1.0, present.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 { } diff --git a/jdk/test/java/util/Optional/BasicInt.java b/jdk/test/java/util/Optional/BasicInt.java index fa29f95208a..8f3b2d5d82c 100644 --- a/jdk/test/java/util/Optional/BasicInt.java +++ b/jdk/test/java/util/Optional/BasicInt.java @@ -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 @@ public class BasicInt { 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 @@ public class BasicInt { assertEquals(1, present.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 { } diff --git a/jdk/test/java/util/Optional/BasicLong.java b/jdk/test/java/util/Optional/BasicLong.java index 85bf689ad46..39b29375cac 100644 --- a/jdk/test/java/util/Optional/BasicLong.java +++ b/jdk/test/java/util/Optional/BasicLong.java @@ -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 @@ public class BasicLong { assertEquals(1, present.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 { }