AutoCloseable
doc
一个对象,它可以保存资源(如文件或套接字句柄)直到它被关闭。当退出已在资源规范头中声明对象的try with resources块时,将自动调用自动关闭对象的close()方法。这种结构确保了及时发布,避免了资源耗尽异常和可能发生的错误。
实例
public class AutoCloseableTest implements AutoCloseable {
@Override
public void close() throws Exception {
System.out.println("关闭数据");
}
public static void main(String[] args) throws Exception {
//此时程序执行完会自动调用AutoCloseableTest该方法执行代码块
try(AutoCloseableTest test = new AutoCloseableTest()) {
System.out.println("数据执行");
}
}
}
/*
数据执行
关闭数据
*/
BaseStream
也就是说 Stream流返回的类型是BaseStream中新的返回流类型
/**
返回此流元素的迭代器。
*/
Iterator<T> iterator();
/**
返回此流元素的分隔迭代器。
这是流的终止操作
*/
Spliterator<T> spliterator();
/**
返回如果要执行终端操作,此流是否将并行执行。
调用流的终止操作方法后,调用此方法可能会产生不可预测的结果。
(意思我们使用时的在流的终止操作之前使用它)
*/
boolean isParallel();
/**
返回一个的等价的串行流。可能返回自身,原因可能是流已经是串行的,
也可能是基础流状态被修改为串行流(串行和并行方法 调用多次返回最后那个那个流)
这是一个中间操作
*/
S sequential();
/*
返回的等价并行流。可能会返回自身,原因可能已经是并行流,
也可能是基础流状态已修改为并行流
这是一个中间操作
*/
S parallel();
/*
返回未排序的等效流。可能会返回自身,原因可能是流已无序,
也可能是基础流状态已修改为无序。
这是一个中间操作
*/
S unordered();
/*
返回具有附加关闭处理程序的等效流。Close处理程序在对流调用Close()方法时运行,并按添加顺序执行。
所有onClose程序都将会运行,即使以前的关闭处理程序引发异常。如果任何close处理程序抛出异常,
则抛出的第一个异常返回给close()的调用方,
而该异常中添加的任何剩余异常都将作为抑制异常(除非剩余异常之一与第一个异常是同一个异常,
因为异常无法抑制自身)返回自身。
*/
S onClose(Runnable closeHandler);
/**
关闭此流,导致调用此流管道的所有关闭处理程序
*/
@Override
void close();
onClose示例
public class StreamTest2 {
public static void main(String[] args) {
List<String> list = Arrays.asList("hello", "nihao", "你好");
/*
onClose会在 close方法调用后去执行
*/
try (Stream<String> stream = list.stream()) {
stream.onClose(() -> {
System.out.println("aaa");
}).onClose(() -> {
System.out.println("bbb");
}).forEach(System.out::println);
}
}
}
/*
hello
nihao
你好
aaa
bbb
*/
抛出1个异常
抛出2个不同异常
抛出相同异常
Stream方法源码解析
doc节选(重要)
- 为了执行计算,流操作被组合成流管道。流管道由源(可能是数组、集合、生成器函数、I/O通道等)、零个或多个中间操作(将流转换为另一个流,如筛选器(谓词))和终端操作(产生结果或副作用,如count()或forEach(Consumer))组成。流是惰性的;只有在启动终端操作时才对源数据执行计算,并且仅根据需要使用源元素。
- 大多数流操作接受描述用户指定行为的参数为了保持正确的行为,这些行为参数:必须是无干扰的(它们不会修改流源)以及在大多数情况下必须是无状态的(它们的结果不应该依赖于流管道执行期间可能更改的任何状态,类似操作同一种行为每个流元素执行顺序不同造成结果不同)
- 这些参数总是函数接口(如函数)的实例,通常是lambda表达式或方法引用。除非另有规定,否则这些参数必须为非空。
- 一个流只能操作一次(调用中间或终端流操作)
- Streams有一个close()方法并实现了AutoCloseable,但实际上几乎所有的stream实例在使用后都不需要关闭。
- 流管道可以按串行执行,也可以并行执行。此执行模式是流的属性。流是通过串行或并行执行的初始选择创建的。(例如,集合.stream()创建顺序流,并且Collection.parallelStream集合(创建一个并行的)此执行模式的选择可以由sequential()(串行)或parallel()(并行同时使用以后面的为主)方法修改,也可以使用isParallel()方法查询。
- 集合和流,虽然有一些表面上的相似之处,但有不同的目标。集合主要涉及对其元素的有效管理(增删改)和访问。相比之下,流不提供直接访问或操作其元素的方法,而是涉及声明性地描述其源和将在该源上聚合执行的计算操作。但是,如果提供的流操作没有提供所需的功能,则可以使用iterator()和spliterator()操作来执行受控遍历。
/*
Stream.of("one", "two", "three", "four")
* .filter(e -> e.length() > 3)
* .peek(e -> System.out.println("Filtered value: " + e))
* .map(String::toUpperCase)
* .peek(e -> System.out.println("Mapped value: " + e))
* .collect(Collectors.toList());
对元素属性进行处理消费,同时返回流 (系统自动返回Consumer无返回值)
*/
Stream<T> peek(Consumer<? super T> action);
示例
public class StreamTest3 {
public static void main(String[] args) {
List<String> list = Arrays.asList("nihao", "hello", "你好");
//没有中间操作执行流程
// list.stream().forEach(System.out::println);
//存在中间操作执行流程
list.stream().map(x -> x + ",").filter(x -> true).forEach(System.out::println);
}
}
Collection.stream
/*
返回以该集合为源的串行流。此时上例list.stream() 调用结束
当spliterator()方法无法返回不可变、并发或延迟绑定的spliterator时,应重写此方法。(有关详细信息,请参见拆分器()。)
{(后续调用方法看下分析)
*/
default Stream<E> stream()
return StreamSupport.stream(spliterator(), false);
}
// 调用改方法返回迭代器 将集合和 特性传递过去
@Override
default Spliterator<E> spliterator() {
return Spliterators.spliterator(this, 0);
}
辅助类
Spliterator分割迭代器
Spliterators实现重新了
/*
如果有剩余元素存在,则对其执行给定行为,返回true;否则返回false。
如果这个分拆器被命令,则在遇到顺序中的下一个元素上执行动作。操作引发的异常将中继到调用方。
(判断有没有下一个元素有执行下一个动作)
*/
boolean tryAdvance(Consumer<? super T> action);
/**
对当前线程中的每个剩余元素按串行执行给定的操作,
直到处理完所有元素或操作引发异常。如果此拆分器已排序,
则按遇到顺序执行操作。操作引发的异常将中继到调用方。
*/
default void forEachRemaining(Consumer<? super T> action) {
//对剩余元素执行了操作返回 Boolean值
do { } while (tryAdvance(action));
}
/*
如果此分隔器可以被分隔的,则返回一个涵盖元素的分隔迭代器,
此分割迭代器在从该方法返回时将不被此分割迭代器涵盖。
(就是被分割出来的元素存储到返回的分割迭代器,剩余的继续存到当前的分隔迭代器当中)
如果此拆分器已ORDERED排序,则返回的拆分器必须包含元素也应该排序
除非此拆分器包含无限多个元素,否则对trySplit()的重复调用最终结果必须返回null(无法进一步分隔)。
返回值不为null时:
分隔前为estimateSize()报告的值在拆分后必须大于或等于当前分隔器和返回的分隔器的
estimateSize();以及
如果此分隔器是SUBSIZED,则拆分前此分隔器的estimateSize()必须等于此分隔器的
estimateSize()和分隔后返回的分隔器的总和
A=T+newA
此方法可能因任何原因返回null,包括空性、开始遍历后无法拆分、数据结构约束和效率考虑。
理想的trySplit方法有效地(无遍历)将元素精确地分成两半,允许平衡的并行计算。此时并行
计算效率最高,当分隔的极度不平衡时此时并行效率最低
*/
Spliterator<T> trySplit();
/*
返回forEachRemaining遍历将遇到的元素数的估计值,
或返回Long.MAX_值(如果是无限的,未知的,或者计算成本太高而无法计算。)
如果此分隔器已固定大小SIZED且尚未部分遍历或拆分,
或者此分隔器已子化SUBSIZED且尚未部分遍历,
则此估算值一定是遇到的元素的精确计数值。
如果不满足上面调价,这个估计可能是任意不准确的,
但必须在调用trySplit时减少。
*/
long estimateSize();
/*
如果此分割器已调整大小,则返回estimateSize()的便利方法,否则返回-1。
*/
default long getExactSizeIfKnown() {
return (characteristics() & SIZED) == 0 ? -1L : estimateSize();
}
/*
返回分割器的特性值
*/
int characteristics();
/*
判断是否包含传过来的特性值
*/
default boolean hasCharacteristics(int characteristics) {
return (characteristics() & characteristics) == characteristics;
}
/*
如果此拆分器的源由比较器排序,则返回该比较器。
如果源按自然顺序排序,则返回null。
否则,如果源未排序,则抛出IllegalStateException。
*/
default Comparator<? super T> getComparator() {
throw new IllegalStateException();
}
//有序
public static final int ORDERED = 0x00000010;
//不同
public static final int DISTINCT = 0x00000001;
//排序
public static final int SORTED = 0x00000004;
/*
确定大小
特征值,表示在遍历或拆分之前从estimateSize()返回的值表示在没有结构源修改的情况下,
表示完整遍历将遇到的元素数的精确计数的有限大小。
*/
public static final int SIZED = 0x00000040;
//不为空的
public static final int NONNULL = 0x00000100;
/*
不可变的
特征值,表示不能在结构上修改元素源;
也就是说,不能添加、替换或删除元素,因此在遍历期间不能发生此类更改。
如果在遍历期间被修改则会抛出ConcurrentModificationException
*/
public static final int IMMUTABLE = 0x00000400;
//并发的
public static final int CONCURRENT = 0x00001000;
//元素分割完确定大小的
public static final int SUBSIZED = 0x00004000;
/**
*/
Spliterator.OfPrimitive 内部接口
专门针对于原生值类型(Int Long Double)的迭代器。主要起到中介的作用
Spliterator.OfInt 内部接口
public interface OfInt extends OfPrimitive<Integer, IntConsumer, OfInt> {
@Override
OfInt trySplit();
@Override
boolean tryAdvance(IntConsumer action);
@Override
default void forEachRemaining(IntConsumer action) {
do { } while (tryAdvance(action));
}
/**
实现的是顶层Spliterator的tryAdvance方法
*/
@Override
default boolean tryAdvance(Consumer<? super Integer> action) {
if (action instanceof IntConsumer) {
return tryAdvance((IntConsumer) action);
}
else {
if (Tripwire.ENABLED)
Tripwire.trip(getClass(),
"{0} calling Spliterator.OfInt.tryAdvance((IntConsumer) action::accept)");
return tryAdvance((IntConsumer) action::accept);
}
}
@Override
default void forEachRemaining(Consumer<? super Integer> action) {
//action 可能传递 行为 也有可能传递Consumer对象(面向对象)
if (action instanceof IntConsumer) {
//如果传递的是IntConsumer实例可以直接转换成对象
forEachRemaining((IntConsumer) action);
}
else {
if (Tripwire.ENABLED)
Tripwire.trip(getClass(),
"{0} calling Spliterator.OfInt.forEachRemaining((IntConsumer) action::accept)");
//如果不是传他的方法引用
forEachRemaining((IntConsumer) action::accept);
}
}
}
//类似上
@Override
default boolean tryAdvance(Consumer<? super Integer> action) {
if (action instanceof IntConsumer) {
return tryAdvance((IntConsumer) action);
}
else {
if (Tripwire.ENABLED)
Tripwire.trip(getClass(),
"{0} calling Spliterator.OfInt.tryAdvance((IntConsumer) action::accept)");
return tryAdvance((IntConsumer) action::accept);
}
}
例
public class ConsumerTest {
public void test(Consumer<Integer> consumer) {
consumer.accept(1000);
}
public static void main(String[] args) {
ConsumerTest consumerTest = new ConsumerTest();
Consumer<Integer> consumer = x -> System.out.println(x);
IntConsumer intConsumer = x -> System.out.println(x);
System.out.println(consumer instanceof Consumer);//true
System.out.println(intConsumer instanceof Consumer);//false
consumerTest.test(consumer);//面向对象的方式传递
consumerTest.test((Consumer) intConsumer);//此时会报错
consumerTest.test(intConsumer::accept);//将行为传递过去了 函数式方式
}
}
Spliterators工厂类
//内部类
static class IteratorSpliterator<T> implements Spliterator<T> {
static final int BATCH_UNIT = 1 << 10; // batch array size increment
static final int MAX_BATCH = 1 << 25; // max batch array size;
private final Collection<? extends T> collection; // null OK
private Iterator<? extends T> it; //collection集合的迭代器
private final int characteristics; //特性值
private long est; // 估算的大小
private int batch; // 分批拆的大小
//
public IteratorSpliterator(Collection<? extends T> collection, int characteristics) {
//集合创建流是传过来的collection存储到内部类
this.collection = collection;
//此时刚调用时定义的迭代器为null
this.it = null;
//存储特性值
this.characteristics = (characteristics & Spliterator.CONCURRENT) == 0
? characteristics | Spliterator.SIZED | Spliterator.SUBSIZED
: characteristics;
}
@Override
public void forEachRemaining(Consumer<? super T> action) {
//传过来的集合不能为空
if (action == null) throw new NullPointerException();
//定义个迭代器
Iterator<? extends T> i;
//判断内部类定义的迭代器是否为空
if ((i = it) == null) {
i = it = collection.iterator();
//设置分隔迭代器的大小估值
est = (long)collection.size();
}
//调用Iterator迭代器的默认方法forEachRemaining 执行action行为
i.forEachRemaining(action);
}
ReferencePipeline引用管道(重要)
doc
中间管道阶段或管道源阶段实现的抽象基类(将流的源和中间操作统一在一个类),其元素为U类型。
- ReferencePipeline表示流的源阶段与中间阶段
- ReferencePipeline.Head表示流的源阶段
- 二者在大部分属性的设定上都是类似的,但存在一些属性是不同的,比如说Head是没有previousStage的,而ReferencePipeline则存在等等
/*
流管道头(源)的构造函数。
*/
ReferencePipeline(Spliterator<?> source,
int sourceFlags, boolean parallel) {
//AbstractPipeline构造方法进行构造
super(source, sourceFlags, parallel);
}
/**
*用于将中间操作附加到现有管道的构造函数。
(流的串联)
*
* @param upstream the upstream element source.
*/
ReferencePipeline(AbstractPipeline<?, P_IN, ?> upstream, int opFlags) {
super(upstream, opFlags);
}
// Optimized sequential terminal operations for the head of the pipeline
//他是针对优化串行管道源的终止操作(就是stream()之后进行操作无中间操作时)
@Override
public void forEach(Consumer<? super E_OUT> action) {
//!isParallel 也就是是串行时
if (!isParallel()) {
/*
调用源分割器的的forEachRemaining方法执行每个流数据
此时需要操作的数据已经在源分割迭代器当中
*/
sourceStageSpliterator().forEachRemaining(action);
}
else {//执行一般操作
super.forEach(action);
}
}
/*
map的实现方法
*/
@Override
@SuppressWarnings("unchecked")
public final <R> Stream<R> map(Function<? super P_OUT, ? extends R> mapper) {
Objects.requireNonNull(mapper);
//创建一个无状态的中间阶段将其追加到上游管道上
return new StatelessOp<P_OUT, R>(this, StreamShape.REFERENCE,
StreamOpFlag.NOT_SORTED | StreamOpFlag.NOT_DISTINCT) {
@Override
Sink<P_OUT> opWrapSink(int flags, Sink<R> sink) {
/*
Sink实例用于表示此管道的每个阶段 (具体阅读doc)
向下游发送值时必须调用accept(int)方法
而Sink 在接收参数时先发调用bigin方法
accept方法执行完 必须调用end方法
Sink.ChainedReference创建一个链接引用 此时已经将
begin、end和cancellationRequested方法连接到下游接收器
此时下游自动执行连接引用方法(begin ,end) 当方法accept执行完直接
自动调用down方法
*/
return new Sink.ChainedReference<P_OUT, R>(sink) {
@Override
public void accept(P_OUT u) {
//此时才是执行的真正操作 操作当前生成的元素值
//同时调用downstream下游的行为
//其他中间操作类似
downstream.accept(mapper.apply(u));
}
};
}
};
}
/**
* 通过将无状态中间操作附加到现有流来构造新流。
*
* @param <E_IN> 上游源中的元素类型
* @param <E_OUT> 本阶段生产的元素类型
* @since 1.8
*/
abstract static class StatelessOp<E_IN, E_OUT>
extends ReferencePipeline<E_IN, E_OUT> {
/**
通过将无状态中间操作附加到现有流来构造新流。
*
* @param upstream 上游管道阶段
* @param inputShape 上游管道的结果类型
* @param opFlags 新阶段的操作标志
*/
StatelessOp(AbstractPipeline<?, E_IN, ?> upstream,
StreamShape inputShape,
int opFlags) {
super(upstream, opFlags);
//断言 上游的结果 一定要等于当前输入的结果类型
assert upstream.getOutputShape() == inputShape;
}
@Override
final boolean opIsStateful() {
return false;
}
}
ReferencePipeline.Head<E_IN,E_OUT>
源阶段
E_IN:上游阶段源元素类型
E_OUT:当前阶段生成的元素类型
static class Head<E_IN, E_OUT> extends ReferencePipeline<E_IN, E_OUT> {
Head(Supplier<? extends Spliterator<?>> source,
int sourceFlags, boolean parallel) {
super(source, sourceFlags, parallel);
}
/**
* 源阶段的构造方法
* source: 源数据
* sourceFlags: 流的特性值
* parallel:
*/
Head(Spliterator<?> source,
int sourceFlags, boolean parallel) {
//调用ReferencePipeline的构造方法 构造源
super(source, sourceFlags, parallel);
}
@Override
final boolean opIsStateful() {
throw new UnsupportedOperationException();
}
@Override
final Sink<E_IN> opWrapSink(int flags, Sink<E_OUT> sink) {
throw new UnsupportedOperationException();
}
AbstractPipeline抽象管道
E_IN:上游阶段源元素类型
E_OUT:当前阶段生成的元素类型
S:实现BaseStream的接口类型
doc
- “管道”类的抽象基类,它是流接口及其原始特化(IntStream)的核心实现。管理流管道的构建和计算。
- AbstractPipeline表示流管道的初始部分,封装流源和零个或多个中间操作。各个抽象管道对象通常称为阶段,每个阶段描述是流源或中间操作。
- 在链接一个新的中间操作或执行一个终端操作之后,流被认为是被消费的,并且在这个流实例上不允许再进行中间或终端操作。
- 具体的中间阶段通常是从抽象管道、特化管道类(例如,IntPipeline)和扩展它的特定于操作的具体类构建的。AbstractPipeline包含了计算管道的大多数机制,并实现了操作的使用的方法;特定于的原生类添加了辅助方法,用于将结果收集到相应的特化的容器中。
- 对于串行流和没有状态中间操作的并行流,并行流的管道计算是在一次传递中完成的,它“阻塞”了所有的操作。(就是每个元素执行了所有的中间操作再去执行下一个,当中间为假就不会往下执行)
- 对于具有状态操作的并行流,执行被划分为多个段,其中每个状态操作标记一个段的结束,每个段单独计算并将结果用作下一个段的输入。在所有情况下,在终端操作开始之前不会使用源数据
类的一些重要方法和属性
/**
反向链接到管道链的头部(如果这是源级,则为自己)
( 一般就是通过这个去链接源头跟中间操作)
*/
@SuppressWarnings("rawtypes")
private final AbstractPipeline sourceStage;
/**
*“上游”管道,如果这是源阶段,则为空。
*/
@SuppressWarnings("rawtypes")
private final AbstractPipeline previousStage;
/**
源分隔迭代器(此时集合数据已经存在到迭代器的一个常量属性当中)。仅对总管有效。
在使用管道之前,如果非空,则sourceSupplier必须为空。
在使用管道之后,如果非空,则设置为空(流已经被消费无法被使用)。
sourceSpliterator与sourceSupplier 是互斥只能一个为空
两个必须的又一个为非空
*/
private Spliterator<?> sourceSpliterator;
/**
源提供者。仅对总管有效。如果非空,则在使用管道之前,sourceSpliterator必须为空。
在使用管道之后,如果非空,则设置为空。
*/
private Supplier<? extends Spliterator<?>> sourceSupplier;
/**
* True if this pipeline has been linked or consumed
* 如果此管道已链接或使用,则为True
*/
private boolean linkedOrConsumed;
/**
* 他下一个阶段正在进行,如果这是最后一个阶段,则为空
* 有效地在连接到下一个管道时结束。
*/
@SuppressWarnings("rawtypes")
private AbstractPipeline nextStage;
/**
* “上游”管道,如果这是源阶段,则为空。
*/
@SuppressWarnings("rawtypes")
private final AbstractPipeline previousStage;
/**
在此管道对象与流源之间的中间操作个数(如果是串行的)或前一个状态(如果是并行的)。
在管道准备计算时有效
(此管道对象和流的源的中间操作个数)
*/
private int depth;
/**
如果管道是并行的,则为True;否则管道是串行的;仅对源阶段有效。
*/
private boolean parallel;
/*
ReferencePipeline调用的父类的构造方法
(构造源节点)
*/
AbstractPipeline(Supplier<? extends Spliterator<?>> source,
int sourceFlags, boolean parallel) {
//源调用时为null
this.previousStage = null;
//源分隔迭代器
this.sourceSupplier = source;
//链接头部(源所有是自己)
this.sourceStage = this;
this.sourceOrOpFlags = sourceFlags & StreamOpFlag.STREAM_MASK;
// The following is an optimization of:
// StreamOpFlag.combineOpFlags(sourceOrOpFlags, StreamOpFlag.INITIAL_OPS_VALUE);
this.combinedFlags = (~(sourceOrOpFlags << 1)) & StreamOpFlag.INITIAL_OPS_VALUE;
//此对象和源头之间的中间操作的个数(head是源头 源头与源头之间0个中间操作)
this.depth = 0;
//是否是并行
this.parallel = parallel;
}
/*
用于将中间操作阶段附加到现有管道pipeline上的构造函数。
(将中间操作阶段附加到现有管道pipeline)
*/
AbstractPipeline(AbstractPipeline<?, E_IN, ?> previousStage, int opFlags) {
if (previousStage.linkedOrConsumed)
// 如果流已经被使用直接抛出异常
throw new IllegalStateException(MSG_STREAM_LINKED);
//标识现有管道已经被使用
previousStage.linkedOrConsumed = true;
//标识下个中间操作头是目前的管道
previousStage.nextStage = this;
//将传过来的上游管道赋值
this.previousStage = previousStage;
this.sourceOrOpFlags = opFlags & StreamOpFlag.OP_MASK;
this.combinedFlags = StreamOpFlag.combineOpFlags(opFlags, previousStage.combinedFlags);
//得到连接头 连接上一个源
this.sourceStage = previousStage.sourceStage;
if (opIsStateful())
sourceStage.sourceAnyStateful = true;
//中间操作加1
this.depth = previousStage.depth + 1;
}
//来自流的终端操作
// 当Stream.forEach有中间操作调用此forEach
@Override
public void forEach(Consumer<? super E_OUT> action) {
if (!isParallel()) {
/*
传入的迭代器是返回实现类IteratorSpliterator
所以此时调用的是该类的forEachRemaining
具体细节看Spliterators的方法讲解
*/
sourceStageSpliterator().forEachRemaining(action);
}
else {
super.forEach(action);
}
}
/*
如果此管道阶段是源阶段,则获取源阶段分隔迭代器。调用此方法将消费该管道,并成功返回。
*/
final Spliterator<E_OUT> sourceStageSpliterator() {
//当不是处于源阶段直接抛出异常
if (this != sourceStage)
throw new IllegalStateException();
//如果g该管道被链接或者被消费
if (linkedOrConsumed)
throw new IllegalStateException(MSG_STREAM_LINKED);
//消费了= true 表示该管道不能被使用
linkedOrConsumed = true;
/*
源 通过两种方式构建sourceStage.sourceSpliterator或者
sourceStage.sourceSupplier
*/
if (sourceStage.sourceSpliterator != null) {
//返回一个Spliterator对象
@SuppressWarnings("unchecked")
Spliterator<E_OUT> s = sourceStage.sourceSpliterator;
//管道一旦被操作 必须将其设置为空
sourceStage.sourceSpliterator = null;
return s;
}
else if (sourceStage.sourceSupplier != null) {
//源进行操作返回一个Spliterator对象
@SuppressWarnings("unchecked")
Spliterator<E_OUT> s = (Spliterator<E_OUT>) sourceStage.sourceSupplier.get();
//管道一旦被操作 必须将其设置为空
sourceStage.sourceSupplier = null;
return s;
}
else {
throw new IllegalStateException(MSG_CONSUMED);
}
}
Sink
doc
- Consumer的一种扩展,用于在首次调用接收器上的accept()方法之前,通过流管道的各个阶段执行值,并使用其他方法管理大小信息、控制流等,必须首先调用begin()方法来通知它数据即将到来(可选地通知接收器有多少数据即将到来),并且在发送完所有数据之后,必须调用end()方法。调用end()之后,不应在不再次调用begin()的情况下调用accept())。Sink还提供了一种机制,通过这种机制,Sink可以协同地发出不希望接收更多数据的信号(cancellationRequested()方法),源可以在向Sink发送更多数据之前对其进行轮询。
- 接收器可能处于两种状态之一:初始状态和激活状态。它从初始状态开始;begin()方法将其转换为激活状态,end()方法将其转换回初始状态,在初始状态中可以重用它。数据接受方法(如accept()仅在活动状态下有效。
用于创建汇链的抽象汇实现。begin、end和cancellationRequested方法连接到下游接收器。