下面列出了怎么用java.util.Spliterators的API类实例代码及写法,或者点击链接到github查看源代码。
/**
* Streams the set of dates included in the range.
* <p>
* This returns a stream consisting of each date in the range.
* The stream is ordered.
*
* @param startInclusive the start date
* @param endExclusive the end date
* @return the stream of dates from the start to the end
*/
static Stream<LocalDate> stream(LocalDate startInclusive, LocalDate endExclusive) {
Iterator<LocalDate> it = new Iterator<LocalDate>() {
private LocalDate current = startInclusive;
@Override
public LocalDate next() {
LocalDate result = current;
current = plusDays(current, 1);
return result;
}
@Override
public boolean hasNext() {
return current.isBefore(endExclusive);
}
};
long count = endExclusive.toEpochDay() - startInclusive.toEpochDay() + 1;
Spliterator<LocalDate> spliterator = Spliterators.spliterator(it, count,
Spliterator.IMMUTABLE | Spliterator.NONNULL |
Spliterator.DISTINCT | Spliterator.ORDERED | Spliterator.SORTED |
Spliterator.SIZED | Spliterator.SUBSIZED);
return StreamSupport.stream(spliterator, false);
}
private static Stream<Node> toStream( NodeList nodeList )
{
return StreamSupport.stream( new Spliterators.AbstractSpliterator<Node>( Long.MAX_VALUE, Spliterator.ORDERED )
{
private int nextIndex = 0;
@Override
public boolean tryAdvance( Consumer<? super Node> action )
{
if( nextIndex >= nodeList.getLength() )
{
return false;
}
action.accept( nodeList.item( nextIndex ) );
nextIndex++;
return true;
}
}, false );
}
/**
* Returns an infinite sequential ordered {@code DoubleStream} produced by iterative
* application of a function {@code f} to an initial element {@code seed},
* producing a {@code Stream} consisting of {@code seed}, {@code f(seed)},
* {@code f(f(seed))}, etc.
*
* <p>The first element (position {@code 0}) in the {@code DoubleStream}
* will be the provided {@code seed}. For {@code n > 0}, the element at
* position {@code n}, will be the result of applying the function {@code f}
* to the element at position {@code n - 1}.
*
* @param seed the initial element
* @param f a function to be applied to to the previous element to produce
* a new element
* @return a new sequential {@code DoubleStream}
*/
public static DoubleStream iterate(final double seed, final DoubleUnaryOperator f) {
Objects.requireNonNull(f);
final PrimitiveIterator.OfDouble iterator = new PrimitiveIterator.OfDouble() {
double t = seed;
@Override
public boolean hasNext() {
return true;
}
@Override
public double nextDouble() {
double v = t;
t = f.applyAsDouble(t);
return v;
}
};
return StreamSupport.doubleStream(Spliterators.spliteratorUnknownSize(
iterator,
Spliterator.ORDERED | Spliterator.IMMUTABLE | Spliterator.NONNULL), false);
}
@Override
public boolean moveNext() {
switch (this.state) {
case 0:
this.iterator = Spliterators.iterator(this.source);
this.state = 1;
case 1:
if (this.iterator.hasNext()) {
this.current = this.iterator.next();
return true;
}
this.close();
return false;
default:
return false;
}
}
private void processDeletion(ResourceChange change) {
String path = change.getPath();
LOG.debug("Process resource deletion at path {}", path);
Resource parent = resolver.getResource(BINDINGS_PARENT_PATH);
Iterator<Resource> resourceIterator = parent.listChildren();
Stream<Resource> targetStream = StreamSupport.stream(Spliterators.spliteratorUnknownSize(resourceIterator, Spliterator.ORDERED),
false);
targetStream.filter(res -> {
ValueMap properties = res.getValueMap();
LOG.debug("Checking the binding at {}", res.getPath());
String cqConf = properties.get(Constants.PN_CONF, "");
if (StringUtils.isEmpty(cqConf)) {
return false;
}
return path.equals(cqConf + "/" + Constants.COMMERCE_BUCKET_PATH);
}).findFirst().ifPresent(res -> {
LOG.debug("Found a binding at {} that uses {}, we'll delete it", res.getPath(), path);
deleteJcrNode(res);
});
}
/**
* Returns an infinite sequential ordered {@code IntStream} produced by iterative
* application of a function {@code f} to an initial element {@code seed},
* producing a {@code Stream} consisting of {@code seed}, {@code f(seed)},
* {@code f(f(seed))}, etc.
*
* <p>The first element (position {@code 0}) in the {@code IntStream} will be
* the provided {@code seed}. For {@code n > 0}, the element at position
* {@code n}, will be the result of applying the function {@code f} to the
* element at position {@code n - 1}.
*
* @param seed the initial element
* @param f a function to be applied to the previous element to produce
* a new element
* @return A new sequential {@code IntStream}
*/
public static IntStream iterate(final int seed, final IntUnaryOperator f) {
Objects.requireNonNull(f);
final PrimitiveIterator.OfInt iterator = new PrimitiveIterator.OfInt() {
int t = seed;
@Override
public boolean hasNext() {
return true;
}
@Override
public int nextInt() {
int v = t;
t = f.applyAsInt(t);
return v;
}
};
return StreamSupport.intStream(Spliterators.spliteratorUnknownSize(
iterator,
Spliterator.ORDERED | Spliterator.IMMUTABLE | Spliterator.NONNULL), false);
}
/**
* Returns an infinite sequential ordered {@code IntStream} produced by iterative
* application of a function {@code f} to an initial element {@code seed},
* producing a {@code Stream} consisting of {@code seed}, {@code f(seed)},
* {@code f(f(seed))}, etc.
*
* <p>The first element (position {@code 0}) in the {@code IntStream} will be
* the provided {@code seed}. For {@code n > 0}, the element at position
* {@code n}, will be the result of applying the function {@code f} to the
* element at position {@code n - 1}.
*
* @param seed the initial element
* @param f a function to be applied to to the previous element to produce
* a new element
* @return A new sequential {@code IntStream}
*/
public static IntStream iterate(final int seed, final IntUnaryOperator f) {
Objects.requireNonNull(f);
final PrimitiveIterator.OfInt iterator = new PrimitiveIterator.OfInt() {
int t = seed;
@Override
public boolean hasNext() {
return true;
}
@Override
public int nextInt() {
int v = t;
t = f.applyAsInt(t);
return v;
}
};
return StreamSupport.intStream(Spliterators.spliteratorUnknownSize(
iterator,
Spliterator.ORDERED | Spliterator.IMMUTABLE | Spliterator.NONNULL), false);
}
/**
* Returns an infinite sequential ordered {@code LongStream} produced by iterative
* application of a function {@code f} to an initial element {@code seed},
* producing a {@code Stream} consisting of {@code seed}, {@code f(seed)},
* {@code f(f(seed))}, etc.
*
* <p>The first element (position {@code 0}) in the {@code LongStream} will
* be the provided {@code seed}. For {@code n > 0}, the element at position
* {@code n}, will be the result of applying the function {@code f} to the
* element at position {@code n - 1}.
*
* @param seed the initial element
* @param f a function to be applied to the previous element to produce
* a new element
* @return a new sequential {@code LongStream}
*/
public static LongStream iterate(final long seed, final LongUnaryOperator f) {
Objects.requireNonNull(f);
final PrimitiveIterator.OfLong iterator = new PrimitiveIterator.OfLong() {
long t = seed;
@Override
public boolean hasNext() {
return true;
}
@Override
public long nextLong() {
long v = t;
t = f.applyAsLong(t);
return v;
}
};
return StreamSupport.longStream(Spliterators.spliteratorUnknownSize(
iterator,
Spliterator.ORDERED | Spliterator.IMMUTABLE | Spliterator.NONNULL), false);
}
@GET
@Path("_table")
@Timed(name = "bv.emodb.blob.BlobStoreResource1.listTables", absolute = true)
@ApiOperation (value = "List all the tables.",
notes = "Returns a list of tables.",
response = Table.class
)
public Iterator<Table> listTables(@QueryParam("from") final String fromKeyExclusive,
@QueryParam("limit") @DefaultValue("10") LongParam limit,
@Authenticated Subject subject) {
_listTableRequestsByApiKey.getUnchecked(subject.getId()).mark();
return streamingIterator(
StreamSupport.stream(Spliterators.spliteratorUnknownSize(_blobStore.listTables(Strings.emptyToNull(fromKeyExclusive), Long.MAX_VALUE), 0), false)
.filter(input -> subject.hasPermission(Permissions.readBlobTable(new NamedResource(input.getName()))))
.limit(limit.get())
.iterator()
);
}
@Override
public Iterator<M> receiveMessages() {
final MultiIterator<M> multiIterator = new MultiIterator<>();
for (final MessageScope messageScope : this.messageBoard.receiveMessages.keySet()) {
// for (final MessageScope messageScope : this.messageBoard.previousMessageScopes) {
if (messageScope instanceof MessageScope.Local) {
final MessageScope.Local<M> localMessageScope = (MessageScope.Local<M>) messageScope;
final Traversal.Admin<Vertex, Edge> incidentTraversal = TinkerMessenger.setVertexStart(localMessageScope.getIncidentTraversal().get().asAdmin(), this.vertex);
final Direction direction = TinkerMessenger.getDirection(incidentTraversal);
final Edge[] edge = new Edge[1]; // simulates storage side-effects available in Gremlin, but not Java8 streams
multiIterator.addIterator(StreamSupport.stream(Spliterators.spliteratorUnknownSize(VertexProgramHelper.reverse(incidentTraversal.asAdmin()), Spliterator.IMMUTABLE | Spliterator.SIZED), false)
.map((Edge e) -> {
edge[0] = e;
Vertex vv;
if (direction.equals(Direction.IN) || direction.equals(Direction.OUT)) {
vv = e.vertices(direction).next();
} else {
vv = e.outVertex() == this.vertex ? e.inVertex() : e.outVertex();
}
return this.messageBoard.receiveMessages.get(messageScope).get(vv);
})
.filter(q -> null != q)
.flatMap(Queue::stream)
.map(message -> localMessageScope.getEdgeFunction().apply(message, edge[0]))
.iterator());
} else {
multiIterator.addIterator(Stream.of(this.vertex)
.map(this.messageBoard.receiveMessages.get(messageScope)::get)
.filter(q -> null != q)
.flatMap(Queue::stream)
.iterator());
}
}
return multiIterator;
}
public Spliterator<E> trySplit() {
Node<E> p;
final ConcurrentLinkedDeque<E> q = this.queue;
int b = batch;
int n = (b <= 0) ? 1 : (b >= MAX_BATCH) ? MAX_BATCH : b + 1;
if (!exhausted &&
((p = current) != null || (p = q.first()) != null)) {
if (p.item == null && p == (p = p.next))
current = p = q.first();
if (p != null && p.next != null) {
Object[] a = new Object[n];
int i = 0;
do {
if ((a[i] = p.item) != null)
++i;
if (p == (p = p.next))
p = q.first();
} while (p != null && i < n);
if ((current = p) == null)
exhausted = true;
if (i > 0) {
batch = i;
return Spliterators.spliterator
(a, 0, i, Spliterator.ORDERED | Spliterator.NONNULL |
Spliterator.CONCURRENT);
}
}
}
return null;
}
@Override
public Spliterator<T> trySplit() {
Spliterator<T> prefix = source.trySplit();
if (prefix == null) {
return null;
}
if (checked.get()) {
return drop ? prefix : Spliterators.emptySpliterator();
}
UnorderedTDOfRef<T> clone = doClone();
clone.source = prefix;
return clone;
}
/**
* Returns a stream of {@code int} zero-extending the {@code char} values
* from this sequence. Any char which maps to a <a
* href="{@docRoot}/java/lang/Character.html#unicode">surrogate code
* point</a> is passed through uninterpreted.
*
* <p>If the sequence is mutated while the stream is being read, the
* result is undefined.
*
* @return an IntStream of char values from this sequence
* @since 1.8
*/
public default IntStream chars() {
class CharIterator implements PrimitiveIterator.OfInt {
int cur = 0;
public boolean hasNext() {
return cur < length();
}
public int nextInt() {
if (hasNext()) {
return charAt(cur++);
} else {
throw new NoSuchElementException();
}
}
@Override
public void forEachRemaining(IntConsumer block) {
for (; cur < length(); cur++) {
block.accept(charAt(cur));
}
}
}
return StreamSupport.intStream(() ->
Spliterators.spliterator(
new CharIterator(),
length(),
Spliterator.ORDERED),
Spliterator.SUBSIZED | Spliterator.SIZED | Spliterator.ORDERED,
false);
}
public void testSpliteratorObjectArray() {
String[] array = { "a", "b", "c", "d", "e", "f", "g", "h" };
ArrayList<String> expectedValues = new ArrayList<>(Arrays.asList(array));
Spliterator<String> sp = Spliterators.spliterator(array, 0);
assertEquals(8, sp.estimateSize());
assertEquals(8, sp.getExactSizeIfKnown());
sp = Spliterators.spliterator(array, 0);
SpliteratorTester.runBasicIterationTests(sp, expectedValues);
sp = Spliterators.spliterator(array, 0);
SpliteratorTester.testSpliteratorNPE(sp);
sp = Spliterators.spliterator(array, 0);
SpliteratorTester.runBasicSplitTests(sp, expectedValues, String::compareTo);
sp = Spliterators.spliterator(array, 0);
SpliteratorTester.runSizedTests(sp, 8);
sp = Spliterators.spliterator(array, 0);
SpliteratorTester.runSubSizedTests(sp, 8);
// Assert the spliterator inherits any characteristics we ask it to.
sp = Spliterators.spliterator(array, Spliterator.ORDERED);
assertTrue(sp.hasCharacteristics(Spliterator.ORDERED));
}
public Spliterator<E> trySplit() {
Node<E> p;
final ConcurrentLinkedQueue<E> q = this.queue;
int b = batch;
int n = (b <= 0) ? 1 : (b >= MAX_BATCH) ? MAX_BATCH : b + 1;
if (!exhausted &&
((p = current) != null || (p = q.first()) != null) &&
p.next != null) {
Object[] a = new Object[n];
int i = 0;
do {
if ((a[i] = p.item) != null)
++i;
if (p == (p = p.next))
p = q.first();
} while (p != null && i < n);
if ((current = p) == null)
exhausted = true;
if (i > 0) {
batch = i;
return Spliterators.spliterator
(a, 0, i, Spliterator.ORDERED | Spliterator.NONNULL |
Spliterator.CONCURRENT);
}
}
return null;
}
@Test
public void testDoubleSpliterator() {
for (int size : new int[] { 1, 5, 100, 1000, 1023, 1024, 1025, 2049 }) {
double[] input = LongStreamEx.range(size).asDoubleStream().toArray();
checkSpliterator(String.valueOf(size), DoubleStreamEx.of(input).boxed().toList(),
() -> new UnknownSizeSpliterator.USOfDouble(Spliterators.iterator(Spliterators.spliterator(input, 0))));
}
}
public Spliterator<E> trySplit() {
Node<E> h;
final LinkedBlockingQueue<E> q = this.queue;
int b = batch;
int n = (b <= 0) ? 1 : (b >= MAX_BATCH) ? MAX_BATCH : b + 1;
if (!exhausted &&
((h = current) != null || (h = q.head.next) != null) &&
h.next != null) {
Object[] a = new Object[n];
int i = 0;
Node<E> p = current;
q.fullyLock();
try {
if (p != null || (p = q.head.next) != null) {
do {
if ((a[i] = p.item) != null)
++i;
} while ((p = p.next) != null && i < n);
}
} finally {
q.fullyUnlock();
}
if ((current = p) == null) {
est = 0L;
exhausted = true;
}
else if ((est -= i) < 0L)
est = 0L;
if (i > 0) {
batch = i;
return Spliterators.spliterator
(a, 0, i, Spliterator.ORDERED | Spliterator.NONNULL |
Spliterator.CONCURRENT);
}
}
return null;
}
@Override
public Tuple<Collection<ExecutionLineageNode>, Collection<ChannelInstance>> evaluate(
ChannelInstance[] inputs,
ChannelInstance[] outputs,
JavaExecutor executor,
OptimizationContext.OperatorContext operatorContext) {
// Cast the inputs and outputs.
final SqlQueryChannel.Instance input = (SqlQueryChannel.Instance) inputs[0];
final StreamChannel.Instance output = (StreamChannel.Instance) outputs[0];
JdbcPlatformTemplate producerPlatform = (JdbcPlatformTemplate) input.getChannel().getProducer().getPlatform();
final Connection connection = producerPlatform
.createDatabaseDescriptor(executor.getConfiguration())
.createJdbcConnection();
Iterator<Record> resultSetIterator = new ResultSetIterator(connection, input.getSqlQuery());
Spliterator<Record> resultSetSpliterator = Spliterators.spliteratorUnknownSize(resultSetIterator, 0);
Stream<Record> resultSetStream = StreamSupport.stream(resultSetSpliterator, false);
output.accept(resultSetStream);
ExecutionLineageNode queryLineageNode = new ExecutionLineageNode(operatorContext);
queryLineageNode.add(LoadProfileEstimators.createFromSpecification(
String.format("rheem.%s.sqltostream.load.query", this.jdbcPlatform.getPlatformId()),
executor.getConfiguration()
));
queryLineageNode.addPredecessor(input.getLineage());
ExecutionLineageNode outputLineageNode = new ExecutionLineageNode(operatorContext);
outputLineageNode.add(LoadProfileEstimators.createFromSpecification(
String.format("rheem.%s.sqltostream.load.output", this.jdbcPlatform.getPlatformId()),
executor.getConfiguration()
));
output.getLineage().addPredecessor(outputLineageNode);
return queryLineageNode.collectAndMark();
}
@Override
public Iterator<StateEntry<K, N, S>> iterator() {
return Arrays.stream(keyGroupedStateMaps)
.filter(Objects::nonNull)
.flatMap(stateMap -> StreamSupport.stream(Spliterators.spliteratorUnknownSize(stateMap.iterator(), 0), false))
.iterator();
}
/**
* Returns a stream of {@code int} zero-extending the {@code char} values
* from this sequence. Any char which maps to a <a
* href="{@docRoot}/java/lang/Character.html#unicode">surrogate code
* point</a> is passed through uninterpreted.
*
* <p>The stream binds to this sequence when the terminal stream operation
* commences (specifically, for mutable sequences the spliterator for the
* stream is <a href="../util/Spliterator.html#binding"><em>late-binding</em></a>).
* If the sequence is modified during that operation then the result is
* undefined.
*
* @return an IntStream of char values from this sequence
* @since 1.8
*/
public default IntStream chars() {
class CharIterator implements PrimitiveIterator.OfInt {
int cur = 0;
public boolean hasNext() {
return cur < length();
}
public int nextInt() {
if (hasNext()) {
return charAt(cur++);
} else {
throw new NoSuchElementException();
}
}
@Override
public void forEachRemaining(IntConsumer block) {
for (; cur < length(); cur++) {
block.accept(charAt(cur));
}
}
}
return StreamSupport.intStream(() ->
Spliterators.spliterator(
new CharIterator(),
length(),
Spliterator.ORDERED),
Spliterator.SUBSIZED | Spliterator.SIZED | Spliterator.ORDERED,
false);
}
private static <T> Stream<T> streamFromArray(T[] a) {
return StreamSupport.stream(
Spliterators.spliterator(
a,
Spliterator.DISTINCT | Spliterator.IMMUTABLE | Spliterator.NONNULL),
false);
}
public Spliterator<E> trySplit() {
Node<E> h;
final LinkedBlockingQueue<E> q = this.queue;
int b = batch;
int n = (b <= 0) ? 1 : (b >= MAX_BATCH) ? MAX_BATCH : b + 1;
if (!exhausted &&
((h = current) != null || (h = q.head.next) != null) &&
h.next != null) {
Object[] a = new Object[n];
int i = 0;
Node<E> p = current;
q.fullyLock();
try {
if (p != null || (p = q.head.next) != null) {
do {
if ((a[i] = p.item) != null)
++i;
} while ((p = p.next) != null && i < n);
}
} finally {
q.fullyUnlock();
}
if ((current = p) == null) {
est = 0L;
exhausted = true;
}
else if ((est -= i) < 0L)
est = 0L;
if (i > 0) {
batch = i;
return Spliterators.spliterator
(a, 0, i, Spliterator.ORDERED | Spliterator.NONNULL |
Spliterator.CONCURRENT);
}
}
return null;
}
@MustBeClosed
public Stream<ColumnEntry<TKey, TValue>> toStream() {
assertOpen();
final Spliterator<ColumnEntry<TKey, TValue>> split =
Spliterators.spliteratorUnknownSize(
this,
Spliterator.IMMUTABLE
| Spliterator.DISTINCT
| Spliterator.NONNULL
| Spliterator.ORDERED
| Spliterator.SORTED);
return StreamSupport.stream(split, false).onClose(this::close);
}
private <T> T tailSetFieldValue(Row currentRow, Class<? super T> type, T instance) {
List<Integer> mappedColumnIndices = new ArrayList<>();
List<Field> unknownCells = new ArrayList<>();
for (Field field : type.getDeclaredFields()) {
if (field.getAnnotation(ExcelRow.class) != null) {
final int rowNum = currentRow.getRowNum();
final Object data = casting.castValue(field.getType(), valueOf(rowNum), rowNum, -1, options);
setFieldData(instance, field, data);
} else if (field.getAnnotation(ExcelCellRange.class) != null) {
Class<?> fieldType = field.getType();
Object fieldInstance = ReflectUtil.newInstanceOf(fieldType);
for (Field fieldField : fieldType.getDeclaredFields()) {
mappedColumnIndices.add(tailSetFieldValue(currentRow, fieldInstance, fieldField));
}
setFieldData(instance, field, fieldInstance);
} else if (field.getAnnotation(ExcelUnknownCells.class) != null) {
unknownCells.add(field);
} else {
mappedColumnIndices.add(tailSetFieldValue(currentRow, instance, field));
}
}
Map<String, String> excelUnknownCellsMap = StreamSupport
.stream(Spliterators.spliteratorUnknownSize(currentRow.cellIterator(), Spliterator.ORDERED), false)
.filter(cell -> !mappedColumnIndices.contains(cell.getColumnIndex()))
.filter(cell -> !cell.toString().isEmpty())
.collect(Collectors.toMap(
cell -> caseSensitiveTitlePerColumnIndex.get(cell.getColumnIndex()),
Object::toString
));
unknownCells.forEach(field -> setFieldData(instance, field, excelUnknownCellsMap));
return instance;
}
@PostConstruct
private void init() {
latestApiVersion = StreamSupport
.stream(Spliterators.spliteratorUnknownSize(applications.iterator(), Spliterator.IMMUTABLE), false)
.filter(a -> a.getClass().isAnnotationPresent(ApplicationPath.class))
.map(a -> a.getClass().getAnnotation(ApplicationPath.class).value())
.map(path -> path.replace("api/v", ""))
.mapToInt(Integer::parseInt)
.max()
.orElse(1);
startTime = new Date();
}
@Override
void setReferences(Map<String, EDIType> types) {
super.setReferences(types);
StreamSupport.stream(Spliterators.spliteratorUnknownSize(implementedTypes.descendingIterator(),
Spliterator.ORDERED),
false)
.filter(type -> type.getType() != Type.ELEMENT)
.map(type -> (BaseComplexImpl) type)
.forEach(type -> setReferences(type, types));
}
/**
* Create a stream of long values from iterating through a dataset
* @param a dataset
* @return long stream
*/
public static LongStream createDatasetStream(LongDataset a, boolean parallel) {
if (a.getStrides() == null) {
StreamSupport.longStream(Spliterators.spliterator(a.getData(), FLAGS), parallel);
}
return StreamSupport.longStream(new LongDatasetSpliterator(a), parallel);
}
@Override
public Stream<Place> streamAll() {
Context timer = streamAllTimer.time();
Iterator<Row> rows = session.execute(streamAll.bind()).iterator();
Iterator<Place> result = TimingIterator.time(
Iterators.transform(rows, (row) -> buildEntity(row)),
timer
);
Spliterator<Place> stream = Spliterators.spliteratorUnknownSize(result, Spliterator.IMMUTABLE | Spliterator.NONNULL);
return StreamSupport.stream(stream, false);
}
/**
* Don't use this directly, use select()... spliterator instead where possible.
* Otherwise, insure the FSIterator instance can support sized/subsized.
* @return a split iterator for this iterator, which has the following characteristics
* DISTINCT, SIZED, SUBSIZED
*
*/
default Spliterator<T> spliterator() {
return Spliterators.spliterator(
this,
((LowLevelIterator<T>)this).ll_indexSizeMaybeNotCurrent(),
Spliterator.DISTINCT |
Spliterator.SIZED |
Spliterator.SUBSIZED);
}
/**
* Returns a {@code Stream}, the elements of which are lines read from
* this {@code BufferedReader}. The {@link Stream} is lazily populated,
* i.e., read only occurs during the
* <a href="../util/stream/package-summary.html#StreamOps">terminal
* stream operation</a>.
*
* <p> The reader must not be operated on during the execution of the
* terminal stream operation. Otherwise, the result of the terminal stream
* operation is undefined.
*
* <p> After execution of the terminal stream operation there are no
* guarantees that the reader will be at a specific position from which to
* read the next character or line.
*
* <p> If an {@link IOException} is thrown when accessing the underlying
* {@code BufferedReader}, it is wrapped in an {@link
* UncheckedIOException} which will be thrown from the {@code Stream}
* method that caused the read to take place. This method will return a
* Stream if invoked on a BufferedReader that is closed. Any operation on
* that stream that requires reading from the BufferedReader after it is
* closed, will cause an UncheckedIOException to be thrown.
*
* @return a {@code Stream<String>} providing the lines of text
* described by this {@code BufferedReader}
*
* @since 1.8
*/
public Stream<String> lines() {
Iterator<String> iter = new Iterator<String>() {
String nextLine = null;
@Override
public boolean hasNext() {
if (nextLine != null) {
return true;
} else {
try {
nextLine = readLine();
return (nextLine != null);
} catch (IOException e) {
throw new UncheckedIOException(e);
}
}
}
@Override
public String next() {
if (nextLine != null || hasNext()) {
String line = nextLine;
nextLine = null;
return line;
} else {
throw new NoSuchElementException();
}
}
};
return StreamSupport.stream(Spliterators.spliteratorUnknownSize(
iter, Spliterator.ORDERED | Spliterator.NONNULL), false);
}