java8新特性-引用流-skip,limit
skip跳过指定数量的元素,limit返回指定数量的元素。可以用来对少量数据的分页。
例子
List<User> users = new ArrayList<>();
users.add(new User("张三",30));
users.add(new User("李四",39));
users.add(new User("王五",20));
List<User> collect = users.stream().skip(1).limit(1).collect(Collectors.toList());
System.out.println(collect);
输出:

源码分析
ReferencePipeline#skip(long n)
@Override
public final Stream<P_OUT> skip(long n) {
if (n < 0)
throw new IllegalArgumentException(Long.toString(n));
if (n == 0)
return this;
else
return SliceOps.makeRef(this, n, -1);
}
关注SliceOps.makeRef。第二个参数是跳过元素数量,第三个参数是返回指定数量的元素。
ReferencePipeline#limit(long maxSize)
public final Stream<P_OUT> limit(long maxSize) {
if (maxSize < 0)
throw new IllegalArgumentException(Long.toString(maxSize));
return SliceOps.makeRef(this, 0, maxSize);
}
skip和limit不同在于参数不同。
SliceOps#makeRef
public static <T> Stream<T> makeRef(AbstractPipeline<?, T, ?> upstream,
long skip, long limit) {
if (skip < 0)
throw new IllegalArgumentException("Skip must be non-negative: " + skip);
return new ReferencePipeline.StatefulOp<T, T>(upstream, StreamShape.REFERENCE,
flags(limit)) {
Spliterator<T> unorderedSkipLimitSpliterator(Spliterator<T> s,
long skip, long limit, long sizeIfKnown) {
if (skip <= sizeIfKnown) {
// Use just the limit if the number of elements
// to skip is <= the known pipeline size
limit = limit >= 0 ? Math.min(limit, sizeIfKnown - skip) : sizeIfKnown - skip;
skip = 0;
}
return new StreamSpliterators.UnorderedSliceSpliterator.OfRef<>(s, skip, limit);
}
@Override
<P_IN> Spliterator<T> opEvaluateParallelLazy(PipelineHelper<T> helper, Spliterator<P_IN> spliterator) {
long size = helper.exactOutputSizeIfKnown(spliterator);
if (size > 0 && spliterator.hasCharacteristics(Spliterator.SUBSIZED)) {
return new StreamSpliterators.SliceSpliterator.OfRef<>(
helper.wrapSpliterator(spliterator),
skip,
calcSliceFence(skip, limit));
} else if (!StreamOpFlag.ORDERED.isKnown(helper.getStreamAndOpFlags())) {
return unorderedSkipLimitSpliterator(
helper.wrapSpliterator(spliterator),
skip, limit, size);
}
else {
// @@@ OOMEs will occur for LongStream.longs().filter(i -> true).limit(n)
// regardless of the value of n
// Need to adjust the target size of splitting for the
// SliceTask from say (size / k) to say min(size / k, 1 << 14)
// This will limit the size of the buffers created at the leaf nodes
// cancellation will be more aggressive cancelling later tasks
// if the target slice size has been reached from a given task,
// cancellation should also clear local results if any
return new SliceTask<>(this, helper, spliterator, castingArray(), skip, limit).
invoke().spliterator();
}
}
@Override
<P_IN> Node<T> opEvaluateParallel(PipelineHelper<T> helper,
Spliterator<P_IN> spliterator,
IntFunction<T[]> generator) {
long size = helper.exactOutputSizeIfKnown(spliterator);
if (size > 0 && spliterator.hasCharacteristics(Spliterator.SUBSIZED)) {
// Because the pipeline is SIZED the slice spliterator
// can be created from the source, this requires matching
// to shape of the source, and is potentially more efficient
// than creating the slice spliterator from the pipeline
// wrapping spliterator
Spliterator<P_IN> s = sliceSpliterator(helper.getSourceShape(), spliterator, skip, limit);
return Nodes.collect(helper, s, true, generator);
} else if (!StreamOpFlag.ORDERED.isKnown(helper.getStreamAndOpFlags())) {
Spliterator<T> s = unorderedSkipLimitSpliterator(
helper.wrapSpliterator(spliterator),
skip, limit, size);
// Collect using this pipeline, which is empty and therefore
// can be used with the pipeline wrapping spliterator
// Note that we cannot create a slice spliterator from
// the source spliterator if the pipeline is not SIZED
return Nodes.collect(this, s, true, generator);
}
else {
return new SliceTask<>(this, helper, spliterator, generator, skip, limit).
invoke();
}
}
@Override
Sink<T> opWrapSink(int flags, Sink<T> sink) {
return new Sink.ChainedReference<T, T>(sink) {
long n = skip;
long m = limit >= 0 ? limit : Long.MAX_VALUE;
@Override
public void begin(long size) {
downstream.begin(calcSize(size, skip, m));
}
@Override
public void accept(T t) {
if (n == 0) {
if (m > 0) {
m--;
downstream.accept(t);
}
}
else {
n--;
}
}
@Override
public boolean cancellationRequested() {
return m == 0 || downstream.cancellationRequested();
}
};
}
};
}
关注里面的opWrapSink方法:
Sink<T> opWrapSink(int flags, Sink<T> sink) {
return new Sink.ChainedReference<T, T>(sink) {
long n = skip;
long m = limit >= 0 ? limit : Long.MAX_VALUE;
@Override
public void begin(long size) {
downstream.begin(calcSize(size, skip, m));
}
@Override
public void accept(T t) {
if (n == 0) {
if (m > 0) {
m--;
downstream.accept(t);
}
}
else {
n--;
}
}
@Override
public boolean cancellationRequested() {
return m == 0 || downstream.cancellationRequested();
}
};
}
n的初始值是跳过元素数量,m是返回元素数量,最大值是Long.MAX_VALUE。accept的逻辑是首先判断跳过元素数量是否等于0,如果不等于0,将n减-,表示跳过此元素。否则判断m是否大于0,表示是否还要返回的元素,如果还需要返回元素(m>0),调用downstream.accept处理元素,同时将m减1.

浙公网安备 33010602011771号