From c6c268006c28d65eb5c8e72a0755ef012cd8fc22 Mon Sep 17 00:00:00 2001 From: cpovirk Date: Fri, 25 Oct 2024 11:02:11 -0700 Subject: [PATCH] Expose more Java 8 APIs to Android users. RELNOTES=Exposed some additional Java 8 APIs to Android users. PiperOrigin-RevId: 689846217 --- .../primitives/ImmutableDoubleArrayTest.java | 38 +++++++- .../primitives/ImmutableIntArrayTest.java | 35 +++++++ .../primitives/ImmutableLongArrayTest.java | 36 +++++++ .../com/google/common/primitives/Doubles.java | 13 +++ .../primitives/IgnoreJRERequirement.java | 30 ++++++ .../primitives/ImmutableDoubleArray.java | 90 ++++++++++++++++- .../common/primitives/ImmutableIntArray.java | 96 ++++++++++++++++++- .../common/primitives/ImmutableLongArray.java | 90 ++++++++++++++++- .../com/google/common/primitives/Ints.java | 13 +++ .../com/google/common/primitives/Longs.java | 13 +++ android/pom.xml | 2 +- .../primitives/ImmutableDoubleArrayTest.java | 4 +- .../primitives/IgnoreJRERequirement.java | 30 ++++++ .../primitives/ImmutableDoubleArray.java | 26 ++++- .../common/primitives/ImmutableIntArray.java | 26 ++++- .../common/primitives/ImmutableLongArray.java | 26 ++++- pom.xml | 2 +- 17 files changed, 548 insertions(+), 22 deletions(-) create mode 100644 android/guava/src/com/google/common/primitives/IgnoreJRERequirement.java create mode 100644 guava/src/com/google/common/primitives/IgnoreJRERequirement.java diff --git a/android/guava-tests/test/com/google/common/primitives/ImmutableDoubleArrayTest.java b/android/guava-tests/test/com/google/common/primitives/ImmutableDoubleArrayTest.java index ee8328ef1f2d..789b6de6d694 100644 --- a/android/guava-tests/test/com/google/common/primitives/ImmutableDoubleArrayTest.java +++ b/android/guava-tests/test/com/google/common/primitives/ImmutableDoubleArrayTest.java @@ -18,6 +18,7 @@ import static com.google.common.primitives.TestPlatform.reduceIterationsIfGwt; import static com.google.common.testing.SerializableTester.reserialize; import static com.google.common.truth.Truth.assertThat; +import static java.util.Arrays.stream; import com.google.common.annotations.GwtCompatible; import com.google.common.annotations.GwtIncompatible; @@ -38,6 +39,7 @@ import java.util.List; import java.util.Random; import java.util.concurrent.atomic.AtomicInteger; +import java.util.stream.DoubleStream; import junit.framework.Test; import junit.framework.TestCase; import junit.framework.TestSuite; @@ -46,7 +48,6 @@ * @author Kevin Bourrillion */ @GwtCompatible(emulated = true) -@ElementTypesAreNonnullByDefault public class ImmutableDoubleArrayTest extends TestCase { // Test all creation paths very lazily: by assuming asList() works @@ -142,6 +143,14 @@ public void testCopyOf_collection_nonempty() { assertThat(iia.asList()).containsExactly(0.0, 1.0, 3.0).inOrder(); } + public void testCopyOf_stream() { + assertThat(ImmutableDoubleArray.copyOf(DoubleStream.empty())) + .isSameInstanceAs(ImmutableDoubleArray.of()); + assertThat(ImmutableDoubleArray.copyOf(DoubleStream.of(0, 1, 3)).asList()) + .containsExactly(0.0, 1.0, 3.0) + .inOrder(); + } + public void testBuilder_presize_zero() { ImmutableDoubleArray.Builder builder = ImmutableDoubleArray.builder(0); builder.add(5.0); @@ -211,6 +220,16 @@ void doIt(ImmutableDoubleArray.Builder builder, AtomicInteger counter) { builder.addAll(iterable(list)); } }, + ADD_STREAM { + @Override + void doIt(ImmutableDoubleArray.Builder builder, AtomicInteger counter) { + double[] array = new double[RANDOM.nextInt(10)]; + for (int i = 0; i < array.length; i++) { + array[i] = counter.getAndIncrement(); + } + builder.addAll(stream(array)); + } + }, ADD_IIA { @Override void doIt(ImmutableDoubleArray.Builder builder, AtomicInteger counter) { @@ -316,6 +335,23 @@ public void testContains() { assertThat(iia.subArray(1, 5).contains(1)).isTrue(); } + public void testForEach() { + ImmutableDoubleArray.of().forEach(i -> fail()); + ImmutableDoubleArray.of(0, 1, 3).subArray(1, 1).forEach(i -> fail()); + + AtomicInteger count = new AtomicInteger(0); + ImmutableDoubleArray.of(0, 1, 2, 3) + .forEach(i -> assertThat(i).isEqualTo((double) count.getAndIncrement())); + assertThat(count.get()).isEqualTo(4); + } + + public void testStream() { + ImmutableDoubleArray.of().stream().forEach(i -> fail()); + ImmutableDoubleArray.of(0, 1, 3).subArray(1, 1).stream().forEach(i -> fail()); + assertThat(ImmutableDoubleArray.of(0, 1, 3).stream().toArray()) + .isEqualTo(new double[] {0, 1, 3}); + } + public void testSubArray() { ImmutableDoubleArray iia0 = ImmutableDoubleArray.of(); ImmutableDoubleArray iia1 = ImmutableDoubleArray.of(5); diff --git a/android/guava-tests/test/com/google/common/primitives/ImmutableIntArrayTest.java b/android/guava-tests/test/com/google/common/primitives/ImmutableIntArrayTest.java index 3f949f3189b9..7d7a83f3fe85 100644 --- a/android/guava-tests/test/com/google/common/primitives/ImmutableIntArrayTest.java +++ b/android/guava-tests/test/com/google/common/primitives/ImmutableIntArrayTest.java @@ -18,6 +18,7 @@ import static com.google.common.primitives.TestPlatform.reduceIterationsIfGwt; import static com.google.common.testing.SerializableTester.reserialize; import static com.google.common.truth.Truth.assertThat; +import static java.util.Arrays.stream; import com.google.common.annotations.GwtCompatible; import com.google.common.annotations.GwtIncompatible; @@ -38,6 +39,7 @@ import java.util.List; import java.util.Random; import java.util.concurrent.atomic.AtomicInteger; +import java.util.stream.IntStream; import junit.framework.Test; import junit.framework.TestCase; import junit.framework.TestSuite; @@ -136,6 +138,14 @@ public void testCopyOf_collection_nonempty() { assertThat(iia.asList()).containsExactly(0, 1, 3).inOrder(); } + public void testCopyOf_stream() { + assertThat(ImmutableIntArray.copyOf(IntStream.empty())) + .isSameInstanceAs(ImmutableIntArray.of()); + assertThat(ImmutableIntArray.copyOf(IntStream.of(0, 1, 3)).asList()) + .containsExactly(0, 1, 3) + .inOrder(); + } + public void testBuilder_presize_zero() { ImmutableIntArray.Builder builder = ImmutableIntArray.builder(0); builder.add(5); @@ -205,6 +215,16 @@ void doIt(ImmutableIntArray.Builder builder, AtomicInteger counter) { builder.addAll(iterable(list)); } }, + ADD_STREAM { + @Override + void doIt(ImmutableIntArray.Builder builder, AtomicInteger counter) { + int[] array = new int[RANDOM.nextInt(10)]; + for (int i = 0; i < array.length; i++) { + array[i] = counter.getAndIncrement(); + } + builder.addAll(stream(array)); + } + }, ADD_IIA { @Override void doIt(ImmutableIntArray.Builder builder, AtomicInteger counter) { @@ -300,6 +320,21 @@ public void testContains() { assertThat(iia.subArray(1, 5).contains(1)).isTrue(); } + public void testForEach() { + ImmutableIntArray.of().forEach(i -> fail()); + ImmutableIntArray.of(0, 1, 3).subArray(1, 1).forEach(i -> fail()); + + AtomicInteger count = new AtomicInteger(0); + ImmutableIntArray.of(0, 1, 2, 3).forEach(i -> assertThat(i).isEqualTo(count.getAndIncrement())); + assertThat(count.get()).isEqualTo(4); + } + + public void testStream() { + ImmutableIntArray.of().stream().forEach(i -> fail()); + ImmutableIntArray.of(0, 1, 3).subArray(1, 1).stream().forEach(i -> fail()); + assertThat(ImmutableIntArray.of(0, 1, 3).stream().toArray()).isEqualTo(new int[] {0, 1, 3}); + } + public void testSubArray() { ImmutableIntArray iia0 = ImmutableIntArray.of(); ImmutableIntArray iia1 = ImmutableIntArray.of(5); diff --git a/android/guava-tests/test/com/google/common/primitives/ImmutableLongArrayTest.java b/android/guava-tests/test/com/google/common/primitives/ImmutableLongArrayTest.java index 74f0dff973c5..d351335cabdb 100644 --- a/android/guava-tests/test/com/google/common/primitives/ImmutableLongArrayTest.java +++ b/android/guava-tests/test/com/google/common/primitives/ImmutableLongArrayTest.java @@ -18,6 +18,7 @@ import static com.google.common.primitives.TestPlatform.reduceIterationsIfGwt; import static com.google.common.testing.SerializableTester.reserialize; import static com.google.common.truth.Truth.assertThat; +import static java.util.Arrays.stream; import com.google.common.annotations.GwtCompatible; import com.google.common.annotations.GwtIncompatible; @@ -38,6 +39,7 @@ import java.util.List; import java.util.Random; import java.util.concurrent.atomic.AtomicLong; +import java.util.stream.LongStream; import junit.framework.Test; import junit.framework.TestCase; import junit.framework.TestSuite; @@ -138,6 +140,14 @@ public void testCopyOf_collection_nonempty() { assertThat(iia.asList()).containsExactly(0L, 1L, 3L).inOrder(); } + public void testCopyOf_stream() { + assertThat(ImmutableLongArray.copyOf(LongStream.empty())) + .isSameInstanceAs(ImmutableLongArray.of()); + assertThat(ImmutableLongArray.copyOf(LongStream.of(0, 1, 3)).asList()) + .containsExactly(0L, 1L, 3L) + .inOrder(); + } + public void testBuilder_presize_zero() { ImmutableLongArray.Builder builder = ImmutableLongArray.builder(0); builder.add(5L); @@ -207,6 +217,16 @@ void doIt(ImmutableLongArray.Builder builder, AtomicLong counter) { builder.addAll(iterable(list)); } }, + ADD_STREAM { + @Override + void doIt(ImmutableLongArray.Builder builder, AtomicLong counter) { + long[] array = new long[RANDOM.nextInt(10)]; + for (int i = 0; i < array.length; i++) { + array[i] = counter.getAndIncrement(); + } + builder.addAll(stream(array)); + } + }, ADD_IIA { @Override void doIt(ImmutableLongArray.Builder builder, AtomicLong counter) { @@ -302,6 +322,22 @@ public void testContains() { assertThat(iia.subArray(1, 5).contains(1)).isTrue(); } + public void testForEach() { + ImmutableLongArray.of().forEach(i -> fail()); + ImmutableLongArray.of(0, 1, 3).subArray(1, 1).forEach(i -> fail()); + + AtomicLong count = new AtomicLong(0); + ImmutableLongArray.of(0, 1, 2, 3) + .forEach(i -> assertThat(i).isEqualTo(count.getAndIncrement())); + assertThat(count.get()).isEqualTo(4); + } + + public void testStream() { + ImmutableLongArray.of().stream().forEach(i -> fail()); + ImmutableLongArray.of(0, 1, 3).subArray(1, 1).stream().forEach(i -> fail()); + assertThat(ImmutableLongArray.of(0, 1, 3).stream().toArray()).isEqualTo(new long[] {0, 1, 3}); + } + public void testSubArray() { ImmutableLongArray iia0 = ImmutableLongArray.of(); ImmutableLongArray iia1 = ImmutableLongArray.of(5); diff --git a/android/guava/src/com/google/common/primitives/Doubles.java b/android/guava/src/com/google/common/primitives/Doubles.java index 5d6291cbe0f9..5123de0ffc4f 100644 --- a/android/guava/src/com/google/common/primitives/Doubles.java +++ b/android/guava/src/com/google/common/primitives/Doubles.java @@ -34,6 +34,8 @@ import java.util.Comparator; import java.util.List; import java.util.RandomAccess; +import java.util.Spliterator; +import java.util.Spliterators; import javax.annotation.CheckForNull; /** @@ -616,6 +618,17 @@ public Double get(int index) { return array[start + index]; } + @Override + @SuppressWarnings("Java7ApiChecker") + /* + * This is an override that is not directly visible to callers, so NewApi will catch calls to + * Collection.spliterator() where necessary. + */ + @IgnoreJRERequirement + public Spliterator.OfDouble spliterator() { + return Spliterators.spliterator(array, start, end, 0); + } + @Override public boolean contains(@CheckForNull Object target) { // Overridden to prevent a ton of boxing diff --git a/android/guava/src/com/google/common/primitives/IgnoreJRERequirement.java b/android/guava/src/com/google/common/primitives/IgnoreJRERequirement.java new file mode 100644 index 000000000000..a5afd04818dc --- /dev/null +++ b/android/guava/src/com/google/common/primitives/IgnoreJRERequirement.java @@ -0,0 +1,30 @@ +/* + * Copyright 2019 The Guava Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except + * in compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software distributed under the License + * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express + * or implied. See the License for the specific language governing permissions and limitations under + * the License. + */ + +package com.google.common.primitives; + +import static java.lang.annotation.ElementType.CONSTRUCTOR; +import static java.lang.annotation.ElementType.METHOD; +import static java.lang.annotation.ElementType.TYPE; + +import java.lang.annotation.Target; + +/** + * Disables Animal Sniffer's checking of compatibility with older versions of Java/Android. + * + *

Each package's copy of this annotation needs to be listed in our {@code pom.xml}. + */ +@Target({METHOD, CONSTRUCTOR, TYPE}) +@ElementTypesAreNonnullByDefault +@interface IgnoreJRERequirement {} diff --git a/android/guava/src/com/google/common/primitives/ImmutableDoubleArray.java b/android/guava/src/com/google/common/primitives/ImmutableDoubleArray.java index 1b4169c12126..e66821e5d32f 100644 --- a/android/guava/src/com/google/common/primitives/ImmutableDoubleArray.java +++ b/android/guava/src/com/google/common/primitives/ImmutableDoubleArray.java @@ -15,6 +15,7 @@ package com.google.common.primitives; import static com.google.common.base.Preconditions.checkArgument; +import static com.google.common.base.Preconditions.checkNotNull; import com.google.common.annotations.GwtCompatible; import com.google.common.base.Preconditions; @@ -26,6 +27,10 @@ import java.util.Collection; import java.util.List; import java.util.RandomAccess; +import java.util.Spliterator; +import java.util.Spliterators; +import java.util.function.DoubleConsumer; +import java.util.stream.DoubleStream; import javax.annotation.CheckForNull; /** @@ -42,6 +47,7 @@ * hunt through classes like {@link Arrays} and {@link Doubles} for them. *

  • Supports a copy-free {@link #subArray} view, so methods that accept this type don't need to * add overloads that accept start and end indexes. + *
  • Can be streamed without "breaking the chain": {@code foo.getBarDoubles().stream()...}. *
  • Access to all collection-based utilities via {@link #asList} (though at the cost of * allocating garbage). * @@ -63,6 +69,8 @@ * * *

    Disadvantages compared to {@code ImmutableList}: @@ -161,6 +169,19 @@ public static ImmutableDoubleArray copyOf(Iterable values) { return builder().addAll(values).build(); } + /** + * Returns an immutable array containing all the values from {@code stream}, in order. + * + * @since NEXT (but since 22.0 in the JRE flavor) + */ + @SuppressWarnings("Java7ApiChecker") + @IgnoreJRERequirement // Users will use this only if they're already using streams. + public static ImmutableDoubleArray copyOf(DoubleStream stream) { + // Note this uses very different growth behavior from copyOf(Iterable) and the builder. + double[] array = stream.toArray(); + return (array.length == 0) ? EMPTY : new ImmutableDoubleArray(array); + } + /** * Returns a new, empty builder for {@link ImmutableDoubleArray} instances, sized to hold up to * {@code initialCapacity} values without resizing. The returned builder is not thread-safe. @@ -252,6 +273,25 @@ public Builder addAll(Collection values) { return this; } + /** + * Appends all values from {@code stream}, in order, to the end of the values the built {@link + * ImmutableDoubleArray} will contain. + * + * @since NEXT (but since 22.0 in the JRE flavor) + */ + @SuppressWarnings("Java7ApiChecker") + @IgnoreJRERequirement // Users will use this only if they're already using streams. + @CanIgnoreReturnValue + public Builder addAll(DoubleStream stream) { + Spliterator.OfDouble spliterator = stream.spliterator(); + long size = spliterator.getExactSizeIfKnown(); + if (size > 0) { // known *and* nonempty + ensureRoomFor(Ints.saturatedCast(size)); + } + spliterator.forEachRemaining((DoubleConsumer) this::add); + return this; + } + /** * Appends {@code values}, in order, to the end of the values the built {@link * ImmutableDoubleArray} will contain. @@ -383,6 +423,32 @@ public boolean contains(double target) { return indexOf(target) >= 0; } + /** + * Invokes {@code consumer} for each value contained in this array, in order. + * + * @since NEXT (but since 22.0 in the JRE flavor) + */ + @SuppressWarnings("Java7ApiChecker") + @IgnoreJRERequirement // We rely on users not to call this without library desugaring. + public void forEach(DoubleConsumer consumer) { + checkNotNull(consumer); + for (int i = start; i < end; i++) { + consumer.accept(array[i]); + } + } + + /** + * Returns a stream over the values in this array, in order. + * + * @since NEXT (but since 22.0 in the JRE flavor) + */ + @SuppressWarnings("Java7ApiChecker") + // If users use this when they shouldn't, we hope that NewApi will catch subsequent stream calls + @IgnoreJRERequirement + public DoubleStream stream() { + return Arrays.stream(array, start, end); + } + /** Returns a new, mutable copy of this array's values, as a primitive {@code double[]}. */ public double[] toArray() { return Arrays.copyOfRange(array, start, end); @@ -402,6 +468,16 @@ public ImmutableDoubleArray subArray(int startIndex, int endIndex) { : new ImmutableDoubleArray(array, start + startIndex, start + endIndex); } + @SuppressWarnings("Java7ApiChecker") + @IgnoreJRERequirement // used only from APIs that use streams + /* + * We declare this as package-private, rather than private, to avoid generating a synthetic + * accessor method (under -target 8) that would lack the Android flavor's @IgnoreJRERequirement. + */ + Spliterator.OfDouble spliterator() { + return Spliterators.spliterator(array, start, end, Spliterator.IMMUTABLE | Spliterator.ORDERED); + } + /** * Returns an immutable view of this array's values as a {@code List}; note that {@code * double} values are boxed into {@link Double} instances on demand, which can be very expensive. @@ -425,7 +501,7 @@ private AsList(ImmutableDoubleArray parent) { this.parent = parent; } - // inherit: isEmpty, containsAll, toArray x2, iterator, listIterator, mutations + // inherit: isEmpty, containsAll, toArray x2, iterator, listIterator, stream, forEach, mutations @Override public int size() { @@ -457,6 +533,18 @@ public List subList(int fromIndex, int toIndex) { return parent.subArray(fromIndex, toIndex).asList(); } + // The default List spliterator is not efficiently splittable + @Override + @SuppressWarnings("Java7ApiChecker") + /* + * This is an override that is not directly visible to callers, so NewApi will catch calls to + * Collection.spliterator() where necessary. + */ + @IgnoreJRERequirement + public Spliterator spliterator() { + return parent.spliterator(); + } + @Override public boolean equals(@CheckForNull Object object) { if (object instanceof AsList) { diff --git a/android/guava/src/com/google/common/primitives/ImmutableIntArray.java b/android/guava/src/com/google/common/primitives/ImmutableIntArray.java index 57c464c9809a..4d8e61c8af4d 100644 --- a/android/guava/src/com/google/common/primitives/ImmutableIntArray.java +++ b/android/guava/src/com/google/common/primitives/ImmutableIntArray.java @@ -15,6 +15,7 @@ package com.google.common.primitives; import static com.google.common.base.Preconditions.checkArgument; +import static com.google.common.base.Preconditions.checkNotNull; import com.google.common.annotations.GwtCompatible; import com.google.common.base.Preconditions; @@ -26,6 +27,10 @@ import java.util.Collection; import java.util.List; import java.util.RandomAccess; +import java.util.Spliterator; +import java.util.Spliterators; +import java.util.function.IntConsumer; +import java.util.stream.IntStream; import javax.annotation.CheckForNull; /** @@ -37,11 +42,12 @@ *

  • All the many well-known advantages of immutability (read Effective Java, third * edition, Item 17). *
  • Has the value-based (not identity-based) {@link #equals}, {@link #hashCode}, and {@link - * #toString} behavior you expect + * #toString} behavior you expect. *
  • Offers useful operations beyond just {@code get} and {@code length}, so you don't have to * hunt through classes like {@link Arrays} and {@link Ints} for them. *
  • Supports a copy-free {@link #subArray} view, so methods that accept this type don't need to * add overloads that accept start and end indexes. + *
  • Can be streamed without "breaking the chain": {@code foo.getBarInts().stream()...}. *
  • Access to all collection-based utilities via {@link #asList} (though at the cost of * allocating garbage). * @@ -61,8 +67,10 @@ * }: * *
      - *
    • Improved memory compactness and locality - *
    • Can be queried without allocating garbage + *
    • Improved memory compactness and locality. + *
    • Can be queried without allocating garbage. + *
    • Access to {@code IntStream} features (like {@link IntStream#sum}) using {@code stream()} + * instead of the awkward {@code stream().mapToInt(v -> v)}. *
    * *

    Disadvantages compared to {@code ImmutableList}: @@ -158,6 +166,19 @@ public static ImmutableIntArray copyOf(Iterable values) { return builder().addAll(values).build(); } + /** + * Returns an immutable array containing all the values from {@code stream}, in order. + * + * @since NEXT (but since 22.0 in the JRE flavor) + */ + @SuppressWarnings("Java7ApiChecker") + @IgnoreJRERequirement // Users will use this only if they're already using streams. + public static ImmutableIntArray copyOf(IntStream stream) { + // Note this uses very different growth behavior from copyOf(Iterable) and the builder. + int[] array = stream.toArray(); + return (array.length == 0) ? EMPTY : new ImmutableIntArray(array); + } + /** * Returns a new, empty builder for {@link ImmutableIntArray} instances, sized to hold up to * {@code initialCapacity} values without resizing. The returned builder is not thread-safe. @@ -249,6 +270,25 @@ public Builder addAll(Collection values) { return this; } + /** + * Appends all values from {@code stream}, in order, to the end of the values the built {@link + * ImmutableIntArray} will contain. + * + * @since NEXT (but since 22.0 in the JRE flavor) + */ + @SuppressWarnings("Java7ApiChecker") + @IgnoreJRERequirement // Users will use this only if they're already using streams. + @CanIgnoreReturnValue + public Builder addAll(IntStream stream) { + Spliterator.OfInt spliterator = stream.spliterator(); + long size = spliterator.getExactSizeIfKnown(); + if (size > 0) { // known *and* nonempty + ensureRoomFor(Ints.saturatedCast(size)); + } + spliterator.forEachRemaining((IntConsumer) this::add); + return this; + } + /** * Appends {@code values}, in order, to the end of the values the built {@link * ImmutableIntArray} will contain. @@ -378,6 +418,32 @@ public boolean contains(int target) { return indexOf(target) >= 0; } + /** + * Invokes {@code consumer} for each value contained in this array, in order. + * + * @since NEXT (but since 22.0 in the JRE flavor) + */ + @SuppressWarnings("Java7ApiChecker") + @IgnoreJRERequirement // We rely on users not to call this without library desugaring. + public void forEach(IntConsumer consumer) { + checkNotNull(consumer); + for (int i = start; i < end; i++) { + consumer.accept(array[i]); + } + } + + /** + * Returns a stream over the values in this array, in order. + * + * @since NEXT (but since 22.0 in the JRE flavor) + */ + @SuppressWarnings("Java7ApiChecker") + // If users use this when they shouldn't, we hope that NewApi will catch subsequent stream calls + @IgnoreJRERequirement + public IntStream stream() { + return Arrays.stream(array, start, end); + } + /** Returns a new, mutable copy of this array's values, as a primitive {@code int[]}. */ public int[] toArray() { return Arrays.copyOfRange(array, start, end); @@ -397,6 +463,16 @@ public ImmutableIntArray subArray(int startIndex, int endIndex) { : new ImmutableIntArray(array, start + startIndex, start + endIndex); } + @SuppressWarnings("Java7ApiChecker") + @IgnoreJRERequirement // used only from APIs that use streams + /* + * We declare this as package-private, rather than private, to avoid generating a synthetic + * accessor method (under -target 8) that would lack the Android flavor's @IgnoreJRERequirement. + */ + Spliterator.OfInt spliterator() { + return Spliterators.spliterator(array, start, end, Spliterator.IMMUTABLE | Spliterator.ORDERED); + } + /** * Returns an immutable view of this array's values as a {@code List}; note that {@code * int} values are boxed into {@link Integer} instances on demand, which can be very expensive. @@ -420,7 +496,7 @@ private AsList(ImmutableIntArray parent) { this.parent = parent; } - // inherit: isEmpty, containsAll, toArray x2, {,list,spl}iterator, stream, forEach, mutations + // inherit: isEmpty, containsAll, toArray x2, iterator, listIterator, stream, forEach, mutations @Override public int size() { @@ -452,6 +528,18 @@ public List subList(int fromIndex, int toIndex) { return parent.subArray(fromIndex, toIndex).asList(); } + // The default List spliterator is not efficiently splittable + @Override + @SuppressWarnings("Java7ApiChecker") + /* + * This is an override that is not directly visible to callers, so NewApi will catch calls to + * Collection.spliterator() where necessary. + */ + @IgnoreJRERequirement + public Spliterator spliterator() { + return parent.spliterator(); + } + @Override public boolean equals(@CheckForNull Object object) { if (object instanceof AsList) { diff --git a/android/guava/src/com/google/common/primitives/ImmutableLongArray.java b/android/guava/src/com/google/common/primitives/ImmutableLongArray.java index cf417458bc1c..58a5338b9fd4 100644 --- a/android/guava/src/com/google/common/primitives/ImmutableLongArray.java +++ b/android/guava/src/com/google/common/primitives/ImmutableLongArray.java @@ -15,6 +15,7 @@ package com.google.common.primitives; import static com.google.common.base.Preconditions.checkArgument; +import static com.google.common.base.Preconditions.checkNotNull; import com.google.common.annotations.GwtCompatible; import com.google.common.base.Preconditions; @@ -26,6 +27,10 @@ import java.util.Collection; import java.util.List; import java.util.RandomAccess; +import java.util.Spliterator; +import java.util.Spliterators; +import java.util.function.LongConsumer; +import java.util.stream.LongStream; import javax.annotation.CheckForNull; /** @@ -42,6 +47,7 @@ * hunt through classes like {@link Arrays} and {@link Longs} for them. *

  • Supports a copy-free {@link #subArray} view, so methods that accept this type don't need to * add overloads that accept start and end indexes. + *
  • Can be streamed without "breaking the chain": {@code foo.getBarLongs().stream()...}. *
  • Access to all collection-based utilities via {@link #asList} (though at the cost of * allocating garbage). * @@ -63,6 +69,8 @@ * * *

    Disadvantages compared to {@code ImmutableList}: @@ -160,6 +168,19 @@ public static ImmutableLongArray copyOf(Iterable values) { return builder().addAll(values).build(); } + /** + * Returns an immutable array containing all the values from {@code stream}, in order. + * + * @since NEXT (but since 22.0 in the JRE flavor) + */ + @SuppressWarnings("Java7ApiChecker") + @IgnoreJRERequirement // Users will use this only if they're already using streams. + public static ImmutableLongArray copyOf(LongStream stream) { + // Note this uses very different growth behavior from copyOf(Iterable) and the builder. + long[] array = stream.toArray(); + return (array.length == 0) ? EMPTY : new ImmutableLongArray(array); + } + /** * Returns a new, empty builder for {@link ImmutableLongArray} instances, sized to hold up to * {@code initialCapacity} values without resizing. The returned builder is not thread-safe. @@ -251,6 +272,25 @@ public Builder addAll(Collection values) { return this; } + /** + * Appends all values from {@code stream}, in order, to the end of the values the built {@link + * ImmutableLongArray} will contain. + * + * @since NEXT (but since 22.0 in the JRE flavor) + */ + @SuppressWarnings("Java7ApiChecker") + @IgnoreJRERequirement // Users will use this only if they're already using streams. + @CanIgnoreReturnValue + public Builder addAll(LongStream stream) { + Spliterator.OfLong spliterator = stream.spliterator(); + long size = spliterator.getExactSizeIfKnown(); + if (size > 0) { // known *and* nonempty + ensureRoomFor(Ints.saturatedCast(size)); + } + spliterator.forEachRemaining((LongConsumer) this::add); + return this; + } + /** * Appends {@code values}, in order, to the end of the values the built {@link * ImmutableLongArray} will contain. @@ -380,6 +420,32 @@ public boolean contains(long target) { return indexOf(target) >= 0; } + /** + * Invokes {@code consumer} for each value contained in this array, in order. + * + * @since NEXT (but since 22.0 in the JRE flavor) + */ + @SuppressWarnings("Java7ApiChecker") + @IgnoreJRERequirement // We rely on users not to call this without library desugaring. + public void forEach(LongConsumer consumer) { + checkNotNull(consumer); + for (int i = start; i < end; i++) { + consumer.accept(array[i]); + } + } + + /** + * Returns a stream over the values in this array, in order. + * + * @since NEXT (but since 22.0 in the JRE flavor) + */ + @SuppressWarnings("Java7ApiChecker") + // If users use this when they shouldn't, we hope that NewApi will catch subsequent stream calls + @IgnoreJRERequirement + public LongStream stream() { + return Arrays.stream(array, start, end); + } + /** Returns a new, mutable copy of this array's values, as a primitive {@code long[]}. */ public long[] toArray() { return Arrays.copyOfRange(array, start, end); @@ -399,6 +465,16 @@ public ImmutableLongArray subArray(int startIndex, int endIndex) { : new ImmutableLongArray(array, start + startIndex, start + endIndex); } + @SuppressWarnings("Java7ApiChecker") + @IgnoreJRERequirement // used only from APIs that use streams + /* + * We declare this as package-private, rather than private, to avoid generating a synthetic + * accessor method (under -target 8) that would lack the Android flavor's @IgnoreJRERequirement. + */ + Spliterator.OfLong spliterator() { + return Spliterators.spliterator(array, start, end, Spliterator.IMMUTABLE | Spliterator.ORDERED); + } + /** * Returns an immutable view of this array's values as a {@code List}; note that {@code * long} values are boxed into {@link Long} instances on demand, which can be very expensive. The @@ -422,7 +498,7 @@ private AsList(ImmutableLongArray parent) { this.parent = parent; } - // inherit: isEmpty, containsAll, toArray x2, iterator, listIterator, mutations + // inherit: isEmpty, containsAll, toArray x2, iterator, listIterator, stream, forEach, mutations @Override public int size() { @@ -454,6 +530,18 @@ public List subList(int fromIndex, int toIndex) { return parent.subArray(fromIndex, toIndex).asList(); } + // The default List spliterator is not efficiently splittable + @Override + @SuppressWarnings("Java7ApiChecker") + /* + * This is an override that is not directly visible to callers, so NewApi will catch calls to + * Collection.spliterator() where necessary. + */ + @IgnoreJRERequirement + public Spliterator spliterator() { + return parent.spliterator(); + } + @Override public boolean equals(@CheckForNull Object object) { if (object instanceof AsList) { diff --git a/android/guava/src/com/google/common/primitives/Ints.java b/android/guava/src/com/google/common/primitives/Ints.java index 95b137edb630..730583f55c14 100644 --- a/android/guava/src/com/google/common/primitives/Ints.java +++ b/android/guava/src/com/google/common/primitives/Ints.java @@ -31,6 +31,8 @@ import java.util.Comparator; import java.util.List; import java.util.RandomAccess; +import java.util.Spliterator; +import java.util.Spliterators; import javax.annotation.CheckForNull; /** @@ -687,6 +689,17 @@ public Integer get(int index) { return array[start + index]; } + @Override + @SuppressWarnings("Java7ApiChecker") + /* + * This is an override that is not directly visible to callers, so NewApi will catch calls to + * Collection.spliterator() where necessary. + */ + @IgnoreJRERequirement + public Spliterator.OfInt spliterator() { + return Spliterators.spliterator(array, start, end, 0); + } + @Override public boolean contains(@CheckForNull Object target) { // Overridden to prevent a ton of boxing diff --git a/android/guava/src/com/google/common/primitives/Longs.java b/android/guava/src/com/google/common/primitives/Longs.java index 03755398480d..fcedce63c2ea 100644 --- a/android/guava/src/com/google/common/primitives/Longs.java +++ b/android/guava/src/com/google/common/primitives/Longs.java @@ -30,6 +30,8 @@ import java.util.Comparator; import java.util.List; import java.util.RandomAccess; +import java.util.Spliterator; +import java.util.Spliterators; import javax.annotation.CheckForNull; /** @@ -751,6 +753,17 @@ public Long get(int index) { return array[start + index]; } + @Override + @SuppressWarnings("Java7ApiChecker") + /* + * This is an override that is not directly visible to callers, so NewApi will catch calls to + * Collection.spliterator() where necessary. + */ + @IgnoreJRERequirement + public Spliterator.OfLong spliterator() { + return Spliterators.spliterator(array, start, end, 0); + } + @Override public boolean contains(@CheckForNull Object target) { // Overridden to prevent a ton of boxing diff --git a/android/pom.xml b/android/pom.xml index 86bcbfdba509..f38a21f729dc 100644 --- a/android/pom.xml +++ b/android/pom.xml @@ -280,7 +280,7 @@ - com.google.common.base.IgnoreJRERequirement,com.google.common.cache.IgnoreJRERequirement,com.google.common.collect.IgnoreJRERequirement,com.google.common.hash.IgnoreJRERequirement,com.google.common.io.IgnoreJRERequirement,com.google.common.math.IgnoreJRERequirement,com.google.common.reflect.IgnoreJRERequirement,com.google.common.testing.IgnoreJRERequirement,com.google.common.util.concurrent.IgnoreJRERequirement + com.google.common.base.IgnoreJRERequirement,com.google.common.cache.IgnoreJRERequirement,com.google.common.collect.IgnoreJRERequirement,com.google.common.hash.IgnoreJRERequirement,com.google.common.io.IgnoreJRERequirement,com.google.common.math.IgnoreJRERequirement,com.google.common.primitives.IgnoreJRERequirement,com.google.common.reflect.IgnoreJRERequirement,com.google.common.testing.IgnoreJRERequirement,com.google.common.util.concurrent.IgnoreJRERequirement true com.toasttab.android diff --git a/guava-tests/test/com/google/common/primitives/ImmutableDoubleArrayTest.java b/guava-tests/test/com/google/common/primitives/ImmutableDoubleArrayTest.java index bd51e0b50f52..789b6de6d694 100644 --- a/guava-tests/test/com/google/common/primitives/ImmutableDoubleArrayTest.java +++ b/guava-tests/test/com/google/common/primitives/ImmutableDoubleArrayTest.java @@ -44,7 +44,9 @@ import junit.framework.TestCase; import junit.framework.TestSuite; -/** @author Kevin Bourrillion */ +/** + * @author Kevin Bourrillion + */ @GwtCompatible(emulated = true) public class ImmutableDoubleArrayTest extends TestCase { // Test all creation paths very lazily: by assuming asList() works diff --git a/guava/src/com/google/common/primitives/IgnoreJRERequirement.java b/guava/src/com/google/common/primitives/IgnoreJRERequirement.java new file mode 100644 index 000000000000..a5afd04818dc --- /dev/null +++ b/guava/src/com/google/common/primitives/IgnoreJRERequirement.java @@ -0,0 +1,30 @@ +/* + * Copyright 2019 The Guava Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except + * in compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software distributed under the License + * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express + * or implied. See the License for the specific language governing permissions and limitations under + * the License. + */ + +package com.google.common.primitives; + +import static java.lang.annotation.ElementType.CONSTRUCTOR; +import static java.lang.annotation.ElementType.METHOD; +import static java.lang.annotation.ElementType.TYPE; + +import java.lang.annotation.Target; + +/** + * Disables Animal Sniffer's checking of compatibility with older versions of Java/Android. + * + *

    Each package's copy of this annotation needs to be listed in our {@code pom.xml}. + */ +@Target({METHOD, CONSTRUCTOR, TYPE}) +@ElementTypesAreNonnullByDefault +@interface IgnoreJRERequirement {} diff --git a/guava/src/com/google/common/primitives/ImmutableDoubleArray.java b/guava/src/com/google/common/primitives/ImmutableDoubleArray.java index 7ee8cfc73b3c..e3f1c215805f 100644 --- a/guava/src/com/google/common/primitives/ImmutableDoubleArray.java +++ b/guava/src/com/google/common/primitives/ImmutableDoubleArray.java @@ -169,7 +169,11 @@ public static ImmutableDoubleArray copyOf(Iterable values) { return builder().addAll(values).build(); } - /** Returns an immutable array containing all the values from {@code stream}, in order. */ + /** + * Returns an immutable array containing all the values from {@code stream}, in order. + * + * @since 22.0 (but only since 33.4.0 in the Android flavor) + */ public static ImmutableDoubleArray copyOf(DoubleStream stream) { // Note this uses very different growth behavior from copyOf(Iterable) and the builder. double[] array = stream.toArray(); @@ -270,6 +274,8 @@ public Builder addAll(Collection values) { /** * Appends all values from {@code stream}, in order, to the end of the values the built {@link * ImmutableDoubleArray} will contain. + * + * @since 22.0 (but only since 33.4.0 in the Android flavor) */ @CanIgnoreReturnValue public Builder addAll(DoubleStream stream) { @@ -413,7 +419,11 @@ public boolean contains(double target) { return indexOf(target) >= 0; } - /** Invokes {@code consumer} for each value contained in this array, in order. */ + /** + * Invokes {@code consumer} for each value contained in this array, in order. + * + * @since 22.0 (but only since 33.4.0 in the Android flavor) + */ public void forEach(DoubleConsumer consumer) { checkNotNull(consumer); for (int i = start; i < end; i++) { @@ -421,7 +431,11 @@ public void forEach(DoubleConsumer consumer) { } } - /** Returns a stream over the values in this array, in order. */ + /** + * Returns a stream over the values in this array, in order. + * + * @since 22.0 (but only since 33.4.0 in the Android flavor) + */ public DoubleStream stream() { return Arrays.stream(array, start, end); } @@ -445,7 +459,11 @@ public ImmutableDoubleArray subArray(int startIndex, int endIndex) { : new ImmutableDoubleArray(array, start + startIndex, start + endIndex); } - private Spliterator.OfDouble spliterator() { + /* + * We declare this as package-private, rather than private, to avoid generating a synthetic + * accessor method (under -target 8) that would lack the Android flavor's @IgnoreJRERequirement. + */ + Spliterator.OfDouble spliterator() { return Spliterators.spliterator(array, start, end, Spliterator.IMMUTABLE | Spliterator.ORDERED); } diff --git a/guava/src/com/google/common/primitives/ImmutableIntArray.java b/guava/src/com/google/common/primitives/ImmutableIntArray.java index f21afe22274e..7badc6f2914f 100644 --- a/guava/src/com/google/common/primitives/ImmutableIntArray.java +++ b/guava/src/com/google/common/primitives/ImmutableIntArray.java @@ -166,7 +166,11 @@ public static ImmutableIntArray copyOf(Iterable values) { return builder().addAll(values).build(); } - /** Returns an immutable array containing all the values from {@code stream}, in order. */ + /** + * Returns an immutable array containing all the values from {@code stream}, in order. + * + * @since 22.0 (but only since 33.4.0 in the Android flavor) + */ public static ImmutableIntArray copyOf(IntStream stream) { // Note this uses very different growth behavior from copyOf(Iterable) and the builder. int[] array = stream.toArray(); @@ -267,6 +271,8 @@ public Builder addAll(Collection values) { /** * Appends all values from {@code stream}, in order, to the end of the values the built {@link * ImmutableIntArray} will contain. + * + * @since 22.0 (but only since 33.4.0 in the Android flavor) */ @CanIgnoreReturnValue public Builder addAll(IntStream stream) { @@ -408,7 +414,11 @@ public boolean contains(int target) { return indexOf(target) >= 0; } - /** Invokes {@code consumer} for each value contained in this array, in order. */ + /** + * Invokes {@code consumer} for each value contained in this array, in order. + * + * @since 22.0 (but only since 33.4.0 in the Android flavor) + */ public void forEach(IntConsumer consumer) { checkNotNull(consumer); for (int i = start; i < end; i++) { @@ -416,7 +426,11 @@ public void forEach(IntConsumer consumer) { } } - /** Returns a stream over the values in this array, in order. */ + /** + * Returns a stream over the values in this array, in order. + * + * @since 22.0 (but only since 33.4.0 in the Android flavor) + */ public IntStream stream() { return Arrays.stream(array, start, end); } @@ -440,7 +454,11 @@ public ImmutableIntArray subArray(int startIndex, int endIndex) { : new ImmutableIntArray(array, start + startIndex, start + endIndex); } - private Spliterator.OfInt spliterator() { + /* + * We declare this as package-private, rather than private, to avoid generating a synthetic + * accessor method (under -target 8) that would lack the Android flavor's @IgnoreJRERequirement. + */ + Spliterator.OfInt spliterator() { return Spliterators.spliterator(array, start, end, Spliterator.IMMUTABLE | Spliterator.ORDERED); } diff --git a/guava/src/com/google/common/primitives/ImmutableLongArray.java b/guava/src/com/google/common/primitives/ImmutableLongArray.java index 3ff21f16cb47..cac27093dcd9 100644 --- a/guava/src/com/google/common/primitives/ImmutableLongArray.java +++ b/guava/src/com/google/common/primitives/ImmutableLongArray.java @@ -168,7 +168,11 @@ public static ImmutableLongArray copyOf(Iterable values) { return builder().addAll(values).build(); } - /** Returns an immutable array containing all the values from {@code stream}, in order. */ + /** + * Returns an immutable array containing all the values from {@code stream}, in order. + * + * @since 22.0 (but only since 33.4.0 in the Android flavor) + */ public static ImmutableLongArray copyOf(LongStream stream) { // Note this uses very different growth behavior from copyOf(Iterable) and the builder. long[] array = stream.toArray(); @@ -269,6 +273,8 @@ public Builder addAll(Collection values) { /** * Appends all values from {@code stream}, in order, to the end of the values the built {@link * ImmutableLongArray} will contain. + * + * @since 22.0 (but only since 33.4.0 in the Android flavor) */ @CanIgnoreReturnValue public Builder addAll(LongStream stream) { @@ -410,7 +416,11 @@ public boolean contains(long target) { return indexOf(target) >= 0; } - /** Invokes {@code consumer} for each value contained in this array, in order. */ + /** + * Invokes {@code consumer} for each value contained in this array, in order. + * + * @since 22.0 (but only since 33.4.0 in the Android flavor) + */ public void forEach(LongConsumer consumer) { checkNotNull(consumer); for (int i = start; i < end; i++) { @@ -418,7 +428,11 @@ public void forEach(LongConsumer consumer) { } } - /** Returns a stream over the values in this array, in order. */ + /** + * Returns a stream over the values in this array, in order. + * + * @since 22.0 (but only since 33.4.0 in the Android flavor) + */ public LongStream stream() { return Arrays.stream(array, start, end); } @@ -442,7 +456,11 @@ public ImmutableLongArray subArray(int startIndex, int endIndex) { : new ImmutableLongArray(array, start + startIndex, start + endIndex); } - private Spliterator.OfLong spliterator() { + /* + * We declare this as package-private, rather than private, to avoid generating a synthetic + * accessor method (under -target 8) that would lack the Android flavor's @IgnoreJRERequirement. + */ + Spliterator.OfLong spliterator() { return Spliterators.spliterator(array, start, end, Spliterator.IMMUTABLE | Spliterator.ORDERED); } diff --git a/pom.xml b/pom.xml index 483579095a16..a6b76710c4a1 100644 --- a/pom.xml +++ b/pom.xml @@ -281,7 +281,7 @@ - com.google.common.base.IgnoreJRERequirement,com.google.common.cache.IgnoreJRERequirement,com.google.common.collect.IgnoreJRERequirement,com.google.common.hash.IgnoreJRERequirement,com.google.common.io.IgnoreJRERequirement,com.google.common.math.IgnoreJRERequirement,com.google.common.reflect.IgnoreJRERequirement,com.google.common.testing.IgnoreJRERequirement,com.google.common.util.concurrent.IgnoreJRERequirement + com.google.common.base.IgnoreJRERequirement,com.google.common.cache.IgnoreJRERequirement,com.google.common.collect.IgnoreJRERequirement,com.google.common.hash.IgnoreJRERequirement,com.google.common.io.IgnoreJRERequirement,com.google.common.math.IgnoreJRERequirement,com.google.common.primitives.IgnoreJRERequirement,com.google.common.reflect.IgnoreJRERequirement,com.google.common.testing.IgnoreJRERequirement,com.google.common.util.concurrent.IgnoreJRERequirement true org.codehaus.mojo.signature