mirror of
https://github.com/openjdk/jdk.git
synced 2025-08-27 14:54:52 +02:00
8238286: Add new flatMap stream operation that is more amenable to pushing
This patch adds a new flatmap-like operation called mapMulti to the java.util.Stream class as well as the primitive variations of this operation i.e. mapMultiToInt, IntStream mapMulti, etc. Reviewed-by: psandoz, smarks
This commit is contained in:
parent
dd89c92c50
commit
79d12507b3
10 changed files with 899 additions and 15 deletions
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright (c) 2013, 2017, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2013, 2020, 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
|
||||
|
@ -304,6 +304,31 @@ abstract class DoublePipeline<E_IN>
|
|||
};
|
||||
}
|
||||
|
||||
@Override
|
||||
public final DoubleStream mapMulti(DoubleMapMultiConsumer mapper) {
|
||||
Objects.requireNonNull(mapper);
|
||||
return new StatelessOp<>(this, StreamShape.DOUBLE_VALUE,
|
||||
StreamOpFlag.NOT_SORTED | StreamOpFlag.NOT_DISTINCT | StreamOpFlag.NOT_SIZED) {
|
||||
|
||||
@Override
|
||||
Sink<Double> opWrapSink(int flags, Sink<Double> sink) {
|
||||
return new Sink.ChainedDouble<>(sink) {
|
||||
|
||||
@Override
|
||||
public void begin(long size) {
|
||||
downstream.begin(-1);
|
||||
}
|
||||
|
||||
@Override
|
||||
@SuppressWarnings("unchecked")
|
||||
public void accept(double t) {
|
||||
mapper.accept(t, (DoubleConsumer) downstream);
|
||||
}
|
||||
};
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
@Override
|
||||
public DoubleStream unordered() {
|
||||
if (!isOrdered())
|
||||
|
|
|
@ -163,6 +163,43 @@ public interface DoubleStream extends BaseStream<Double, DoubleStream> {
|
|||
*/
|
||||
DoubleStream flatMap(DoubleFunction<? extends DoubleStream> mapper);
|
||||
|
||||
/**
|
||||
* Returns a stream consisting of the results of replacing each element of
|
||||
* this stream with multiple elements, specifically zero or more elements.
|
||||
* Replacement is performed by applying the provided mapping function to each
|
||||
* element in conjunction with a {@linkplain DoubleConsumer consumer} argument
|
||||
* that accepts replacement elements. The mapping function calls the consumer
|
||||
* zero or more times to provide the replacement elements.
|
||||
*
|
||||
* <p>This is an <a href="package-summary.html#StreamOps">intermediate
|
||||
* operation</a>.
|
||||
*
|
||||
* <p>If the {@linkplain DoubleConsumer consumer} argument is used outside the scope of
|
||||
* its application to the mapping function, the results are undefined.
|
||||
*
|
||||
* @implSpec
|
||||
* The default implementation invokes {@link #flatMap flatMap} on this stream,
|
||||
* passing a function that behaves as follows. First, it calls the mapper function
|
||||
* with a {@code DoubleConsumer} that accumulates replacement elements into a newly created
|
||||
* internal buffer. When the mapper function returns, it creates a {@code DoubleStream} from the
|
||||
* internal buffer. Finally, it returns this stream to {@code flatMap}.
|
||||
*
|
||||
* @param mapper a <a href="package-summary.html#NonInterference">non-interfering</a>,
|
||||
* <a href="package-summary.html#Statelessness">stateless</a>
|
||||
* function that generates replacement elements
|
||||
* @return the new stream
|
||||
* @see Stream#mapMulti Stream.mapMulti
|
||||
* @since 16
|
||||
*/
|
||||
default DoubleStream mapMulti(DoubleMapMultiConsumer mapper) {
|
||||
Objects.requireNonNull(mapper);
|
||||
return flatMap(e -> {
|
||||
SpinedBuffer.OfDouble buffer = new SpinedBuffer.OfDouble();
|
||||
mapper.accept(e, buffer);
|
||||
return StreamSupport.doubleStream(buffer.spliterator(), false);
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a stream consisting of the distinct elements of this stream. The
|
||||
* elements are compared for equality according to
|
||||
|
@ -1180,4 +1217,30 @@ public interface DoubleStream extends BaseStream<Double, DoubleStream> {
|
|||
*/
|
||||
DoubleStream build();
|
||||
}
|
||||
|
||||
/**
|
||||
* Represents an operation that accepts a {@code double}-valued argument
|
||||
* and a DoubleConsumer, and returns no result. This functional interface is
|
||||
* used by {@link DoubleStream#mapMulti(DoubleMapMultiConsumer) DoubleStream.mapMulti}
|
||||
* to replace a double value with zero or more double values.
|
||||
*
|
||||
* <p>This is a <a href="../function/package-summary.html">functional interface</a>
|
||||
* whose functional method is {@link #accept(double, DoubleConsumer)}.
|
||||
*
|
||||
* @see DoubleStream#mapMulti(DoubleMapMultiConsumer)
|
||||
*
|
||||
* @since 16
|
||||
*/
|
||||
@FunctionalInterface
|
||||
interface DoubleMapMultiConsumer {
|
||||
|
||||
/**
|
||||
* Replaces the given {@code value} with zero or more values by feeding the mapped
|
||||
* values to the {@code dc} consumer.
|
||||
*
|
||||
* @param value the double value coming from upstream
|
||||
* @param dc a {@code DoubleConsumer} accepting the mapped values
|
||||
*/
|
||||
void accept(double value, DoubleConsumer dc);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright (c) 2012, 2017, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2012, 2020, 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
|
||||
|
@ -338,6 +338,30 @@ abstract class IntPipeline<E_IN>
|
|||
};
|
||||
}
|
||||
|
||||
@Override
|
||||
public final IntStream mapMulti(IntMapMultiConsumer mapper) {
|
||||
Objects.requireNonNull(mapper);
|
||||
return new StatelessOp<>(this, StreamShape.INT_VALUE,
|
||||
StreamOpFlag.NOT_SORTED | StreamOpFlag.NOT_DISTINCT | StreamOpFlag.NOT_SIZED) {
|
||||
@Override
|
||||
Sink<Integer> opWrapSink(int flags, Sink<Integer> sink) {
|
||||
return new Sink.ChainedInt<>(sink) {
|
||||
|
||||
@Override
|
||||
public void begin(long size) {
|
||||
downstream.begin(-1);
|
||||
}
|
||||
|
||||
@Override
|
||||
@SuppressWarnings("unchecked")
|
||||
public void accept(int t) {
|
||||
mapper.accept(t, (IntConsumer) downstream);
|
||||
}
|
||||
};
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
@Override
|
||||
public IntStream unordered() {
|
||||
if (!isOrdered())
|
||||
|
|
|
@ -164,6 +164,43 @@ public interface IntStream extends BaseStream<Integer, IntStream> {
|
|||
*/
|
||||
IntStream flatMap(IntFunction<? extends IntStream> mapper);
|
||||
|
||||
/**
|
||||
* Returns a stream consisting of the results of replacing each element of
|
||||
* this stream with multiple elements, specifically zero or more elements.
|
||||
* Replacement is performed by applying the provided mapping function to each
|
||||
* element in conjunction with a {@linkplain IntConsumer consumer} argument
|
||||
* that accepts replacement elements. The mapping function calls the consumer
|
||||
* zero or more times to provide the replacement elements.
|
||||
*
|
||||
* <p>This is an <a href="package-summary.html#StreamOps">intermediate
|
||||
* operation</a>.
|
||||
*
|
||||
* <p>If the {@linkplain IntConsumer consumer} argument is used outside the scope of
|
||||
* its application to the mapping function, the results are undefined.
|
||||
*
|
||||
* @implSpec
|
||||
* The default implementation invokes {@link #flatMap flatMap} on this stream,
|
||||
* passing a function that behaves as follows. First, it calls the mapper function
|
||||
* with an {@code IntConsumer} that accumulates replacement elements into a newly created
|
||||
* internal buffer. When the mapper function returns, it creates an {@code IntStream} from the
|
||||
* internal buffer. Finally, it returns this stream to {@code flatMap}.
|
||||
*
|
||||
* @param mapper a <a href="package-summary.html#NonInterference">non-interfering</a>,
|
||||
* <a href="package-summary.html#Statelessness">stateless</a>
|
||||
* function that generates replacement elements
|
||||
* @return the new stream
|
||||
* @see Stream#mapMulti Stream.mapMulti
|
||||
* @since 16
|
||||
*/
|
||||
default IntStream mapMulti(IntMapMultiConsumer mapper) {
|
||||
Objects.requireNonNull(mapper);
|
||||
return flatMap(e -> {
|
||||
SpinedBuffer.OfInt buffer = new SpinedBuffer.OfInt();
|
||||
mapper.accept(e, buffer);
|
||||
return StreamSupport.intStream(buffer.spliterator(), false);
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a stream consisting of the distinct elements of this stream.
|
||||
*
|
||||
|
@ -1173,4 +1210,30 @@ public interface IntStream extends BaseStream<Integer, IntStream> {
|
|||
*/
|
||||
IntStream build();
|
||||
}
|
||||
|
||||
/**
|
||||
* Represents an operation that accepts an {@code int}-valued argument
|
||||
* and an IntConsumer, and returns no result. This functional interface is
|
||||
* used by {@link IntStream#mapMulti(IntMapMultiConsumer) IntStream.mapMulti}
|
||||
* to replace an int value with zero or more int values.
|
||||
*
|
||||
* <p>This is a <a href="../function/package-summary.html">functional interface</a>
|
||||
* whose functional method is {@link #accept(int, IntConsumer)}.
|
||||
*
|
||||
* @see IntStream#mapMulti(IntMapMultiConsumer)
|
||||
*
|
||||
* @since 16
|
||||
*/
|
||||
@FunctionalInterface
|
||||
interface IntMapMultiConsumer {
|
||||
|
||||
/**
|
||||
* Replaces the given {@code value} with zero or more values by feeding the mapped
|
||||
* values to the {@code ic} consumer.
|
||||
*
|
||||
* @param value the int value coming from upstream
|
||||
* @param ic an {@code IntConsumer} accepting the mapped values
|
||||
*/
|
||||
void accept(int value, IntConsumer ic);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright (c) 2013, 2017, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2013, 2020, 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
|
||||
|
@ -320,6 +320,30 @@ abstract class LongPipeline<E_IN>
|
|||
};
|
||||
}
|
||||
|
||||
@Override
|
||||
public final LongStream mapMulti(LongMapMultiConsumer mapper) {
|
||||
Objects.requireNonNull(mapper);
|
||||
return new LongPipeline.StatelessOp<>(this, StreamShape.LONG_VALUE,
|
||||
StreamOpFlag.NOT_SORTED | StreamOpFlag.NOT_DISTINCT | StreamOpFlag.NOT_SIZED) {
|
||||
@Override
|
||||
Sink<Long> opWrapSink(int flags, Sink<Long> sink) {
|
||||
return new Sink.ChainedLong<>(sink) {
|
||||
|
||||
@Override
|
||||
public void begin(long size) {
|
||||
downstream.begin(-1);
|
||||
}
|
||||
|
||||
@Override
|
||||
@SuppressWarnings("unchecked")
|
||||
public void accept(long t) {
|
||||
mapper.accept(t, (LongConsumer) downstream);
|
||||
}
|
||||
};
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
@Override
|
||||
public LongStream unordered() {
|
||||
if (!isOrdered())
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright (c) 2013, 2016, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2013, 2020, 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
|
||||
|
@ -164,6 +164,43 @@ public interface LongStream extends BaseStream<Long, LongStream> {
|
|||
*/
|
||||
LongStream flatMap(LongFunction<? extends LongStream> mapper);
|
||||
|
||||
/**
|
||||
* Returns a stream consisting of the results of replacing each element of
|
||||
* this stream with multiple elements, specifically zero or more elements.
|
||||
* Replacement is performed by applying the provided mapping function to each
|
||||
* element in conjunction with a {@linkplain LongConsumer consumer} argument
|
||||
* that accepts replacement elements. The mapping function calls the consumer
|
||||
* zero or more times to provide the replacement elements.
|
||||
*
|
||||
* <p>This is an <a href="package-summary.html#StreamOps">intermediate
|
||||
* operation</a>.
|
||||
*
|
||||
* <p>If the {@linkplain LongConsumer consumer} argument is used outside the scope of
|
||||
* its application to the mapping function, the results are undefined.
|
||||
*
|
||||
* @implSpec
|
||||
* The default implementation invokes {@link #flatMap flatMap} on this stream,
|
||||
* passing a function that behaves as follows. First, it calls the mapper function
|
||||
* with a {@code LongConsumer} that accumulates replacement elements into a newly created
|
||||
* internal buffer. When the mapper function returns, it creates a {@code LongStream} from the
|
||||
* internal buffer. Finally, it returns this stream to {@code flatMap}.
|
||||
*
|
||||
* @param mapper a <a href="package-summary.html#NonInterference">non-interfering</a>,
|
||||
* <a href="package-summary.html#Statelessness">stateless</a>
|
||||
* function that generates replacement elements
|
||||
* @return the new stream
|
||||
* @see Stream#mapMulti Stream.mapMulti
|
||||
* @since 16
|
||||
*/
|
||||
default LongStream mapMulti(LongMapMultiConsumer mapper) {
|
||||
Objects.requireNonNull(mapper);
|
||||
return flatMap(e -> {
|
||||
SpinedBuffer.OfLong buffer = new SpinedBuffer.OfLong();
|
||||
mapper.accept(e, buffer);
|
||||
return StreamSupport.longStream(buffer.spliterator(), false);
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a stream consisting of the distinct elements of this stream.
|
||||
*
|
||||
|
@ -1177,4 +1214,30 @@ public interface LongStream extends BaseStream<Long, LongStream> {
|
|||
*/
|
||||
LongStream build();
|
||||
}
|
||||
|
||||
/**
|
||||
* Represents an operation that accepts a {@code long}-valued argument
|
||||
* and a LongConsumer, and returns no result. This functional interface is
|
||||
* used by {@link LongStream#mapMulti(LongStream.LongMapMultiConsumer) LongStream.mapMulti}
|
||||
* to replace a long value with zero or more long values.
|
||||
*
|
||||
* <p>This is a <a href="../function/package-summary.html">functional interface</a>
|
||||
* whose functional method is {@link #accept(long, LongConsumer)}.
|
||||
*
|
||||
* @see LongStream#mapMulti(LongStream.LongMapMultiConsumer)
|
||||
*
|
||||
* @since 16
|
||||
*/
|
||||
@FunctionalInterface
|
||||
interface LongMapMultiConsumer {
|
||||
|
||||
/**
|
||||
* Replaces the given {@code value} with zero or more values by feeding the mapped
|
||||
* values to the {@code lc} consumer.
|
||||
*
|
||||
* @param value the long value coming from upstream
|
||||
* @param lc a {@code LongConsumer} accepting the mapped values
|
||||
*/
|
||||
void accept(long value, LongConsumer lc);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright (c) 2012, 2017, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2012, 2020, 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
|
||||
|
@ -257,7 +257,7 @@ abstract class ReferencePipeline<P_IN, P_OUT>
|
|||
StreamOpFlag.NOT_SORTED | StreamOpFlag.NOT_DISTINCT | StreamOpFlag.NOT_SIZED) {
|
||||
@Override
|
||||
Sink<P_OUT> opWrapSink(int flags, Sink<R> sink) {
|
||||
return new Sink.ChainedReference<P_OUT, R>(sink) {
|
||||
return new Sink.ChainedReference<>(sink) {
|
||||
// true if cancellationRequested() has been called
|
||||
boolean cancellationRequestedCalled;
|
||||
|
||||
|
@ -428,6 +428,103 @@ abstract class ReferencePipeline<P_IN, P_OUT>
|
|||
};
|
||||
}
|
||||
|
||||
@Override
|
||||
public final <R> Stream<R> mapMulti(BiConsumer<? super P_OUT, ? super Consumer<R>> mapper) {
|
||||
Objects.requireNonNull(mapper);
|
||||
return new StatelessOp<>(this, StreamShape.REFERENCE,
|
||||
StreamOpFlag.NOT_SORTED | StreamOpFlag.NOT_DISTINCT | StreamOpFlag.NOT_SIZED) {
|
||||
@Override
|
||||
Sink<P_OUT> opWrapSink(int flags, Sink<R> sink) {
|
||||
return new Sink.ChainedReference<>(sink) {
|
||||
|
||||
@Override
|
||||
public void begin(long size) {
|
||||
downstream.begin(-1);
|
||||
}
|
||||
|
||||
@Override
|
||||
@SuppressWarnings("unchecked")
|
||||
public void accept(P_OUT u) {
|
||||
mapper.accept(u, (Consumer<R>) downstream);
|
||||
}
|
||||
};
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
@Override
|
||||
public final IntStream mapMultiToInt(BiConsumer<? super P_OUT, ? super IntConsumer> mapper) {
|
||||
Objects.requireNonNull(mapper);
|
||||
return new IntPipeline.StatelessOp<>(this, StreamShape.REFERENCE,
|
||||
StreamOpFlag.NOT_SORTED | StreamOpFlag.NOT_DISTINCT | StreamOpFlag.NOT_SIZED) {
|
||||
@Override
|
||||
Sink<P_OUT> opWrapSink(int flags, Sink<Integer> sink) {
|
||||
return new Sink.ChainedReference<>(sink) {
|
||||
|
||||
@Override
|
||||
public void begin(long size) {
|
||||
downstream.begin(-1);
|
||||
}
|
||||
|
||||
@Override
|
||||
@SuppressWarnings("unchecked")
|
||||
public void accept(P_OUT u) {
|
||||
mapper.accept(u, (IntConsumer)downstream);
|
||||
}
|
||||
};
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
@Override
|
||||
public final LongStream mapMultiToLong(BiConsumer<? super P_OUT, ? super LongConsumer> mapper) {
|
||||
Objects.requireNonNull(mapper);
|
||||
return new LongPipeline.StatelessOp<>(this, StreamShape.REFERENCE,
|
||||
StreamOpFlag.NOT_SORTED | StreamOpFlag.NOT_DISTINCT | StreamOpFlag.NOT_SIZED) {
|
||||
@Override
|
||||
Sink<P_OUT> opWrapSink(int flags, Sink<Long> sink) {
|
||||
return new Sink.ChainedReference<>(sink) {
|
||||
|
||||
@Override
|
||||
public void begin(long size) {
|
||||
downstream.begin(-1);
|
||||
}
|
||||
|
||||
@Override
|
||||
@SuppressWarnings("unchecked")
|
||||
public void accept(P_OUT u) {
|
||||
mapper.accept(u, (LongConsumer) downstream);
|
||||
}
|
||||
};
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public final DoubleStream mapMultiToDouble(BiConsumer<? super P_OUT, ? super DoubleConsumer> mapper) {
|
||||
Objects.requireNonNull(mapper);
|
||||
return new DoublePipeline.StatelessOp<>(this, StreamShape.REFERENCE,
|
||||
StreamOpFlag.NOT_SORTED | StreamOpFlag.NOT_DISTINCT | StreamOpFlag.NOT_SIZED) {
|
||||
@Override
|
||||
Sink<P_OUT> opWrapSink(int flags, Sink<Double> sink) {
|
||||
return new Sink.ChainedReference<>(sink) {
|
||||
|
||||
@Override
|
||||
public void begin(long size) {
|
||||
downstream.begin(-1);
|
||||
}
|
||||
|
||||
@Override
|
||||
@SuppressWarnings("unchecked")
|
||||
public void accept(P_OUT u) {
|
||||
mapper.accept(u, (DoubleConsumer) downstream);
|
||||
}
|
||||
};
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
@Override
|
||||
public final Stream<P_OUT> peek(Consumer<? super P_OUT> action) {
|
||||
Objects.requireNonNull(action);
|
||||
|
|
|
@ -26,20 +26,17 @@ package java.util.stream;
|
|||
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Path;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collection;
|
||||
import java.util.Comparator;
|
||||
import java.util.Objects;
|
||||
import java.util.Optional;
|
||||
import java.util.Spliterator;
|
||||
import java.util.Spliterators;
|
||||
import java.util.*;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
import java.util.function.BiConsumer;
|
||||
import java.util.function.BiFunction;
|
||||
import java.util.function.BinaryOperator;
|
||||
import java.util.function.Consumer;
|
||||
import java.util.function.DoubleConsumer;
|
||||
import java.util.function.Function;
|
||||
import java.util.function.IntConsumer;
|
||||
import java.util.function.IntFunction;
|
||||
import java.util.function.LongConsumer;
|
||||
import java.util.function.Predicate;
|
||||
import java.util.function.Supplier;
|
||||
import java.util.function.ToDoubleFunction;
|
||||
|
@ -279,6 +276,7 @@ public interface Stream<T> extends BaseStream<T, Stream<T>> {
|
|||
* function to apply to each element which produces a stream
|
||||
* of new values
|
||||
* @return the new stream
|
||||
* @see #mapMulti
|
||||
*/
|
||||
<R> Stream<R> flatMap(Function<? super T, ? extends Stream<? extends R>> mapper);
|
||||
|
||||
|
@ -342,6 +340,210 @@ public interface Stream<T> extends BaseStream<T, Stream<T>> {
|
|||
*/
|
||||
DoubleStream flatMapToDouble(Function<? super T, ? extends DoubleStream> mapper);
|
||||
|
||||
/**
|
||||
* Returns a stream consisting of the results of replacing each element of
|
||||
* this stream with multiple elements, specifically zero or more elements.
|
||||
* Replacement is performed by applying the provided mapping function to each
|
||||
* element in conjunction with a {@linkplain Consumer consumer} argument
|
||||
* that accepts replacement elements. The mapping function calls the consumer
|
||||
* zero or more times to provide the replacement elements.
|
||||
*
|
||||
* <p>This is an <a href="package-summary.html#StreamOps">intermediate
|
||||
* operation</a>.
|
||||
*
|
||||
* <p>If the {@linkplain Consumer consumer} argument is used outside the scope of
|
||||
* its application to the mapping function, the results are undefined.
|
||||
*
|
||||
* @implSpec
|
||||
* The default implementation invokes {@link #flatMap flatMap} on this stream,
|
||||
* passing a function that behaves as follows. First, it calls the mapper function
|
||||
* with a {@code Consumer} that accumulates replacement elements into a newly created
|
||||
* internal buffer. When the mapper function returns, it creates a stream from the
|
||||
* internal buffer. Finally, it returns this stream to {@code flatMap}.
|
||||
*
|
||||
* @apiNote
|
||||
* This method is similar to {@link #flatMap flatMap} in that it applies a one-to-many
|
||||
* transformation to the elements of the stream and flattens the result elements
|
||||
* into a new stream. This method is preferable to {@code flatMap} in the following
|
||||
* circumstances:
|
||||
* <ul>
|
||||
* <li>When replacing each stream element with a small (possibly zero) number of
|
||||
* elements. Using this method avoids the overhead of creating a new Stream instance
|
||||
* for every group of result elements, as required by {@code flatMap}.</li>
|
||||
* <li>When it is easier to use an imperative approach for generating result
|
||||
* elements than it is to return them in the form of a Stream.</li>
|
||||
* </ul>
|
||||
*
|
||||
* <p>If a lambda expression is provided as the mapper function argument, additional type
|
||||
* information maybe be necessary for proper inference of the element type {@code <R>} of
|
||||
* the returned stream. This can be provided in the form of explicit type declarations for
|
||||
* the lambda parameters or as an explicit type argument to the {@code mapMulti} call.
|
||||
*
|
||||
* <p><b>Examples</b>
|
||||
*
|
||||
* <p>Given a stream of {@code Number} objects, the following
|
||||
* produces a list containing only the {@code Integer} objects:
|
||||
* <pre>{@code
|
||||
* Stream<Number> numbers = ... ;
|
||||
* List<Integer> integers = numbers.<Integer>mapMulti((number, consumer) -> {
|
||||
* if (number instanceof Integer)
|
||||
* consumer.accept((Integer) number);
|
||||
* })
|
||||
* .collect(Collectors.toList());
|
||||
* }</pre>
|
||||
*
|
||||
* <p>If we have an {@code Iterable<Object>} and need to recursively expand its elements
|
||||
* that are themselves of type {@code Iterable}, we can use {@code mapMulti} as follows:
|
||||
* <pre>{@code
|
||||
* class C {
|
||||
* static void expandIterable(Object e, Consumer<Object> c) {
|
||||
* if (e instanceof Iterable) {
|
||||
* for (Object ie: (Iterable<?>) e) {
|
||||
* expandIterable(ie, c);
|
||||
* }
|
||||
* } else if (e != null) {
|
||||
* c.accept(e);
|
||||
* }
|
||||
* }
|
||||
*
|
||||
* public static void main(String[] args) {
|
||||
* Stream<Object> stream = ...;
|
||||
* Stream<Object> expandedStream = stream.mapMulti(C::expandIterable);
|
||||
* }
|
||||
* }
|
||||
* }</pre>
|
||||
*
|
||||
* @param <R> The element type of the new stream
|
||||
* @param mapper a <a href="package-summary.html#NonInterference">non-interfering</a>,
|
||||
* <a href="package-summary.html#Statelessness">stateless</a>
|
||||
* function that generates replacement elements
|
||||
* @return the new stream
|
||||
* @see #flatMap flatMap
|
||||
* @since 16
|
||||
*/
|
||||
default <R> Stream<R> mapMulti(BiConsumer<? super T, ? super Consumer<R>> mapper) {
|
||||
Objects.requireNonNull(mapper);
|
||||
return flatMap(e -> {
|
||||
SpinedBuffer<R> buffer = new SpinedBuffer<>();
|
||||
mapper.accept(e, buffer);
|
||||
return StreamSupport.stream(buffer.spliterator(), false);
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns an {@code IntStream} consisting of the results of replacing each
|
||||
* element of this stream with multiple elements, specifically zero or more
|
||||
* elements.
|
||||
* Replacement is performed by applying the provided mapping function to each
|
||||
* element in conjunction with a {@linkplain IntConsumer consumer} argument
|
||||
* that accepts replacement elements. The mapping function calls the consumer
|
||||
* zero or more times to provide the replacement elements.
|
||||
*
|
||||
* <p>This is an <a href="package-summary.html#StreamOps">intermediate
|
||||
* operation</a>.
|
||||
*
|
||||
* <p>If the {@linkplain IntConsumer consumer} argument is used outside the scope of
|
||||
* its application to the mapping function, the results are undefined.
|
||||
*
|
||||
* @implSpec
|
||||
* The default implementation invokes {@link #flatMapToInt flatMapToInt} on this stream,
|
||||
* passing a function that behaves as follows. First, it calls the mapper function
|
||||
* with an {@code IntConsumer} that accumulates replacement elements into a newly created
|
||||
* internal buffer. When the mapper function returns, it creates an {@code IntStream} from
|
||||
* the internal buffer. Finally, it returns this stream to {@code flatMapToInt}.
|
||||
*
|
||||
* @param mapper a <a href="package-summary.html#NonInterference">non-interfering</a>,
|
||||
* <a href="package-summary.html#Statelessness">stateless</a>
|
||||
* function that generates replacement elements
|
||||
* @return the new stream
|
||||
* @see #mapMulti mapMulti
|
||||
* @since 16
|
||||
*/
|
||||
default IntStream mapMultiToInt(BiConsumer<? super T, ? super IntConsumer> mapper) {
|
||||
Objects.requireNonNull(mapper);
|
||||
return flatMapToInt(e -> {
|
||||
SpinedBuffer.OfInt buffer = new SpinedBuffer.OfInt();
|
||||
mapper.accept(e, buffer);
|
||||
return StreamSupport.intStream(buffer.spliterator(), false);
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a {@code LongStream} consisting of the results of replacing each
|
||||
* element of this stream with multiple elements, specifically zero or more
|
||||
* elements.
|
||||
* Replacement is performed by applying the provided mapping function to each
|
||||
* element in conjunction with a {@linkplain LongConsumer consumer} argument
|
||||
* that accepts replacement elements. The mapping function calls the consumer
|
||||
* zero or more times to provide the replacement elements.
|
||||
*
|
||||
* <p>This is an <a href="package-summary.html#StreamOps">intermediate
|
||||
* operation</a>.
|
||||
*
|
||||
* <p>If the {@linkplain LongConsumer consumer} argument is used outside the scope of
|
||||
* its application to the mapping function, the results are undefined.
|
||||
*
|
||||
* @implSpec
|
||||
* The default implementation invokes {@link #flatMapToLong flatMapToLong} on this stream,
|
||||
* passing a function that behaves as follows. First, it calls the mapper function
|
||||
* with a {@code LongConsumer} that accumulates replacement elements into a newly created
|
||||
* internal buffer. When the mapper function returns, it creates a {@code LongStream} from
|
||||
* the internal buffer. Finally, it returns this stream to {@code flatMapToLong}.
|
||||
*
|
||||
* @param mapper a <a href="package-summary.html#NonInterference">non-interfering</a>,
|
||||
* <a href="package-summary.html#Statelessness">stateless</a>
|
||||
* function that generates replacement elements
|
||||
* @return the new stream
|
||||
* @see #mapMulti mapMulti
|
||||
* @since 16
|
||||
*/
|
||||
default LongStream mapMultiToLong(BiConsumer<? super T, ? super LongConsumer> mapper) {
|
||||
Objects.requireNonNull(mapper);
|
||||
return flatMapToLong(e -> {
|
||||
SpinedBuffer.OfLong buffer = new SpinedBuffer.OfLong();
|
||||
mapper.accept(e, buffer);
|
||||
return StreamSupport.longStream(buffer.spliterator(), false);
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a {@code DoubleStream} consisting of the results of replacing each
|
||||
* element of this stream with multiple elements, specifically zero or more
|
||||
* elements.
|
||||
* Replacement is performed by applying the provided mapping function to each
|
||||
* element in conjunction with a {@linkplain DoubleConsumer consumer} argument
|
||||
* that accepts replacement elements. The mapping function calls the consumer
|
||||
* zero or more times to provide the replacement elements.
|
||||
*
|
||||
* <p>This is an <a href="package-summary.html#StreamOps">intermediate
|
||||
* operation</a>.
|
||||
*
|
||||
* <p>If the {@linkplain DoubleConsumer consumer} argument is used outside the scope of
|
||||
* its application to the mapping function, the results are undefined.
|
||||
*
|
||||
* @implSpec
|
||||
* The default implementation invokes {@link #flatMapToDouble flatMapToDouble} on this stream,
|
||||
* passing a function that behaves as follows. First, it calls the mapper function
|
||||
* with an {@code DoubleConsumer} that accumulates replacement elements into a newly created
|
||||
* internal buffer. When the mapper function returns, it creates a {@code DoubleStream} from
|
||||
* the internal buffer. Finally, it returns this stream to {@code flatMapToDouble}.
|
||||
*
|
||||
* @param mapper a <a href="package-summary.html#NonInterference">non-interfering</a>,
|
||||
* <a href="package-summary.html#Statelessness">stateless</a>
|
||||
* function that generates replacement elements
|
||||
* @return the new stream
|
||||
* @see #mapMulti mapMulti
|
||||
* @since 16
|
||||
*/
|
||||
default DoubleStream mapMultiToDouble(BiConsumer<? super T, ? super DoubleConsumer> mapper) {
|
||||
Objects.requireNonNull(mapper);
|
||||
return flatMapToDouble(e -> {
|
||||
SpinedBuffer.OfDouble buffer = new SpinedBuffer.OfDouble();
|
||||
mapper.accept(e, buffer);
|
||||
return StreamSupport.doubleStream(buffer.spliterator(), false);
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a stream consisting of the distinct elements (according to
|
||||
* {@link Object#equals(Object)}) of this stream.
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue