Input: Returns a Flowable that emits only the last item emitted by the source Publisher during sequential time windows of a specified duration where the duration is governed by a specified Scheduler . <p > This differs from { @link #throttleFirst } in that this ticks along at a scheduled interval whereas { @link #throttleFirst } does not tick it just tracks the passage of time . <p > <img width = 640 height = 305 src = https : // raw . github . com / wiki / ReactiveX / RxJava / images / rx - operators / throttleLast . s . png alt = > <dl > <dt > <b > Backpressure : < / b > < / dt > <dd > This operator does not support backpressure as it uses time to control data flow . < / dd > <dt > <b > Scheduler : < / b > < / dt > <dd > You specify which { @link Scheduler } this operator will use . < / dd > < / dl > [CODESPLIT] @ CheckReturnValue @ BackpressureSupport ( BackpressureKind . ERROR ) @ SchedulerSupport ( SchedulerSupport . CUSTOM ) public final Flowable < T > throttleLast ( long intervalDuration , TimeUnit unit , Scheduler scheduler ) { return sample ( intervalDuration , unit , scheduler ) ; }


Input: Returns a Flowable that mirrors the source Publisher except that it drops items emitted by the source Publisher that are followed by newer items before a timeout value expires on a specified Scheduler . The timer resets on each emission ( alias to { @link #debounce ( long TimeUnit Scheduler ) } ) . <p > <em > Note : < / em > If items keep being emitted by the source Publisher faster than the timeout then no items will be emitted by the resulting Publisher . <p > <img width = 640 height = 305 src = https : // raw . github . com / wiki / ReactiveX / RxJava / images / rx - operators / throttleWithTimeout . s . png alt = > <dl > <dt > <b > Backpressure : < / b > < / dt > <dd > This operator does not support backpressure as it uses time to control data flow . < / dd > <dt > <b > Scheduler : < / b > < / dt > <dd > You specify which { @link Scheduler } this operator will use . < / dd > < / dl > [CODESPLIT] @ CheckReturnValue @ BackpressureSupport ( BackpressureKind . ERROR ) @ SchedulerSupport ( SchedulerSupport . CUSTOM ) public final Flowable < T > throttleWithTimeout ( long timeout , TimeUnit unit , Scheduler scheduler ) { return debounce ( timeout , unit , scheduler ) ; }


Input: Returns a Flowable that emits records of the time interval between consecutive items emitted by the source Publisher . <p > <img width = 640 height = 310 src = https : // raw . github . com / wiki / ReactiveX / RxJava / images / rx - operators / timeInterval . png alt = > <dl > <dt > <b > Backpressure : < / b > < / dt > <dd > The operator doesn t interfere with backpressure which is determined by the source { @code Publisher } s backpressure behavior . < / dd > <dt > <b > Scheduler : < / b > < / dt > <dd > { @code timeInterval } does not operate on any particular scheduler but uses the current time from the { @code computation } { @link Scheduler } . < / dd > < / dl > [CODESPLIT] @ CheckReturnValue @ BackpressureSupport ( BackpressureKind . PASS_THROUGH ) @ SchedulerSupport ( SchedulerSupport . NONE ) public final Flowable < Timed < T > > timeInterval ( TimeUnit unit ) { return timeInterval ( unit , Schedulers . computation ( ) ) ; }


Input: Returns a Flowable that emits records of the time interval between consecutive items emitted by the source Publisher where this interval is computed on a specified Scheduler . <p > <img width = 640 height = 315 src = https : // raw . github . com / wiki / ReactiveX / RxJava / images / rx - operators / timeInterval . s . png alt = > <dl > <dt > <b > Backpressure : < / b > < / dt > <dd > The operator doesn t interfere with backpressure which is determined by the source { @code Publisher } s backpressure behavior . < / dd > <dt > <b > Scheduler : < / b > < / dt > <dd > The operator does not operate on any particular scheduler but uses the current time from the specified { @link Scheduler } . < / dd > < / dl > [CODESPLIT] @ CheckReturnValue @ BackpressureSupport ( BackpressureKind . PASS_THROUGH ) @ SchedulerSupport ( SchedulerSupport . NONE ) // Supplied scheduler is only used for creating timestamps. public final Flowable < Timed < T > > timeInterval ( TimeUnit unit , Scheduler scheduler ) { ObjectHelper . requireNonNull ( unit , "unit is null" ) ; ObjectHelper . requireNonNull ( scheduler , "scheduler is null" ) ; return RxJavaPlugins . onAssembly ( new FlowableTimeInterval < T > ( this , unit , scheduler ) ) ; }


Input: Returns a Flowable that mirrors the source Publisher but notifies Subscribers of a { @code TimeoutException } if an item emitted by the source Publisher doesn t arrive within a window of time after the emission of the previous item where that period of time is measured by a Publisher that is a function of the previous item . <p > <img width = 640 height = 400 src = https : // raw . github . com / wiki / ReactiveX / RxJava / images / rx - operators / timeout3 . png alt = > <p > Note : The arrival of the first source item is never timed out . <dl > <dt > <b > Backpressure : < / b > < / dt > <dd > The operator honors backpressure from downstream . The { @code Publisher } sources are expected to honor backpressure as well . If any of the source { @code Publisher } s violate this it <em > may< / em > throw an { @code IllegalStateException } when the source { @code Publisher } completes . < / dd > <dt > <b > Scheduler : < / b > < / dt > <dd > This version of { @code timeout } operates by default on the { @code immediate } { @link Scheduler } . < / dd > < / dl > [CODESPLIT] @ CheckReturnValue @ BackpressureSupport ( BackpressureKind . PASS_THROUGH ) @ SchedulerSupport ( SchedulerSupport . NONE ) public final < V > Flowable < T > timeout ( Function < ? super T , ? extends Publisher < V > > itemTimeoutIndicator ) { return timeout0 ( null , itemTimeoutIndicator , null ) ; }


Input: Returns a Flowable that mirrors the source Publisher but applies a timeout policy for each emitted item . If the next item isn t emitted within the specified timeout duration starting from its predecessor the resulting Publisher terminates and notifies Subscribers of a { @code TimeoutException } . <p > <img width = 640 height = 305 src = https : // raw . github . com / wiki / ReactiveX / RxJava / images / rx - operators / timeout . 1 . png alt = > <dl > <dt > <b > Backpressure : < / b > < / dt > <dd > The operator doesn t interfere with backpressure which is determined by the source { @code Publisher } s backpressure behavior . < / dd > <dt > <b > Scheduler : < / b > < / dt > <dd > This version of { @code timeout } operates by default on the { @code computation } { @link Scheduler } . < / dd > < / dl > [CODESPLIT] @ CheckReturnValue @ BackpressureSupport ( BackpressureKind . PASS_THROUGH ) @ SchedulerSupport ( SchedulerSupport . COMPUTATION ) public final Flowable < T > timeout ( long timeout , TimeUnit timeUnit ) { return timeout0 ( timeout , timeUnit , null , Schedulers . computation ( ) ) ; }


Input: Returns a Flowable that mirrors the source Publisher but applies a timeout policy for each emitted item where this policy is governed by a specified Scheduler . If the next item isn t emitted within the specified timeout duration starting from its predecessor the resulting Publisher terminates and notifies Subscribers of a { @code TimeoutException } . <p > <img width = 640 height = 305 src = https : // raw . github . com / wiki / ReactiveX / RxJava / images / rx - operators / timeout . 1s . png alt = > <dl > <dt > <b > Backpressure : < / b > < / dt > <dd > The operator doesn t interfere with backpressure which is determined by the source { @code Publisher } s backpressure behavior . < / dd > <dt > <b > Scheduler : < / b > < / dt > <dd > You specify which { @link Scheduler } this operator will use . < / dd > < / dl > [CODESPLIT] @ CheckReturnValue @ BackpressureSupport ( BackpressureKind . PASS_THROUGH ) @ SchedulerSupport ( SchedulerSupport . CUSTOM ) public final Flowable < T > timeout ( long timeout , TimeUnit timeUnit , Scheduler scheduler ) { return timeout0 ( timeout , timeUnit , null , scheduler ) ; }


Input: Returns a Flowable that mirrors the source Publisher but notifies Subscribers of a { @code TimeoutException } if either the first item emitted by the source Publisher or any subsequent item doesn t arrive within time windows defined by other Publishers . <p > <img width = 640 height = 400 src = https : // raw . github . com / wiki / ReactiveX / RxJava / images / rx - operators / timeout5 . png alt = > <dl > <dt > <b > Backpressure : < / b > < / dt > <dd > The operator honors backpressure from downstream . Both this and the returned { @code Publisher } s are expected to honor backpressure as well . If any of then violates this rule it <em > may< / em > throw an { @code IllegalStateException } when the { @code Publisher } completes . < / dd > <dt > <b > Scheduler : < / b > < / dt > <dd > { @code timeout } does not operate by default on any { @link Scheduler } . < / dd > < / dl > [CODESPLIT] @ CheckReturnValue @ NonNull @ BackpressureSupport ( BackpressureKind . PASS_THROUGH ) @ SchedulerSupport ( SchedulerSupport . NONE ) public final < U , V > Flowable < T > timeout ( Publisher < U > firstTimeoutIndicator , Function < ? super T , ? extends Publisher < V > > itemTimeoutIndicator ) { ObjectHelper . requireNonNull ( firstTimeoutIndicator , "firstTimeoutIndicator is null" ) ; return timeout0 ( firstTimeoutIndicator , itemTimeoutIndicator , null ) ; }


Input: Returns a Flowable that emits each item emitted by the source Publisher wrapped in a { @link Timed } object whose timestamps are provided by a specified Scheduler . <p > <img width = 640 height = 310 src = https : // raw . github . com / wiki / ReactiveX / RxJava / images / rx - operators / timestamp . s . png alt = > <dl > <dt > <b > Backpressure : < / b > < / dt > <dd > The operator doesn t interfere with backpressure which is determined by the source { @code Publisher } s backpressure behavior . < / dd > <dt > <b > Scheduler : < / b > < / dt > <dd > This operator does not operate on any particular scheduler but uses the current time from the specified { @link Scheduler } . < / dd > < / dl > [CODESPLIT] @ CheckReturnValue @ BackpressureSupport ( BackpressureKind . PASS_THROUGH ) @ SchedulerSupport ( SchedulerSupport . NONE ) // Supplied scheduler is only used for creating timestamps. public final Flowable < Timed < T > > timestamp ( Scheduler scheduler ) { return timestamp ( TimeUnit . MILLISECONDS , scheduler ) ; }


Input: Calls the specified converter function during assembly time and returns its resulting value . <p > This allows fluent conversion to any other type . <dl > <dt > <b > Backpressure : < / b > < / dt > <dd > The backpressure behavior depends on what happens in the { [CODESPLIT] @ CheckReturnValue @ BackpressureSupport ( BackpressureKind . SPECIAL ) @ SchedulerSupport ( SchedulerSupport . NONE ) public final < R > R to ( Function < ? super Flowable < T > , R > converter ) { try { return ObjectHelper . requireNonNull ( converter , "converter is null" ) . apply ( this ) ; } catch ( Throwable ex ) { Exceptions . throwIfFatal ( ex ) ; throw ExceptionHelper . wrapOrThrow ( ex ) ; } }


Input: Returns a Single that emits a single item a list composed of all the items emitted by the finite upstream source Publisher . <p > <img width = 640 height = 305 src = https : // raw . github . com / wiki / ReactiveX / RxJava / images / rx - operators / toList . png alt = > <p > Normally a Publisher that returns multiple items will do so by invoking its { @link Subscriber } s { @link Subscriber#onNext onNext } method for each such item . You can change this behavior instructing the Publisher to compose a list of all of these items and then to invoke the Subscriber s { @code onNext } function once passing it the entire list by calling the Publisher s { @code toList } method prior to calling its { @link #subscribe } method . <p > Note that this operator requires the upstream to signal { @code onComplete } for the accumulated list to be emitted . Sources that are infinite and never complete will never emit anything through this operator and an infinite source may lead to a fatal { @code OutOfMemoryError } . <dl > <dt > <b > Backpressure : < / b > < / dt > <dd > The operator honors backpressure from downstream and consumes the source { @code Publisher } in an unbounded manner ( i . e . without applying backpressure to it ) . < / dd > <dt > <b > Scheduler : < / b > < / dt > <dd > { @code toList } does not operate by default on a particular { @link Scheduler } . < / dd > < / dl > [CODESPLIT] @ CheckReturnValue @ BackpressureSupport ( BackpressureKind . UNBOUNDED_IN ) @ SchedulerSupport ( SchedulerSupport . NONE ) public final Single < List < T > > toList ( ) { return RxJavaPlugins . onAssembly ( new FlowableToListSingle < T , List < T > > ( this ) ) ; }


Input: Returns a Single that emits a single item a list composed of all the items emitted by the finite source Publisher . <p > <img width = 640 height = 305 src = https : // raw . github . com / wiki / ReactiveX / RxJava / images / rx - operators / toList . png alt = > <p > Normally a Publisher that returns multiple items will do so by invoking its { @link Subscriber } s { @link Subscriber#onNext onNext } method for each such item . You can change this behavior instructing the Publisher to compose a list of all of these items and then to invoke the Subscriber s { @code onNext } function once passing it the entire list by calling the Publisher s { @code toList } method prior to calling its { @link #subscribe } method . <p > Note that this operator requires the upstream to signal { @code onComplete } for the accumulated list to be emitted . Sources that are infinite and never complete will never emit anything through this operator and an infinite source may lead to a fatal { @code OutOfMemoryError } . <dl > <dt > <b > Backpressure : < / b > < / dt > <dd > The operator honors backpressure from downstream and consumes the source { @code Publisher } in an unbounded manner ( i . e . without applying backpressure to it ) . < / dd > <dt > <b > Scheduler : < / b > < / dt > <dd > { @code toList } does not operate by default on a particular { @link Scheduler } . < / dd > < / dl > [CODESPLIT] @ CheckReturnValue @ BackpressureSupport ( BackpressureKind . UNBOUNDED_IN ) @ SchedulerSupport ( SchedulerSupport . NONE ) public final Single < List < T > > toList ( final int capacityHint ) { ObjectHelper . verifyPositive ( capacityHint , "capacityHint" ) ; return RxJavaPlugins . onAssembly ( new FlowableToListSingle < T , List < T > > ( this , Functions . < T > createArrayList ( capacityHint ) ) ) ; }


Input: Returns a Single that emits a single item a list composed of all the items emitted by the finite source Publisher . <p > <img width = 640 height = 305 src = https : // raw . github . com / wiki / ReactiveX / RxJava / images / rx - operators / toList . png alt = > <p > Normally a Publisher that returns multiple items will do so by invoking its { @link Subscriber } s { @link Subscriber#onNext onNext } method for each such item . You can change this behavior instructing the Publisher to compose a list of all of these items and then to invoke the Subscriber s { @code onNext } function once passing it the entire list by calling the Publisher s { @code toList } method prior to calling its { @link #subscribe } method . <p > Note that this operator requires the upstream to signal { @code onComplete } for the accumulated collection to be emitted . Sources that are infinite and never complete will never emit anything through this operator and an infinite source may lead to a fatal { @code OutOfMemoryError } . <dl > <dt > <b > Backpressure : < / b > < / dt > <dd > The operator honors backpressure from downstream and consumes the source { @code Publisher } in an unbounded manner ( i . e . without applying backpressure to it ) . < / dd > <dt > <b > Scheduler : < / b > < / dt > <dd > { @code toList } does not operate by default on a particular { @link Scheduler } . < / dd > < / dl > [CODESPLIT] @ CheckReturnValue @ BackpressureSupport ( BackpressureKind . UNBOUNDED_IN ) @ SchedulerSupport ( SchedulerSupport . NONE ) public final < U extends Collection < ? super T > > Single < U > toList ( Callable < U > collectionSupplier ) { ObjectHelper . requireNonNull ( collectionSupplier , "collectionSupplier is null" ) ; return RxJavaPlugins . onAssembly ( new FlowableToListSingle < T , U > ( this , collectionSupplier ) ) ; }


Input: Returns a Single that emits a single Map returned by a specified { @code mapFactory } function that contains a custom collection of values extracted by a specified { @code valueSelector } function from items emitted by the finite source Publisher and keyed by the { @code keySelector } function . <p > <img width = 640 height = 305 src = https : // raw . github . com / wiki / ReactiveX / RxJava / images / rx - operators / toMultiMap . png alt = > <p > Note that this operator requires the upstream to signal { @code onComplete } for the accumulated map to be emitted . Sources that are infinite and never complete will never emit anything through this operator and an infinite source may lead to a fatal { @code OutOfMemoryError } . <dl > <dt > <b > Backpressure : < / b > < / dt > <dd > The operator honors backpressure from downstream and consumes the source { @code Publisher } in an unbounded manner ( i . e . without applying backpressure to it ) . < / dd > <dt > <b > Scheduler : < / b > < / dt > <dd > { @code toMultimap } does not operate by default on a particular { @link Scheduler } . < / dd > < / dl > [CODESPLIT] @ CheckReturnValue @ NonNull @ BackpressureSupport ( BackpressureKind . UNBOUNDED_IN ) @ SchedulerSupport ( SchedulerSupport . NONE ) public final < K , V > Single < Map < K , Collection < V > > > toMultimap ( final Function < ? super T , ? extends K > keySelector , final Function < ? super T , ? extends V > valueSelector , final Callable < ? extends Map < K , Collection < V > > > mapSupplier , final Function < ? super K , ? extends Collection < ? super V > > collectionFactory ) { ObjectHelper . requireNonNull ( keySelector , "keySelector is null" ) ; ObjectHelper . requireNonNull ( valueSelector , "valueSelector is null" ) ; ObjectHelper . requireNonNull ( mapSupplier , "mapSupplier is null" ) ; ObjectHelper . requireNonNull ( collectionFactory , "collectionFactory is null" ) ; return collect ( mapSupplier , Functions . toMultimapKeyValueSelector ( keySelector , valueSelector , collectionFactory ) ) ; }


Input: Converts the current Flowable into a non - backpressured { [CODESPLIT] @ CheckReturnValue @ BackpressureSupport ( BackpressureKind . UNBOUNDED_IN ) @ SchedulerSupport ( SchedulerSupport . NONE ) public final Observable < T > toObservable ( ) { return RxJavaPlugins . onAssembly ( new ObservableFromPublisher < T > ( this ) ) ; }


Input: Returns a Single that emits a list that contains the items emitted by the finite source Publisher in a sorted order . Each item emitted by the Publisher must implement { @link Comparable } with respect to all other items in the sequence . [CODESPLIT] @ CheckReturnValue @ BackpressureSupport ( BackpressureKind . UNBOUNDED_IN ) @ SchedulerSupport ( SchedulerSupport . NONE ) public final Single < List < T > > toSortedList ( ) { return toSortedList ( Functions . naturalComparator ( ) ) ; }


Input: Modifies the source Publisher so that subscribers will cancel it on a specified { @link Scheduler } . <dl > <dt > <b > Backpressure : < / b > < / dt > <dd > The operator doesn t interfere with backpressure which is determined by the source { @code Publisher } s backpressure behavior . < / dd > <dt > <b > Scheduler : < / b > < / dt > <dd > You specify which { @link Scheduler } this operator will use . < / dd > < / dl > [CODESPLIT] @ CheckReturnValue @ NonNull @ BackpressureSupport ( BackpressureKind . PASS_THROUGH ) @ SchedulerSupport ( SchedulerSupport . CUSTOM ) public final Flowable < T > unsubscribeOn ( Scheduler scheduler ) { ObjectHelper . requireNonNull ( scheduler , "scheduler is null" ) ; return RxJavaPlugins . onAssembly ( new FlowableUnsubscribeOn < T > ( this , scheduler ) ) ; }


Input: Returns a Flowable that emits windows of items it collects from the source Publisher . The resulting Publisher emits connected non - overlapping windows each containing { @code count } items . When the source Publisher completes or encounters an error the resulting Publisher emits the current window and propagates the notification from the source Publisher . <p > <img width = 640 height = 400 src = https : // raw . github . com / wiki / ReactiveX / RxJava / images / rx - operators / window3 . png alt = > <dl > <dt > <b > Backpressure : < / b > < / dt > <dd > The operator honors backpressure of its inner and outer subscribers however the inner Publisher uses an unbounded buffer that may hold at most { @code count } elements . < / dd > <dt > <b > Scheduler : < / b > < / dt > <dd > This version of { @code window } does not operate by default on a particular { @link Scheduler } . < / dd > < / dl > [CODESPLIT] @ CheckReturnValue @ BackpressureSupport ( BackpressureKind . FULL ) @ SchedulerSupport ( SchedulerSupport . NONE ) public final Flowable < Flowable < T > > window ( long count ) { return window ( count , count , bufferSize ( ) ) ; }


Input: Returns a Flowable that emits windows of items it collects from the source Publisher . The resulting Publisher emits windows every { @code skip } items each containing no more than { @code count } items . When the source Publisher completes or encounters an error the resulting Publisher emits the current window and propagates the notification from the source Publisher . <p > <img width = 640 height = 365 src = https : // raw . github . com / wiki / ReactiveX / RxJava / images / rx - operators / window4 . png alt = > <dl > <dt > <b > Backpressure : < / b > < / dt > <dd > The operator honors backpressure of its inner and outer subscribers however the inner Publisher uses an unbounded buffer that may hold at most { @code count } elements . < / dd > <dt > <b > Scheduler : < / b > < / dt > <dd > This version of { @code window } does not operate by default on a particular { @link Scheduler } . < / dd > < / dl > [CODESPLIT] @ CheckReturnValue @ BackpressureSupport ( BackpressureKind . FULL ) @ SchedulerSupport ( SchedulerSupport . NONE ) public final Flowable < Flowable < T > > window ( long count , long skip , int bufferSize ) { ObjectHelper . verifyPositive ( skip , "skip" ) ; ObjectHelper . verifyPositive ( count , "count" ) ; ObjectHelper . verifyPositive ( bufferSize , "bufferSize" ) ; return RxJavaPlugins . onAssembly ( new FlowableWindow < T > ( this , count , skip , bufferSize ) ) ; }


Input: Returns a Flowable that emits windows of items it collects from the source Publisher . The resulting Publisher starts a new window periodically as determined by the { @code timeskip } argument . It emits each window after a fixed timespan specified by the { @code timespan } argument . When the source Publisher completes or Publisher completes or encounters an error the resulting Publisher emits the current window and propagates the notification from the source Publisher . <p > <img width = 640 height = 335 src = https : // raw . github . com / wiki / ReactiveX / RxJava / images / rx - operators / window7 . png alt = > <dl > <dt > <b > Backpressure : < / b > < / dt > <dd > The operator consumes the source { @code Publisher } in an unbounded manner . The returned { @code Publisher } doesn t support backpressure as it uses time to control the creation of windows . The returned inner { @code Publisher } s honor backpressure but have an unbounded inner buffer that <em > may< / em > lead to { @code OutOfMemoryError } if left unconsumed . < / dd > <dt > <b > Scheduler : < / b > < / dt > <dd > This version of { @code window } operates by default on the { @code computation } { @link Scheduler } . < / dd > < / dl > [CODESPLIT] @ CheckReturnValue @ BackpressureSupport ( BackpressureKind . ERROR ) @ SchedulerSupport ( SchedulerSupport . COMPUTATION ) public final Flowable < Flowable < T > > window ( long timespan , long timeskip , TimeUnit unit ) { return window ( timespan , timeskip , unit , Schedulers . computation ( ) , bufferSize ( ) ) ; }


Input: Returns a Flowable that emits windows of items it collects from the source Publisher . The resulting Publisher emits connected non - overlapping windows each of a fixed duration as specified by the { @code timespan } argument or a maximum size as specified by the { @code count } argument ( whichever is reached first ) . When the source Publisher completes or encounters an error the resulting Publisher emits the current window and propagates the notification from the source Publisher . <p > <img width = 640 height = 370 src = https : // raw . github . com / wiki / ReactiveX / RxJava / images / rx - operators / window6 . png alt = > <dl > <dt > <b > Backpressure : < / b > < / dt > <dd > The operator consumes the source { @code Publisher } in an unbounded manner . The returned { @code Publisher } doesn t support backpressure as it uses time to control the creation of windows . The returned inner { @code Publisher } s honor backpressure and may hold up to { @code count } elements at most . < / dd > <dt > <b > Scheduler : < / b > < / dt > <dd > This version of { @code window } operates by default on the { @code computation } { @link Scheduler } . < / dd > < / dl > [CODESPLIT] @ CheckReturnValue @ BackpressureSupport ( BackpressureKind . ERROR ) @ SchedulerSupport ( SchedulerSupport . COMPUTATION ) public final Flowable < Flowable < T > > window ( long timespan , TimeUnit unit , long count ) { return window ( timespan , unit , Schedulers . computation ( ) , count , false ) ; }


Input: Returns a Flowable that emits windows of items it collects from the source Publisher . The resulting Publisher emits connected non - overlapping windows each of a fixed duration as specified by the { @code timespan } argument . When the source Publisher completes or encounters an error the resulting Publisher emits the current window and propagates the notification from the source Publisher . <p > <img width = 640 height = 375 src = https : // raw . github . com / wiki / ReactiveX / RxJava / images / rx - operators / window5 . s . png alt = > <dl > <dt > <b > Backpressure : < / b > < / dt > <dd > The operator consumes the source { @code Publisher } in an unbounded manner . The returned { @code Publisher } doesn t support backpressure as it uses time to control the creation of windows . The returned inner { @code Publisher } s honor backpressure but have an unbounded inner buffer that <em > may< / em > lead to { @code OutOfMemoryError } if left unconsumed . < / dd > <dt > <b > Scheduler : < / b > < / dt > <dd > You specify which { @link Scheduler } this operator will use . < / dd > < / dl > [CODESPLIT] @ CheckReturnValue @ BackpressureSupport ( BackpressureKind . ERROR ) @ SchedulerSupport ( SchedulerSupport . CUSTOM ) public final Flowable < Flowable < T > > window ( long timespan , TimeUnit unit , Scheduler scheduler ) { return window ( timespan , unit , scheduler , Long . MAX_VALUE , false ) ; }


Input: Returns a Flowable that emits windows of items it collects from the source Publisher . The resulting Publisher emits windows that contain those items emitted by the source Publisher between the time when the { @code windowOpenings } Publisher emits an item and when the Publisher returned by { @code closingSelector } emits an item . <p > <img width = 640 height = 550 src = https : // raw . github . com / wiki / ReactiveX / RxJava / images / rx - operators / window2 . png alt = > <dl > <dt > <b > Backpressure : < / b > < / dt > <dd > The outer Publisher of this operator doesn t support backpressure because the emission of new inner Publishers are controlled by the { @code windowOpenings } Publisher . The inner Publishers honor backpressure and buffer everything until the associated closing Publisher signals or completes . < / dd > <dt > <b > Scheduler : < / b > < / dt > <dd > This version of { @code window } does not operate by default on a particular { @link Scheduler } . < / dd > < / dl > [CODESPLIT] @ CheckReturnValue @ BackpressureSupport ( BackpressureKind . ERROR ) @ SchedulerSupport ( SchedulerSupport . NONE ) public final < U , V > Flowable < Flowable < T > > window ( Publisher < U > openingIndicator , Function < ? super U , ? extends Publisher < V > > closingIndicator ) { return window ( openingIndicator , closingIndicator , bufferSize ( ) ) ; }


Input: Returns a Flowable that emits windows of items it collects from the source Publisher . The resulting Publisher emits windows that contain those items emitted by the source Publisher between the time when the { @code windowOpenings } Publisher emits an item and when the Publisher returned by { @code closingSelector } emits an item . <p > <img width = 640 height = 550 src = https : // raw . github . com / wiki / ReactiveX / RxJava / images / rx - operators / window2 . png alt = > <dl > <dt > <b > Backpressure : < / b > < / dt > <dd > The outer Publisher of this operator doesn t support backpressure because the emission of new inner Publishers are controlled by the { @code windowOpenings } Publisher . The inner Publishers honor backpressure and buffer everything until the associated closing Publisher signals or completes . < / dd > <dt > <b > Scheduler : < / b > < / dt > <dd > This version of { @code window } does not operate by default on a particular { @link Scheduler } . < / dd > < / dl > [CODESPLIT] @ CheckReturnValue @ NonNull @ BackpressureSupport ( BackpressureKind . ERROR ) @ SchedulerSupport ( SchedulerSupport . NONE ) public final < U , V > Flowable < Flowable < T > > window ( Publisher < U > openingIndicator , Function < ? super U , ? extends Publisher < V > > closingIndicator , int bufferSize ) { ObjectHelper . requireNonNull ( openingIndicator , "openingIndicator is null" ) ; ObjectHelper . requireNonNull ( closingIndicator , "closingIndicator is null" ) ; ObjectHelper . verifyPositive ( bufferSize , "bufferSize" ) ; return RxJavaPlugins . onAssembly ( new FlowableWindowBoundarySelector < T , U , V > ( this , openingIndicator , closingIndicator , bufferSize ) ) ; }


Input: Returns a Flowable that emits windows of items it collects from the source Publisher . The resulting Publisher emits connected non - overlapping windows . It emits the current window and opens a new one whenever the Publisher produced by the specified { @code closingSelector } emits an item . <p > <img width = 640 height = 455 src = https : // raw . github . com / wiki / ReactiveX / RxJava / images / rx - operators / window1 . png alt = > <dl > <dt > <b > Backpressure : < / b > < / dt > <dd > The operator consumes the source { @code Publisher } in an unbounded manner . The returned { @code Publisher } doesn t support backpressure as it uses the { @code closingSelector } to control the creation of windows . The returned inner { @code Publisher } s honor backpressure but have an unbounded inner buffer that <em > may< / em > lead to { @code OutOfMemoryError } if left unconsumed . < / dd > <dt > <b > Scheduler : < / b > < / dt > <dd > This version of { @code window } does not operate by default on a particular { @link Scheduler } . < / dd > < / dl > [CODESPLIT] @ CheckReturnValue @ BackpressureSupport ( BackpressureKind . ERROR ) @ SchedulerSupport ( SchedulerSupport . NONE ) public final < B > Flowable < Flowable < T > > window ( Callable < ? extends Publisher < B > > boundaryIndicatorSupplier ) { return window ( boundaryIndicatorSupplier , bufferSize ( ) ) ; }


Input: Returns a Flowable that emits windows of items it collects from the source Publisher . The resulting Publisher emits connected non - overlapping windows . It emits the current window and opens a new one whenever the Publisher produced by the specified { @code closingSelector } emits an item . <p > <img width = 640 height = 455 src = https : // raw . github . com / wiki / ReactiveX / RxJava / images / rx - operators / window1 . png alt = > <dl > <dt > <b > Backpressure : < / b > < / dt > <dd > The operator consumes the source { @code Publisher } in an unbounded manner . The returned { @code Publisher } doesn t support backpressure as it uses the { @code closingSelector } to control the creation of windows . The returned inner { @code Publisher } s honor backpressure but have an unbounded inner buffer that <em > may< / em > lead to { @code OutOfMemoryError } if left unconsumed . < / dd > <dt > <b > Scheduler : < / b > < / dt > <dd > This version of { @code window } does not operate by default on a particular { @link Scheduler } . < / dd > < / dl > [CODESPLIT] @ CheckReturnValue @ NonNull @ BackpressureSupport ( BackpressureKind . ERROR ) @ SchedulerSupport ( SchedulerSupport . NONE ) public final < B > Flowable < Flowable < T > > window ( Callable < ? extends Publisher < B > > boundaryIndicatorSupplier , int bufferSize ) { ObjectHelper . requireNonNull ( boundaryIndicatorSupplier , "boundaryIndicatorSupplier is null" ) ; ObjectHelper . verifyPositive ( bufferSize , "bufferSize" ) ; return RxJavaPlugins . onAssembly ( new FlowableWindowBoundarySupplier < T , B > ( this , boundaryIndicatorSupplier , bufferSize ) ) ; }


Input: Returns a Flowable that emits items that are the result of applying a specified function to pairs of values one each from the source Publisher and a specified Iterable sequence . <p > <img width = 640 height = 380 src = https : // raw . github . com / wiki / ReactiveX / RxJava / images / rx - operators / zip . i . png alt = > <p > Note that the { @code other } Iterable is evaluated as items are observed from the source Publisher ; it is not pre - consumed . This allows you to zip infinite streams on either side . <dl > <dt > <b > Backpressure : < / b > < / dt > <dd > The operator expects backpressure from the sources and honors backpressure from the downstream . ( I . e . zipping with { @link #interval ( long TimeUnit ) } may result in MissingBackpressureException use one of the { @code onBackpressureX } to handle similar backpressure - ignoring sources . < / dd > <dt > <b > Scheduler : < / b > < / dt > <dd > { @code zipWith } does not operate by default on a particular { @link Scheduler } . < / dd > < / dl > [CODESPLIT] @ CheckReturnValue @ NonNull @ BackpressureSupport ( BackpressureKind . FULL ) @ SchedulerSupport ( SchedulerSupport . NONE ) public final < U , R > Flowable < R > zipWith ( Iterable < U > other , BiFunction < ? super T , ? super U , ? extends R > zipper ) { ObjectHelper . requireNonNull ( other , "other is null" ) ; ObjectHelper . requireNonNull ( zipper , "zipper is null" ) ; return RxJavaPlugins . onAssembly ( new FlowableZipIterable < T , U , R > ( this , other , zipper ) ) ; }


Input:
Returns a Flowable that emits items that are the result of applying a specified function to pairs of values one each from the source Publisher and another specified Publisher .
 The operator subscribes to its sources in the order they are specified and completes eagerly if one of the sources is shorter than the rest while canceling the other sources . Therefore it is possible those other sources will never be able to run to completion ( and thus not calling { @code doOnComplete () } ) . This can also happen if the sources are exactly the same length ; if source A completes and B has been consumed and is about to complete the operator detects A won t be sending further values and it will cancel B immediately . For example :
  range ( 1 5 ) . doOnComplete ( action1 ) . zipWith ( range ( 6 5 ) . doOnComplete ( action2 ) ( a b ) - &gt ; a + b )
 { @code action1 } will be called but { @code action2 } won t .
 To work around this termination property use { @link #doOnCancel ( Action ) } as well or use { @code using () } to do cleanup in case of completion or cancellation .

  Backpressure :

 The operator expects backpressure from the sources and honors backpressure from the downstream . ( I . e . zipping with { @link #interval ( long TimeUnit ) } may result in MissingBackpressureException use one of the { @code onBackpressureX } to handle similar backpressure - ignoring sources .

  Scheduler :

 { @code zipWith } does not operate by default on a particular { @link Scheduler } .

 [CODESPLIT] @ CheckReturnValue @ BackpressureSupport ( BackpressureKind . FULL ) @ SchedulerSupport ( SchedulerSupport . NONE ) public final  Flowable < R > zipWith ( Publisher < ? extends U > other , BiFunction < ? super T , ? super U , ? extends R > zipper , boolean delayError ) { return zip ( this , other , zipper , delayError ) ; }


Input:
{ @inheritDoc }

 IMPLEMENTATION NOTES :
 Offer is allowed from multiple threads .
 Offer allocates a new node and :

 Swaps it atomically with current producer node ( only one producer wins )
 Sets the new node as the node following from the swapped producer node
 This works because each producer is guaranteed to plant a new node and link the old node . No 2 producers can get the same producer node as part of XCHG guarantee . [CODESPLIT] @ Override public boolean offer ( final T e ) { if ( null == e ) { throw new NullPointerException ( "Null is not a valid element" ) ; } final LinkedQueueNode < T > nextNode = new LinkedQueueNode < T > ( e ) ; final LinkedQueueNode < T > prevProducerNode = xchgProducerNode ( nextNode ) ; // Should a producer thread get interrupted here the chain WILL be broken until that thread is resumed // and completes the store in prev.next. prevProducerNode . soNext ( nextNode ) ; // StoreStore return true ; }


Input:
{ @inheritDoc }

 IMPLEMENTATION NOTES :
 Poll is allowed from a SINGLE thread .
 Poll reads the next node from the consumerNode and :

 If it is null the queue is assumed empty ( though it might not be ) .
 If it is not null set it as the consumer node and return it s now evacuated value .
 This means the consumerNode . value is always null which is also the starting point for the queue . Because null values are not allowed to be offered this is the only node with it s value set to null at any one time . [CODESPLIT] @ Nullable @ Override public T poll ( ) { LinkedQueueNode < T > currConsumerNode = lpConsumerNode ( ) ; // don't load twice, it's alright LinkedQueueNode < T > nextNode = currConsumerNode . lvNext ( ) ; if ( nextNode != null ) { // we have to null out the value because we are going to hang on to the node final T nextValue = nextNode . getAndNullValue ( ) ; spConsumerNode ( nextNode ) ; return nextValue ; } else if ( currConsumerNode != lvProducerNode ( ) ) { // spin, we are no longer wait free while ( ( nextNode = currConsumerNode . lvNext ( ) ) == null ) { } // NOPMD // got the next node... // we have to null out the value because we are going to hang on to the node final T nextValue = nextNode . getAndNullValue ( ) ; spConsumerNode ( nextNode ) ; return nextValue ; } return null ; }


Input: Wraps the given runnable into a ScheduledRunnable and schedules it on the underlying ScheduledExecutorService . <p > If the schedule has been rejected the ScheduledRunnable . wasScheduled will return false . [CODESPLIT] @ NonNull public ScheduledRunnable scheduleActual ( final Runnable run , long delayTime , @ NonNull TimeUnit unit , @ Nullable DisposableContainer parent ) { Runnable decoratedRun = RxJavaPlugins . onSchedule ( run ) ; ScheduledRunnable sr = new ScheduledRunnable ( decoratedRun , parent ) ; if ( parent != null ) { if ( ! parent . add ( sr ) ) { return sr ; } } Future < ? > f ; try { if ( delayTime <= 0 ) { f = executor . submit ( ( Callable < Object > ) sr ) ; } else { f = executor . schedule ( ( Callable < Object > ) sr , delayTime , unit ) ; } sr . setFuture ( f ) ; } catch ( RejectedExecutionException ex ) { if ( parent != null ) { parent . remove ( sr ) ; } RxJavaPlugins . onError ( ex ) ; } return sr ; }


Input: Wait for the terminal signal . [CODESPLIT] public PerfAsyncConsumer await ( int count ) { if ( count <= 1000 ) { while ( getCount ( ) != 0 ) { } } else { try { await ( ) ; } catch ( InterruptedException ex ) { throw new RuntimeException ( ex ) ; } } return this ; }


Input: Completes this subscription by indicating the given value should be emitted when the first request arrives . <p > Make sure this is called exactly once . [CODESPLIT] public final void complete ( T v ) { int state = get ( ) ; for ( ; ; ) { if ( state == FUSED_EMPTY ) { value = v ; lazySet ( FUSED_READY ) ; Subscriber < ? super T > a = downstream ; a . onNext ( v ) ; if ( get ( ) != CANCELLED ) { a . onComplete ( ) ; } return ; } // if state is >= CANCELLED or bit zero is set (*_HAS_VALUE) case, return if ( ( state & ~ HAS_REQUEST_NO_VALUE ) != 0 ) { return ; } if ( state == HAS_REQUEST_NO_VALUE ) { lazySet ( HAS_REQUEST_HAS_VALUE ) ; Subscriber < ? super T > a = downstream ; a . onNext ( v ) ; if ( get ( ) != CANCELLED ) { a . onComplete ( ) ; } return ; } value = v ; if ( compareAndSet ( NO_REQUEST_NO_VALUE , NO_REQUEST_HAS_VALUE ) ) { return ; } state = get ( ) ; if ( state == CANCELLED ) { value = null ; return ; } } }


Input: Creates a { @link BehaviorProcessor } that emits the last item it observed and all subsequent items to each { @link Subscriber } that subscribes to it . [CODESPLIT] @ CheckReturnValue @ NonNull public static < T > BehaviorProcessor < T > createDefault ( T defaultValue ) { ObjectHelper . requireNonNull ( defaultValue , "defaultValue is null" ) ; return new BehaviorProcessor < T > ( defaultValue ) ; }


Input: Tries to emit the item to all currently subscribed Subscribers if all of them has requested some value returns false otherwise . <p > This method should be called in a sequential manner just like the onXXX methods of the PublishProcessor . <p > Calling with null will terminate the PublishProcessor and a NullPointerException is signalled to the Subscribers . <p > History : 2 . 0 . 8 - experimental [CODESPLIT] public boolean offer ( T t ) { if ( t == null ) { onError ( new NullPointerException ( "onNext called with null. Null values are generally not allowed in 2.x operators and sources." ) ) ; return true ; } BehaviorSubscription < T > [ ] array = subscribers . get ( ) ; for ( BehaviorSubscription < T > s : array ) { if ( s . isFull ( ) ) { return false ; } } Object o = NotificationLite . next ( t ) ; setCurrent ( o ) ; for ( BehaviorSubscription < T > bs : array ) { bs . emitNext ( o , index ) ; } return true ; }


Input: TODO fuse back to Flowable [CODESPLIT] @ Override protected void subscribeActual ( MaybeObserver < ? super T > observer ) { source . subscribe ( new LastSubscriber < T > ( observer ) ) ; }


Input: Checks if the { [CODESPLIT] public static void verifyNonBlocking ( ) { if ( RxJavaPlugins . isFailOnNonBlockingScheduler ( ) && ( Thread . currentThread ( ) instanceof NonBlockingThread || RxJavaPlugins . onBeforeBlocking ( ) ) ) { throw new IllegalStateException ( "Attempt to block on a Scheduler " + Thread . currentThread ( ) . getName ( ) + " that doesn't support blocking operators as they may lead to deadlock" ) ; } }


Input: Returns a { [CODESPLIT] @ NonNull @ CheckReturnValue @ SchedulerSupport ( SchedulerSupport . NONE ) @ BackpressureSupport ( BackpressureKind . PASS_THROUGH ) public Flowable < T > refCount ( ) { return RxJavaPlugins . onAssembly ( new FlowableRefCount < T > ( this ) ) ; }


Input: Connects to the upstream { [CODESPLIT] @ CheckReturnValue @ SchedulerSupport ( SchedulerSupport . NONE ) @ BackpressureSupport ( BackpressureKind . PASS_THROUGH ) public final Flowable < T > refCount ( int subscriberCount ) { return refCount ( subscriberCount , 0 , TimeUnit . NANOSECONDS , Schedulers . trampoline ( ) ) ; }


Input: Connects to the upstream { [CODESPLIT] @ CheckReturnValue @ SchedulerSupport ( SchedulerSupport . COMPUTATION ) @ BackpressureSupport ( BackpressureKind . PASS_THROUGH ) public final Flowable < T > refCount ( long timeout , TimeUnit unit ) { return refCount ( 1 , timeout , unit , Schedulers . computation ( ) ) ; }


Input: Connects to the upstream { [CODESPLIT] @ CheckReturnValue @ SchedulerSupport ( SchedulerSupport . CUSTOM ) @ BackpressureSupport ( BackpressureKind . PASS_THROUGH ) public final Flowable < T > refCount ( long timeout , TimeUnit unit , Scheduler scheduler ) { return refCount ( 1 , timeout , unit , scheduler ) ; }


Input: Connects to the upstream { [CODESPLIT] @ CheckReturnValue @ SchedulerSupport ( SchedulerSupport . CUSTOM ) @ BackpressureSupport ( BackpressureKind . PASS_THROUGH ) public final Flowable < T > refCount ( int subscriberCount , long timeout , TimeUnit unit , Scheduler scheduler ) { ObjectHelper . verifyPositive ( subscriberCount , "subscriberCount" ) ; ObjectHelper . requireNonNull ( unit , "unit is null" ) ; ObjectHelper . requireNonNull ( scheduler , "scheduler is null" ) ; return RxJavaPlugins . onAssembly ( new FlowableRefCount < T > ( this , subscriberCount , timeout , unit , scheduler ) ) ; }


Input: Returns a Flowable that automatically connects ( at most once ) to this ConnectableFlowable when the specified number of Subscribers subscribe to it and calls the specified callback with the Subscription associated with the established connection . <p > <img width = 640 height = 392 src = https : // raw . github . com / wiki / ReactiveX / RxJava / images / rx - operators / autoConnect . f . png alt = > <p > The connection happens after the given number of subscriptions and happens at most once during the lifetime of the returned Flowable . If this ConnectableFlowable terminates the connection is never renewed no matter how Subscribers come and go . Use { @link #refCount () } to renew a connection or dispose an active connection when all { @code Subscriber } s have cancelled their { @code Subscription } s . [CODESPLIT] @ NonNull public Flowable < T > autoConnect ( int numberOfSubscribers , @ NonNull Consumer < ? super Disposable > connection ) { if ( numberOfSubscribers <= 0 ) { this . connect ( connection ) ; return RxJavaPlugins . onAssembly ( this ) ; } return RxJavaPlugins . onAssembly ( new FlowableAutoConnect < T > ( this , numberOfSubscribers , connection ) ) ; }


Input: Requests from the upstream Subscription . [CODESPLIT] protected final void request ( long n ) { Subscription s = this . upstream ; if ( s != null ) { s . request ( n ) ; } }


Input: Sets the resource at the specified index and disposes the old resource . [CODESPLIT] public boolean setResource ( int index , Disposable resource ) { for ( ; ; ) { Disposable o = get ( index ) ; if ( o == DisposableHelper . DISPOSED ) { resource . dispose ( ) ; return false ; } if ( compareAndSet ( index , o , resource ) ) { if ( o != null ) { o . dispose ( ) ; } return true ; } } }


Input: Replaces the resource at the specified index and returns the old resource . [CODESPLIT] public Disposable replaceResource ( int index , Disposable resource ) { for ( ; ; ) { Disposable o = get ( index ) ; if ( o == DisposableHelper . DISPOSED ) { resource . dispose ( ) ; return null ; } if ( compareAndSet ( index , o , resource ) ) { return o ; } } }


Input: Block until the first value arrives and return it otherwise return null for an empty source and rethrow any exception . [CODESPLIT] public final T blockingGet ( ) { if ( getCount ( ) != 0 ) { try { BlockingHelper . verifyNonBlocking ( ) ; await ( ) ; } catch ( InterruptedException ex ) { Subscription s = this . upstream ; this . upstream = SubscriptionHelper . CANCELLED ; if ( s != null ) { s . cancel ( ) ; } throw ExceptionHelper . wrapOrThrow ( ex ) ; } } Throwable e = error ; if ( e != null ) { throw ExceptionHelper . wrapOrThrow ( e ) ; } return value ; }


Input: Tries to add the given subscriber to the subscribers array atomically or returns false if the subject has terminated . [CODESPLIT] boolean add ( PublishDisposable < T > ps ) { for ( ; ; ) { PublishDisposable < T > [ ] a = subscribers . get ( ) ; if ( a == TERMINATED ) { return false ; } int n = a . length ; @ SuppressWarnings ( "unchecked" ) PublishDisposable < T > [ ] b = new PublishDisposable [ n + 1 ] ; System . arraycopy ( a , 0 , b , 0 , n ) ; b [ n ] = ps ; if ( subscribers . compareAndSet ( a , b ) ) { return true ; } } }


Input: Atomically removes the given subscriber if it is subscribed to the subject . [CODESPLIT] @ SuppressWarnings ( "unchecked" ) void remove ( PublishDisposable < T > ps ) { for ( ; ; ) { PublishDisposable < T > [ ] a = subscribers . get ( ) ; if ( a == TERMINATED || a == EMPTY ) { return ; } int n = a . length ; int j = - 1 ; for ( int i = 0 ; i < n ; i ++ ) { if ( a [ i ] == ps ) { j = i ; break ; } } if ( j < 0 ) { return ; } PublishDisposable < T > [ ] b ; if ( n == 1 ) { b = EMPTY ; } else { b = new PublishDisposable [ n - 1 ] ; System . arraycopy ( a , 0 , b , 0 , j ) ; System . arraycopy ( a , j + 1 , b , j , n - j - 1 ) ; } if ( subscribers . compareAndSet ( a , b ) ) { return ; } } }


Input: Given a connectable observable factory it multicasts over the generated ConnectableObservable via a selector function . [CODESPLIT] public static < U , R > Flowable < R > multicastSelector ( final Callable < ? extends ConnectableFlowable < U > > connectableFactory , final Function < ? super Flowable < U > , ? extends Publisher < R > > selector ) { return new MulticastFlowable < R , U > ( connectableFactory , selector ) ; }


Input: Child Subscribers will observe the events of the ConnectableObservable on the specified scheduler . [CODESPLIT] public static < T > ConnectableFlowable < T > observeOn ( final ConnectableFlowable < T > cf , final Scheduler scheduler ) { final Flowable < T > flowable = cf . observeOn ( scheduler ) ; return RxJavaPlugins . onAssembly ( new ConnectableFlowableReplay < T > ( cf , flowable ) ) ; }


Input: Creates a replaying ConnectableObservable with an unbounded buffer . [CODESPLIT] @ SuppressWarnings ( "unchecked" ) public static < T > ConnectableFlowable < T > createFrom ( Flowable < ? extends T > source ) { return create ( source , DEFAULT_UNBOUNDED_FACTORY ) ; }


Input: Creates a replaying ConnectableObservable with a size bound buffer . [CODESPLIT] public static < T > ConnectableFlowable < T > create ( Flowable < T > source , final int bufferSize ) { if ( bufferSize == Integer . MAX_VALUE ) { return createFrom ( source ) ; } return create ( source , new ReplayBufferTask < T > ( bufferSize ) ) ; }


Input: Creates a replaying ConnectableObservable with a time bound buffer . [CODESPLIT] public static < T > ConnectableFlowable < T > create ( Flowable < T > source , long maxAge , TimeUnit unit , Scheduler scheduler ) { return create ( source , maxAge , unit , scheduler , Integer . MAX_VALUE ) ; }


Input: Creates a replaying ConnectableObservable with a size and time bound buffer . [CODESPLIT] public static < T > ConnectableFlowable < T > create ( Flowable < T > source , final long maxAge , final TimeUnit unit , final Scheduler scheduler , final int bufferSize ) { return create ( source , new ScheduledReplayBufferTask < T > ( bufferSize , maxAge , unit , scheduler ) ) ; }


Input: Creates a OperatorReplay instance to replay values of the given source observable . [CODESPLIT] static < T > ConnectableFlowable < T > create ( Flowable < T > source , final Callable < ? extends ReplayBuffer < T > > bufferFactory ) { // the current connection to source needs to be shared between the operator and its onSubscribe call final AtomicReference < ReplaySubscriber < T > > curr = new AtomicReference < ReplaySubscriber < T > > ( ) ; Publisher < T > onSubscribe = new ReplayPublisher < T > ( curr , bufferFactory ) ; return RxJavaPlugins . onAssembly ( new FlowableReplay < T > ( onSubscribe , source , curr , bufferFactory ) ) ; }


Input: Create an instance using { [CODESPLIT] @ SuppressWarnings ( "ConstantConditions" ) // Guarding public API nullability. public static MoshiConverterFactory create ( Moshi moshi ) { if ( moshi == null ) throw new NullPointerException ( "moshi == null" ) ; return new MoshiConverterFactory ( moshi , false , false , false ) ; }


Input: Returns an instance which creates synchronous observables that { [CODESPLIT] @ SuppressWarnings ( "ConstantConditions" ) // Guarding public API nullability. public static RxJava2CallAdapterFactory createWithScheduler ( Scheduler scheduler ) { if ( scheduler == null ) throw new NullPointerException ( "scheduler == null" ) ; return new RxJava2CallAdapterFactory ( scheduler , false ) ; }


Input: Create an instance using { [CODESPLIT] @ SuppressWarnings ( "ConstantConditions" ) // Guarding public API nullability. public static SimpleXmlConverterFactory createNonStrict ( Serializer serializer ) { if ( serializer == null ) throw new NullPointerException ( "serializer == null" ) ; return new SimpleXmlConverterFactory ( serializer , false ) ; }


Input: Returns the generic supertype for { [CODESPLIT] static Type getGenericSupertype ( Type context , Class < ? > rawType , Class < ? > toResolve ) { if ( toResolve == rawType ) return context ; // We skip searching through interfaces if unknown is an interface. if ( toResolve . isInterface ( ) ) { Class < ? > [ ] interfaces = rawType . getInterfaces ( ) ; for ( int i = 0 , length = interfaces . length ; i < length ; i ++ ) { if ( interfaces [ i ] == toResolve ) { return rawType . getGenericInterfaces ( ) [ i ] ; } else if ( toResolve . isAssignableFrom ( interfaces [ i ] ) ) { return getGenericSupertype ( rawType . getGenericInterfaces ( ) [ i ] , interfaces [ i ] , toResolve ) ; } } } // Check our supertypes. if ( ! rawType . isInterface ( ) ) { while ( rawType != Object . class ) { Class < ? > rawSupertype = rawType . getSuperclass ( ) ; if ( rawSupertype == toResolve ) { return rawType . getGenericSuperclass ( ) ; } else if ( toResolve . isAssignableFrom ( rawSupertype ) ) { return getGenericSupertype ( rawType . getGenericSuperclass ( ) , rawSupertype , toResolve ) ; } rawType = rawSupertype ; } } // We can't resolve this further. return toResolve ; }


Input: Invokes { [CODESPLIT] public static < T > Call < T > defer ( Callable < Call < T > > callable ) { return new DeferredCall <> ( callable ) ; }


Input: Create an implementation of the API endpoints defined by the { [CODESPLIT] @ SuppressWarnings ( "unchecked" ) // Single-interface proxy creation guarded by parameter safety. public < T > T create ( final Class < T > service ) { Utils . validateServiceInterface ( service ) ; if ( validateEagerly ) { eagerlyValidateMethods ( service ) ; } return ( T ) Proxy . newProxyInstance ( service . getClassLoader ( ) , new Class < ? > [ ] { service } , new InvocationHandler ( ) { private final Platform platform = Platform . get ( ) ; private final Object [ ] emptyArgs = new Object [ 0 ] ; @ Override public @ Nullable Object invoke ( Object proxy , Method method , @ Nullable Object [ ] args ) throws Throwable { // If the method is a method from Object then defer to normal invocation. if ( method . getDeclaringClass ( ) == Object . class ) { return method . invoke ( this , args ) ; } if ( platform . isDefaultMethod ( method ) ) { return platform . invokeDefaultMethod ( method , service , proxy , args ) ; } return loadServiceMethod ( method ) . invoke ( args != null ? args : emptyArgs ) ; } } ) ; }


Input: Returns the { @link CallAdapter } for { @code returnType } from the available { @linkplain #callAdapterFactories () factories } . [CODESPLIT] public CallAdapter < ? , ? > callAdapter ( Type returnType , Annotation [ ] annotations ) { return nextCallAdapter ( null , returnType , annotations ) ; }


Input: Returns the { @link CallAdapter } for { @code returnType } from the available { @linkplain #callAdapterFactories () factories } except { @code skipPast } . [CODESPLIT] public CallAdapter < ? , ? > nextCallAdapter ( @ Nullable CallAdapter . Factory skipPast , Type returnType , Annotation [ ] annotations ) { checkNotNull ( returnType , "returnType == null" ) ; checkNotNull ( annotations , "annotations == null" ) ; int start = callAdapterFactories . indexOf ( skipPast ) + 1 ; for ( int i = start , count = callAdapterFactories . size ( ) ; i < count ; i ++ ) { CallAdapter < ? , ? > adapter = callAdapterFactories . get ( i ) . get ( returnType , annotations , this ) ; if ( adapter != null ) { return adapter ; } } StringBuilder builder = new StringBuilder ( "Could not locate call adapter for " ) . append ( returnType ) . append ( ".\n" ) ; if ( skipPast != null ) { builder . append ( "  Skipped:" ) ; for ( int i = 0 ; i < start ; i ++ ) { builder . append ( "\n   * " ) . append ( callAdapterFactories . get ( i ) . getClass ( ) . getName ( ) ) ; } builder . append ( ' ' ) ; } builder . append ( "  Tried:" ) ; for ( int i = start , count = callAdapterFactories . size ( ) ; i < count ; i ++ ) { builder . append ( "\n   * " ) . append ( callAdapterFactories . get ( i ) . getClass ( ) . getName ( ) ) ; } throw new IllegalArgumentException ( builder . toString ( ) ) ; }


Input: Returns a { @link Converter } for { @code type } to { @link RequestBody } from the available { @linkplain #converterFactories () factories } . [CODESPLIT] public < T > Converter < T , RequestBody > requestBodyConverter ( Type type , Annotation [ ] parameterAnnotations , Annotation [ ] methodAnnotations ) { return nextRequestBodyConverter ( null , type , parameterAnnotations , methodAnnotations ) ; }


Input: Returns a { @link Converter } for { @code type } to { @link RequestBody } from the available { @linkplain #converterFactories () factories } except { @code skipPast } . [CODESPLIT] public < T > Converter < T , RequestBody > nextRequestBodyConverter ( @ Nullable Converter . Factory skipPast , Type type , Annotation [ ] parameterAnnotations , Annotation [ ] methodAnnotations ) { checkNotNull ( type , "type == null" ) ; checkNotNull ( parameterAnnotations , "parameterAnnotations == null" ) ; checkNotNull ( methodAnnotations , "methodAnnotations == null" ) ; int start = converterFactories . indexOf ( skipPast ) + 1 ; for ( int i = start , count = converterFactories . size ( ) ; i < count ; i ++ ) { Converter . Factory factory = converterFactories . get ( i ) ; Converter < ? , RequestBody > converter = factory . requestBodyConverter ( type , parameterAnnotations , methodAnnotations , this ) ; if ( converter != null ) { //noinspection unchecked return ( Converter < T , RequestBody > ) converter ; } } StringBuilder builder = new StringBuilder ( "Could not locate RequestBody converter for " ) . append ( type ) . append ( ".\n" ) ; if ( skipPast != null ) { builder . append ( "  Skipped:" ) ; for ( int i = 0 ; i < start ; i ++ ) { builder . append ( "\n   * " ) . append ( converterFactories . get ( i ) . getClass ( ) . getName ( ) ) ; } builder . append ( ' ' ) ; } builder . append ( "  Tried:" ) ; for ( int i = start , count = converterFactories . size ( ) ; i < count ; i ++ ) { builder . append ( "\n   * " ) . append ( converterFactories . get ( i ) . getClass ( ) . getName ( ) ) ; } throw new IllegalArgumentException ( builder . toString ( ) ) ; }


Input: Returns a { @link Converter } for { @link ResponseBody } to { @code type } from the available { @linkplain #converterFactories () factories } . [CODESPLIT] public < T > Converter < ResponseBody , T > responseBodyConverter ( Type type , Annotation [ ] annotations ) { return nextResponseBodyConverter ( null , type , annotations ) ; }


Input: Returns a { @link Converter } for { @link ResponseBody } to { @code type } from the available { @linkplain #converterFactories () factories } except { @code skipPast } . [CODESPLIT] public < T > Converter < ResponseBody , T > nextResponseBodyConverter ( @ Nullable Converter . Factory skipPast , Type type , Annotation [ ] annotations ) { checkNotNull ( type , "type == null" ) ; checkNotNull ( annotations , "annotations == null" ) ; int start = converterFactories . indexOf ( skipPast ) + 1 ; for ( int i = start , count = converterFactories . size ( ) ; i < count ; i ++ ) { Converter < ResponseBody , ? > converter = converterFactories . get ( i ) . responseBodyConverter ( type , annotations , this ) ; if ( converter != null ) { //noinspection unchecked return ( Converter < ResponseBody , T > ) converter ; } } StringBuilder builder = new StringBuilder ( "Could not locate ResponseBody converter for " ) . append ( type ) . append ( ".\n" ) ; if ( skipPast != null ) { builder . append ( "  Skipped:" ) ; for ( int i = 0 ; i < start ; i ++ ) { builder . append ( "\n   * " ) . append ( converterFactories . get ( i ) . getClass ( ) . getName ( ) ) ; } builder . append ( ' ' ) ; } builder . append ( "  Tried:" ) ; for ( int i = start , count = converterFactories . size ( ) ; i < count ; i ++ ) { builder . append ( "\n   * " ) . append ( converterFactories . get ( i ) . getClass ( ) . getName ( ) ) ; } throw new IllegalArgumentException ( builder . toString ( ) ) ; }


Input: Returns a { [CODESPLIT] public < T > Converter < T , String > stringConverter ( Type type , Annotation [ ] annotations ) { checkNotNull ( type , "type == null" ) ; checkNotNull ( annotations , "annotations == null" ) ; for ( int i = 0 , count = converterFactories . size ( ) ; i < count ; i ++ ) { Converter < ? , String > converter = converterFactories . get ( i ) . stringConverter ( type , annotations , this ) ; if ( converter != null ) { //noinspection unchecked return ( Converter < T , String > ) converter ; } } // Nothing matched. Resort to default converter which just calls toString(). //noinspection unchecked return ( Converter < T , String > ) BuiltInConverters . ToStringConverter . INSTANCE ; }


Input: Create an instance using { [CODESPLIT] @ SuppressWarnings ( "ConstantConditions" ) // Guarding public API nullability. public static JaxbConverterFactory create ( JAXBContext context ) { if ( context == null ) throw new NullPointerException ( "context == null" ) ; return new JaxbConverterFactory ( context ) ; }


Input: Create an instance using { [CODESPLIT] @ SuppressWarnings ( "ConstantConditions" ) // Guarding public API nullability. public static GsonConverterFactory create ( Gson gson ) { if ( gson == null ) throw new NullPointerException ( "gson == null" ) ; return new GsonConverterFactory ( gson ) ; }


Input: Returns an instance which creates synchronous observables that { [CODESPLIT] @ SuppressWarnings ( "ConstantConditions" ) // Guarding public API nullability. public static RxJavaCallAdapterFactory createWithScheduler ( Scheduler scheduler ) { if ( scheduler == null ) throw new NullPointerException ( "scheduler == null" ) ; return new RxJavaCallAdapterFactory ( scheduler , false ) ; }


Input: Create an instance using { [CODESPLIT] @ SuppressWarnings ( "ConstantConditions" ) // Guarding public API nullability. public static JacksonConverterFactory create ( ObjectMapper mapper ) { if ( mapper == null ) throw new NullPointerException ( "mapper == null" ) ; return new JacksonConverterFactory ( mapper ) ; }


Input: Inspects the annotations on an interface method to construct a reusable service method that speaks HTTP . This requires potentially - expensive reflection so it is best to build each service method only once and reuse it . [CODESPLIT] static < ResponseT , ReturnT > HttpServiceMethod < ResponseT , ReturnT > parseAnnotations ( Retrofit retrofit , Method method , RequestFactory requestFactory ) { boolean isKotlinSuspendFunction = requestFactory . isKotlinSuspendFunction ; boolean continuationWantsResponse = false ; boolean continuationBodyNullable = false ; Annotation [ ] annotations = method . getAnnotations ( ) ; Type adapterType ; if ( isKotlinSuspendFunction ) { Type [ ] parameterTypes = method . getGenericParameterTypes ( ) ; Type responseType = Utils . getParameterLowerBound ( 0 , ( ParameterizedType ) parameterTypes [ parameterTypes . length - 1 ] ) ; if ( getRawType ( responseType ) == Response . class && responseType instanceof ParameterizedType ) { // Unwrap the actual body type from Response<T>. responseType = Utils . getParameterUpperBound ( 0 , ( ParameterizedType ) responseType ) ; continuationWantsResponse = true ; } else { // TODO figure out if type is nullable or not // Metadata metadata = method.getDeclaringClass().getAnnotation(Metadata.class) // Find the entry for method // Determine if return type is nullable or not } adapterType = new Utils . ParameterizedTypeImpl ( null , Call . class , responseType ) ; annotations = SkipCallbackExecutorImpl . ensurePresent ( annotations ) ; } else { adapterType = method . getGenericReturnType ( ) ; } CallAdapter < ResponseT , ReturnT > callAdapter = createCallAdapter ( retrofit , method , adapterType , annotations ) ; Type responseType = callAdapter . responseType ( ) ; if ( responseType == okhttp3 . Response . class ) { throw methodError ( method , "'" + getRawType ( responseType ) . getName ( ) + "' is not a valid response body type. Did you mean ResponseBody?" ) ; } if ( responseType == Response . class ) { throw methodError ( method , "Response must include generic type (e.g., Response<String>)" ) ; } // TODO support Unit for Kotlin? if ( requestFactory . httpMethod . equals ( "HEAD" ) && ! Void . class . equals ( responseType ) ) { throw methodError ( method , "HEAD method must use Void as response type." ) ; } Converter < ResponseBody , ResponseT > responseConverter = createResponseConverter ( retrofit , method , responseType ) ; okhttp3 . Call . Factory callFactory = retrofit . callFactory ; if ( ! isKotlinSuspendFunction ) { return new CallAdapted <> ( requestFactory , callFactory , responseConverter , callAdapter ) ; } else if ( continuationWantsResponse ) { //noinspection unchecked Kotlin compiler guarantees ReturnT to be Object. return ( HttpServiceMethod < ResponseT , ReturnT > ) new SuspendForResponse <> ( requestFactory , callFactory , responseConverter , ( CallAdapter < ResponseT , Call < ResponseT > > ) callAdapter ) ; } else { //noinspection unchecked Kotlin compiler guarantees ReturnT to be Object. return ( HttpServiceMethod < ResponseT , ReturnT > ) new SuspendForBody <> ( requestFactory , callFactory , responseConverter , ( CallAdapter < ResponseT , Call < ResponseT > > ) callAdapter , continuationBodyNullable ) ; } }


Input: Create an instance with default behavior which uses { [CODESPLIT] @ SuppressWarnings ( "ConstantConditions" ) // Guarding public API nullability. public static NetworkBehavior create ( Random random ) { if ( random == null ) throw new NullPointerException ( "random == null" ) ; return new NetworkBehavior ( random ) ; }


Input: Set the network round trip delay . [CODESPLIT] public void setDelay ( long amount , TimeUnit unit ) { if ( amount < 0 ) { throw new IllegalArgumentException ( "Amount must be positive value." ) ; } this . delayMs = unit . toMillis ( amount ) ; }


Input: Set the error response factory to be used when an error is triggered . This factory may only return responses for which { [CODESPLIT] @ SuppressWarnings ( "ConstantConditions" ) // Guarding public API nullability. public void setErrorFactory ( Callable < Response < ? > > errorFactory ) { if ( errorFactory == null ) { throw new NullPointerException ( "errorFactory == null" ) ; } this . errorFactory = errorFactory ; }


Input: The HTTP error to be used when an error is triggered . [CODESPLIT] public Response < ? > createErrorResponse ( ) { Response < ? > call ; try { call = errorFactory . call ( ) ; } catch ( Exception e ) { throw new IllegalStateException ( "Error factory threw an exception." , e ) ; } if ( call == null ) { throw new IllegalStateException ( "Error factory returned null." ) ; } if ( call . isSuccessful ( ) ) { throw new IllegalStateException ( "Error factory returned successful response." ) ; } return call ; }


Input: Get the delay that should be used for delaying a response in accordance with configured behavior . [CODESPLIT] public long calculateDelay ( TimeUnit unit ) { float delta = variancePercent / 100f ; // e.g., 20 / 100f == 0.2f float lowerBound = 1f - delta ; // 0.2f --> 0.8f float upperBound = 1f + delta ; // 0.2f --> 1.2f float bound = upperBound - lowerBound ; // 1.2f - 0.8f == 0.4f float delayPercent = lowerBound + ( random . nextFloat ( ) * bound ) ; // 0.8 + (rnd * 0.4) long callDelayMs = ( long ) ( delayMs * delayPercent ) ; return MILLISECONDS . convert ( callDelayMs , unit ) ; }


Input: Create a synthetic successful response with { [CODESPLIT] public static < T > Response < T > success ( @ Nullable T body ) { return success ( body , new okhttp3 . Response . Builder ( ) // . code ( 200 ) . message ( "OK" ) . protocol ( Protocol . HTTP_1_1 ) . request ( new Request . Builder ( ) . url ( "http://localhost/" ) . build ( ) ) . build ( ) ) ; }


Input: Create a successful response from { [CODESPLIT] public static < T > Response < T > success ( @ Nullable T body , okhttp3 . Response rawResponse ) { checkNotNull ( rawResponse , "rawResponse == null" ) ; if ( ! rawResponse . isSuccessful ( ) ) { throw new IllegalArgumentException ( "rawResponse must be successful response" ) ; } return new Response <> ( rawResponse , body , null ) ; }


Input: Create a synthetic error response with an HTTP status code of { [CODESPLIT] public static < T > Response < T > error ( int code , ResponseBody body ) { if ( code < 400 ) throw new IllegalArgumentException ( "code < 400: " + code ) ; return error ( body , new okhttp3 . Response . Builder ( ) // . code ( code ) . message ( "Response.error()" ) . protocol ( Protocol . HTTP_1_1 ) . request ( new Request . Builder ( ) . url ( "http://localhost/" ) . build ( ) ) . build ( ) ) ; }


Input: Create an error response from { [CODESPLIT] public static < T > Response < T > error ( ResponseBody body , okhttp3 . Response rawResponse ) { checkNotNull ( body , "body == null" ) ; checkNotNull ( rawResponse , "rawResponse == null" ) ; if ( rawResponse . isSuccessful ( ) ) { throw new IllegalArgumentException ( "rawResponse should not be successful response" ) ; } return new Response <> ( rawResponse , null , body ) ; }


Input:
处理数字字母混合输出 如：windos2000 | linliangyi2005 [CODESPLIT] private boolean processMixLetter ( AnalyzeContext context ) { boolean needLock = false ; if ( this . start == - 1 ) { //当前的分词器尚未开始处理字符
 if ( CharacterUtil . CHAR_ARABIC == context . getCurrentCharType ( ) || CharacterUtil . CHAR_ENGLISH == context . getCurrentCharType ( ) ) { //记录起始指针的位置,标明分词器进入处理状态
 this . start = context . getCursor ( ) ; this . end = start ; } } else { //当前的分词器正在处理字符
 if ( CharacterUtil . CHAR_ARABIC == context . getCurrentCharType ( ) || CharacterUtil . CHAR_ENGLISH == context . getCurrentCharType ( ) ) { //记录下可能的结束位置
 this . end = context . getCursor ( ) ; } else if ( CharacterUtil . CHAR_USELESS == context . getCurrentCharType ( ) && this . isLetterConnector ( context . getCurrentChar ( ) ) ) { //记录下可能的结束位置
 this . end = context . getCursor ( ) ; } else { //遇到非Letter字符，输出词元
 Lexeme newLexeme = new Lexeme ( context . getBufferOffset ( ) , this . start , this . end - this . start + 1 , Lexeme . TYPE_LETTER ) ; context . addLexeme ( newLexeme ) ; this . start = - 1 ; this . end = - 1 ; } } //判断缓冲区是否已经读完
 if ( context . isBufferConsumed ( ) && ( this . start != - 1 && this . end != - 1 ) ) { //缓冲以读完，输出词元
 Lexeme newLexeme = new Lexeme ( context . getBufferOffset ( ) , this . start , this . end - this . start + 1 , Lexeme . TYPE_LETTER ) ; context . addLexeme ( newLexeme ) ; this . start = - 1 ; this . end = - 1 ; } //判断是否锁定缓冲区
 if ( this . start == - 1 && this . end == - 1 ) { //对缓冲区解锁
 needLock = false ; } else { needLock = true ; } return needLock ; }


Input:
识别字符类型 [CODESPLIT] static int identifyCharType ( char input ) { if ( input >= ' ' && input <= ' ' ) { return CHAR_ARABIC ; } else if ( ( input >= ' ' && input <= ' ' ) || ( input >= ' ' && input <= ' ' ) ) { return CHAR_ENGLISH ; } else { Character . UnicodeBlock ub = Character . UnicodeBlock . of ( input ) ; if ( ub == Character . UnicodeBlock . CJK_UNIFIED_IDEOGRAPHS || ub == Character . UnicodeBlock . CJK_COMPATIBILITY_IDEOGRAPHS || ub == Character . UnicodeBlock . CJK_UNIFIED_IDEOGRAPHS_EXTENSION_A ) { //目前已知的中文字符UTF-8集合
 return CHAR_CHINESE ; } else if ( ub == Character . UnicodeBlock . HALFWIDTH_AND_FULLWIDTH_FORMS //全角数字字符和日韩字符
 //韩文字符集
 || ub == Character . UnicodeBlock . HANGUL_SYLLABLES || ub == Character . UnicodeBlock . HANGUL_JAMO || ub == Character . UnicodeBlock . HANGUL_COMPATIBILITY_JAMO //日文字符集
 || ub == Character . UnicodeBlock . HIRAGANA //平假名
 || ub == Character . UnicodeBlock . KATAKANA //片假名
 || ub == Character . UnicodeBlock . KATAKANA_PHONETIC_EXTENSIONS ) { return CHAR_OTHER_CJK ; } } //其他的不做处理的字符
 return CHAR_USELESS ; }


Input: 进行字符规格化（全角转半角，大写转小写处理） [CODESPLIT] static char regularize ( char input , boolean lowercase ) { if ( input == 12288 ) { input = ( char ) 32 ; } else if ( input > 65280 && input < 65375 ) { input = ( char ) ( input - 65248 ) ; } else if ( input >= ' ' && input <= ' ' && lowercase ) { input += 32 ; } return input ; }


Input:
初始化词典，加载子分词器实现 [CODESPLIT] private List < ISegmenter > loadSegmenters ( ) { List < ISegmenter > segmenters = new ArrayList < ISegmenter > ( 4 ) ; //处理字母的子分词器
 segmenters . add ( new LetterSegmenter ( ) ) ; //处理中文数量词的子分词器
 segmenters . add ( new CN_QuantifierSegmenter ( ) ) ; //处理中文词的子分词器
 segmenters . add ( new CJKSegmenter ( ) ) ; return segmenters ; }


Input:
分词，获取下一个词元 [CODESPLIT] public synchronized Lexeme next ( ) throws IOException { Lexeme l = null ; while ( ( l = context . getNextLexeme ( ) ) == null ) { /*
			 * 从reader中读取数据，填充buffer
			 * 如果reader是分次读入buffer的，那么buffer要  进行移位处理
			 * 移位处理上次读入的但未处理的数据
			 */ int available = context . fillBuffer ( this . input ) ; if ( available <= 0 ) { //reader已经读完
 context . reset ( ) ; return null ; } else { //初始化指针
 context . initCursor ( ) ; do { //遍历子分词器
 for ( ISegmenter segmenter : segmenters ) { segmenter . analyze ( context ) ; } //字符缓冲区接近读完，需要读入新的字符
 if ( context . needRefillBuffer ( ) ) { break ; } //向前移动指针
 } while ( context . moveCursor ( ) ) ; //重置子分词器，为下轮循环进行初始化
 for ( ISegmenter segmenter : segmenters ) { segmenter . reset ( ) ; } } //对分词进行歧义处理
 this . arbitrator . process ( context , configuration . isUseSmart ( ) ) ; //将分词结果输出到结果集，并处理未切分的单个CJK字符
 context . outputToResult ( ) ; //记录本次分词的缓冲区位移
 context . markBufferOffset ( ) ; } return l ; }


Input: 重置分词器到初始状态 [CODESPLIT] public synchronized void reset ( Reader input ) { this . input = input ; context . reset ( ) ; for ( ISegmenter segmenter : segmenters ) { segmenter . reset ( ) ; } }


Input:
分词歧义处理 * [CODESPLIT] void process ( AnalyzeContext context , boolean useSmart ) { QuickSortSet orgLexemes = context . getOrgLexemes ( ) ; Lexeme orgLexeme = orgLexemes . pollFirst ( ) ; LexemePath crossPath = new LexemePath ( ) ; while ( orgLexeme != null ) { if ( ! crossPath . addCrossLexeme ( orgLexeme ) ) { //找到与crossPath不相交的下一个crossPath
 if ( crossPath . size ( ) == 1 || ! useSmart ) { //crossPath没有歧义 或者 不做歧义处理
 //直接输出当前crossPath
 context . addLexemePath ( crossPath ) ; } else { //对当前的crossPath进行歧义处理
 QuickSortSet . Cell headCell = crossPath . getHead ( ) ; LexemePath judgeResult = this . judge ( headCell , crossPath . getPathLength ( ) ) ; //输出歧义处理结果judgeResult
 context . addLexemePath ( judgeResult ) ; } //把orgLexeme加入新的crossPath中
 crossPath = new LexemePath ( ) ; crossPath . addCrossLexeme ( orgLexeme ) ; } orgLexeme = orgLexemes . pollFirst ( ) ; } //处理最后的path
 if ( crossPath . size ( ) == 1 || ! useSmart ) { //crossPath没有歧义 或者 不做歧义处理
 //直接输出当前crossPath
 context . addLexemePath ( crossPath ) ; } else { //对当前的crossPath进行歧义处理
 QuickSortSet . Cell headCell = crossPath . getHead ( ) ; LexemePath judgeResult = this . judge ( headCell , crossPath . getPathLength ( ) ) ; //输出歧义处理结果judgeResult
 context . addLexemePath ( judgeResult ) ; } }


Input:
歧义识别 [CODESPLIT] private LexemePath judge ( QuickSortSet . Cell lexemeCell , int fullTextLength ) { //候选路径集合
 TreeSet < LexemePath > pathOptions = new TreeSet < LexemePath > ( ) ; //候选结果路径
 LexemePath option = new LexemePath ( ) ; //对crossPath进行一次遍历,同时返回本次遍历中有冲突的Lexeme栈
 Stack < QuickSortSet . Cell > lexemeStack = this . forwardPath ( lexemeCell , option ) ; //当前词元链并非最理想的，加入候选路径集合
 pathOptions . add ( option . copy ( ) ) ; //存在歧义词，处理
 QuickSortSet . Cell c = null ; while ( ! lexemeStack . isEmpty ( ) ) { c = lexemeStack . pop ( ) ; //回滚词元链
 this . backPath ( c . getLexeme ( ) , option ) ; //从歧义词位置开始，递归，生成可选方案
 this . forwardPath ( c , option ) ; pathOptions . add ( option . copy ( ) ) ; } //返回集合中的最优方案
 return pathOptions . first ( ) ; }


Input:
向前遍历，添加词元，构造一个无歧义词元组合 * [CODESPLIT] private Stack < QuickSortSet . Cell > forwardPath ( QuickSortSet . Cell lexemeCell , LexemePath option ) { //发生冲突的Lexeme栈
 Stack < QuickSortSet . Cell > conflictStack = new Stack < QuickSortSet . Cell > ( ) ; QuickSortSet . Cell c = lexemeCell ; //迭代遍历Lexeme链表
 while ( c != null && c . getLexeme ( ) != null ) { if ( ! option . addNotCrossLexeme ( c . getLexeme ( ) ) ) { //词元交叉，添加失败则加入lexemeStack栈
 conflictStack . push ( c ) ; } c = c . getNext ( ) ; } return conflictStack ; }


Input: 回滚词元链，直到它能够接受指定的词元 * [CODESPLIT] private void backPath ( Lexeme l , LexemePath option ) { while ( option . checkCross ( l ) ) { option . removeTail ( ) ; } }


Input: 重载Analyzer接口，构造分词组件 [CODESPLIT] @ Override protected TokenStreamComponents createComponents ( String fieldName ) { Tokenizer _IKTokenizer = new IKTokenizer ( configuration ) ; return new TokenStreamComponents ( _IKTokenizer ) ; }


Input:
根据context的上下文情况，填充segmentBuff [CODESPLIT] int fillBuffer ( Reader reader ) throws IOException { int readCount = 0 ; if ( this . buffOffset == 0 ) { //首次读取reader
 readCount = reader . read ( segmentBuff ) ; } else { int offset = this . available - this . cursor ; if ( offset > 0 ) { //最近一次读取的>最近一次处理的，将未处理的字串拷贝到segmentBuff头部
 System . arraycopy ( this . segmentBuff , this . cursor , this . segmentBuff , 0 , offset ) ; readCount = offset ; } //继续读取reader ，以onceReadIn - onceAnalyzed为起始位置，继续填充segmentBuff剩余的部分
 readCount += reader . read ( this . segmentBuff , offset , BUFF_SIZE - offset ) ; } //记录最后一次从Reader中读入的可用字符长度
 this . available = readCount ; //重置当前指针
 this . cursor = 0 ; return readCount ; }


Input: 初始化buff指针，处理第一个字符 [CODESPLIT] void initCursor ( ) { this . cursor = 0 ; this . segmentBuff [ this . cursor ] = CharacterUtil . regularize ( this . segmentBuff [ this . cursor ] , cfg . isEnableLowercase ( ) ) ; this . charTypes [ this . cursor ] = CharacterUtil . identifyCharType ( this . segmentBuff [ this . cursor ] ) ; }


Input: 添加分词结果路径 路径起始位置 --- > 路径 映射表 [CODESPLIT] void addLexemePath ( LexemePath path ) { if ( path != null ) { this . pathMap . put ( path . getPathBegin ( ) , path ) ; } }


Input:
推送分词结果到结果集合 1 . 从buff头部遍历到this . cursor已处理位置 2 . 将map中存在的分词结果推入results 3 . 将map中不存在的CJDK字符以单字方式推入results [CODESPLIT] void outputToResult ( ) { int index = 0 ; for ( ; index <= this . cursor ; ) { //跳过非CJK字符
 if ( CharacterUtil . CHAR_USELESS == this . charTypes [ index ] ) { index ++ ; continue ; } //从pathMap找出对应index位置的LexemePath
 LexemePath path = this . pathMap . get ( index ) ; if ( path != null ) { //输出LexemePath中的lexeme到results集合
 Lexeme l = path . pollFirst ( ) ; while ( l != null ) { this . results . add ( l ) ; //字典中无单字，但是词元冲突了，切分出相交词元的前一个词元中的单字
 int innerIndex = index + 1 ; for ( ; innerIndex < index + l . getLength ( ) ; innerIndex ++ ) { Lexeme innerL = path . peekFirst ( ) ; if ( innerL != null && innerIndex == innerL . getBegin ( ) ) { this . outputSingleCJK ( innerIndex - 1 ) ; } } //将index移至lexeme后
 index = l . getBegin ( ) + l . getLength ( ) ; l = path . pollFirst ( ) ; if ( l != null ) { //输出path内部，词元间遗漏的单字
 for ( ; index < l . getBegin ( ) ; index ++ ) { this . outputSingleCJK ( index ) ; } } } } else { //pathMap中找不到index对应的LexemePath
 //单字输出
 this . outputSingleCJK ( index ) ; index ++ ; } } //清空当前的Map
 this . pathMap . clear ( ) ; }


Input: 对CJK字符进行单字输出 [CODESPLIT] private void outputSingleCJK ( int index ) { if ( CharacterUtil . CHAR_CHINESE == this . charTypes [ index ] ) { Lexeme singleCharLexeme = new Lexeme ( this . buffOffset , index , 1 , Lexeme . TYPE_CNCHAR ) ; this . results . add ( singleCharLexeme ) ; } else if ( CharacterUtil . CHAR_OTHER_CJK == this . charTypes [ index ] ) { Lexeme singleCharLexeme = new Lexeme ( this . buffOffset , index , 1 , Lexeme . TYPE_OTHER_CJK ) ; this . results . add ( singleCharLexeme ) ; } }


Input:
返回lexeme [CODESPLIT] Lexeme getNextLexeme ( ) { //从结果集取出，并移除第一个Lexme
 Lexeme result = this . results . pollFirst ( ) ; while ( result != null ) { //数量词合并
 this . compound ( result ) ; if ( Dictionary . getSingleton ( ) . isStopWord ( this . segmentBuff , result . getBegin ( ) , result . getLength ( ) ) ) { //是停止词继续取列表的下一个
 result = this . results . pollFirst ( ) ; } else { //不是停止词, 生成lexeme的词元文本,输出
 result . setLexemeText ( String . valueOf ( segmentBuff , result . getBegin ( ) , result . getLength ( ) ) ) ; break ; } } return result ; }


Input: 重置分词上下文状态 [CODESPLIT] void reset ( ) { this . buffLocker . clear ( ) ; this . orgLexemes = new QuickSortSet ( ) ; this . available = 0 ; this . buffOffset = 0 ; this . charTypes = new int [ BUFF_SIZE ] ; this . cursor = 0 ; this . results . clear ( ) ; this . segmentBuff = new char [ BUFF_SIZE ] ; this . pathMap . clear ( ) ; }


Input:
组合词元 [CODESPLIT] private void compound ( Lexeme result ) { if ( ! this . cfg . isUseSmart ( ) ) { return ; } //数量词合并处理
 if ( ! this . results . isEmpty ( ) ) { if ( Lexeme . TYPE_ARABIC == result . getLexemeType ( ) ) { Lexeme nextLexeme = this . results . peekFirst ( ) ; boolean appendOk = false ; if ( Lexeme . TYPE_CNUM == nextLexeme . getLexemeType ( ) ) { //合并英文数词+中文数词
 appendOk = result . append ( nextLexeme , Lexeme . TYPE_CNUM ) ; } else if ( Lexeme . TYPE_COUNT == nextLexeme . getLexemeType ( ) ) { //合并英文数词+中文量词
 appendOk = result . append ( nextLexeme , Lexeme . TYPE_CQUAN ) ; } if ( appendOk ) { //弹出
 this . results . pollFirst ( ) ; } } //可能存在第二轮合并
 if ( Lexeme . TYPE_CNUM == result . getLexemeType ( ) && ! this . results . isEmpty ( ) ) { Lexeme nextLexeme = this . results . peekFirst ( ) ; boolean appendOk = false ; if ( Lexeme . TYPE_COUNT == nextLexeme . getLexemeType ( ) ) { //合并中文数词+中文量词
 appendOk = result . append ( nextLexeme , Lexeme . TYPE_CQUAN ) ; } if ( appendOk ) { //弹出
 this . results . pollFirst ( ) ; } } } }


Input: 向LexemePath追加相交的Lexeme [CODESPLIT] boolean addCrossLexeme ( Lexeme lexeme ) { if ( this . isEmpty ( ) ) { this . addLexeme ( lexeme ) ; this . pathBegin = lexeme . getBegin ( ) ; this . pathEnd = lexeme . getBegin ( ) + lexeme . getLength ( ) ; this . payloadLength += lexeme . getLength ( ) ; return true ; } else if ( this . checkCross ( lexeme ) ) { this . addLexeme ( lexeme ) ; if ( lexeme . getBegin ( ) + lexeme . getLength ( ) > this . pathEnd ) { this . pathEnd = lexeme . getBegin ( ) + lexeme . getLength ( ) ; } this . payloadLength = this . pathEnd - this . pathBegin ; return true ; } else { return false ; } }


Input: 向LexemePath追加不相交的Lexeme [CODESPLIT] boolean addNotCrossLexeme ( Lexeme lexeme ) { if ( this . isEmpty ( ) ) { this . addLexeme ( lexeme ) ; this . pathBegin = lexeme . getBegin ( ) ; this . pathEnd = lexeme . getBegin ( ) + lexeme . getLength ( ) ; this . payloadLength += lexeme . getLength ( ) ; return true ; } else if ( this . checkCross ( lexeme ) ) { return false ; } else { this . addLexeme ( lexeme ) ; this . payloadLength += lexeme . getLength ( ) ; Lexeme head = this . peekFirst ( ) ; this . pathBegin = head . getBegin ( ) ; Lexeme tail = this . peekLast ( ) ; this . pathEnd = tail . getBegin ( ) + tail . getLength ( ) ; return true ; } }


Input: 移除尾部的Lexeme [CODESPLIT] Lexeme removeTail ( ) { Lexeme tail = this . pollLast ( ) ; if ( this . isEmpty ( ) ) { this . pathBegin = - 1 ; this . pathEnd = - 1 ; this . payloadLength = 0 ; } else { this . payloadLength -= tail . getLength ( ) ; Lexeme newTail = this . peekLast ( ) ; this . pathEnd = newTail . getBegin ( ) + newTail . getLength ( ) ; } return tail ; }


Input: 检测词元位置交叉（有歧义的切分） [CODESPLIT] boolean checkCross ( Lexeme lexeme ) { return ( lexeme . getBegin ( ) >= this . pathBegin && lexeme . getBegin ( ) < this . pathEnd ) || ( this . pathBegin >= lexeme . getBegin ( ) && this . pathBegin < lexeme . getBegin ( ) + lexeme . getLength ( ) ) ; }


Input: X权重（词元长度积） [CODESPLIT] int getXWeight ( ) { int product = 1 ; Cell c = this . getHead ( ) ; while ( c != null && c . getLexeme ( ) != null ) { product *= c . getLexeme ( ) . getLength ( ) ; c = c . getNext ( ) ; } return product ; }


Input: 词元位置权重 [CODESPLIT] int getPWeight ( ) { int pWeight = 0 ; int p = 0 ; Cell c = this . getHead ( ) ; while ( c != null && c . getLexeme ( ) != null ) { p ++ ; pWeight += p * c . getLexeme ( ) . getLength ( ) ; c = c . getNext ( ) ; } return pWeight ; }


Input:
词典初始化 由于IK Analyzer的词典采用Dictionary类的静态方法进行词典初始化 只有当Dictionary类被实际调用时，才会开始载入词典， 这将延长首次分词操作的时间 该方法提供了一个在应用加载阶段就初始化字典的手段 [CODESPLIT] public static synchronized void initial ( Configuration cfg ) { if ( singleton == null ) { synchronized ( Dictionary . class ) { if ( singleton == null ) { singleton = new Dictionary ( cfg ) ; singleton . loadMainDict ( ) ; singleton . loadSurnameDict ( ) ; singleton . loadQuantifierDict ( ) ; singleton . loadSuffixDict ( ) ; singleton . loadPrepDict ( ) ; singleton . loadStopWordDict ( ) ; if ( cfg . isEnableRemoteDict ( ) ) { // 建立监控线程
 for ( String location : singleton . getRemoteExtDictionarys ( ) ) { // 10 秒是初始延迟可以修改的 60是间隔时间 单位秒
 pool . scheduleAtFixedRate ( new Monitor ( location ) , 10 , 60 , TimeUnit . SECONDS ) ; } for ( String location : singleton . getRemoteExtStopWordDictionarys ( ) ) { pool . scheduleAtFixedRate ( new Monitor ( location ) , 10 , 60 , TimeUnit . SECONDS ) ; } } } } } }


Input:
批量移除（屏蔽）词条 [CODESPLIT] public void disableWords ( Collection < String > words ) { if ( words != null ) { for ( String word : words ) { if ( word != null ) { // 批量屏蔽词条
 singleton . _MainDict . disableSegment ( word . trim ( ) . toCharArray ( ) ) ; } } } }


Input: 检索匹配主词典 [CODESPLIT] public Hit matchInMainDict ( char [ ] charArray , int begin , int length ) { return singleton . _MainDict . match ( charArray , begin , length ) ; }


Input: 检索匹配量词词典 [CODESPLIT] public Hit matchInQuantifierDict ( char [ ] charArray , int begin , int length ) { return singleton . _QuantifierDict . match ( charArray , begin , length ) ; }


Input: 从已匹配的Hit中直接取出DictSegment，继续向下匹配 [CODESPLIT] public Hit matchWithHit ( char [ ] charArray , int currentIndex , Hit matchedHit ) { DictSegment ds = matchedHit . getMatchedDictSegment ( ) ; return ds . match ( charArray , currentIndex , 1 , matchedHit ) ; }


Input: 判断是否是停止词 [CODESPLIT] public boolean isStopWord ( char [ ] charArray , int begin , int length ) { return singleton . _StopWords . match ( charArray , begin , length ) . isMatch ( ) ; }


Input:
加载主词典及扩展词典 [CODESPLIT] private void loadMainDict ( ) { // 建立一个主词典实例
 _MainDict = new DictSegment ( ( char ) 0 ) ; // 读取主词典文件
 Path file = PathUtils . get ( getDictRoot ( ) , Dictionary . PATH_DIC_MAIN ) ; loadDictFile ( _MainDict , file , false , "Main Dict" ) ; // 加载扩展词典
 this . loadExtDict ( ) ; // 加载远程自定义词库
 this . loadRemoteExtDict ( ) ; }


Input:
加载用户配置的扩展词典到主词库表 [CODESPLIT] private void loadExtDict ( ) { // 加载扩展词典配置
 List < String > extDictFiles = getExtDictionarys ( ) ; if ( extDictFiles != null ) { for ( String extDictName : extDictFiles ) { // 读取扩展词典文件
 logger . info ( "[Dict Loading] " + extDictName ) ; Path file = PathUtils . get ( extDictName ) ; loadDictFile ( _MainDict , file , false , "Extra Dict" ) ; } } }


Input:
加载远程扩展词典到主词库表 [CODESPLIT] private void loadRemoteExtDict ( ) { List < String > remoteExtDictFiles = getRemoteExtDictionarys ( ) ; for ( String location : remoteExtDictFiles ) { logger . info ( "[Dict Loading] " + location ) ; List < String > lists = getRemoteWords ( location ) ; // 如果找不到扩展的字典，则忽略
 if ( lists == null ) { logger . error ( "[Dict Loading] " + location + "加载失败");
   continue ; } for ( String theWord : lists ) { if ( theWord != null && ! "" . equals ( theWord . trim ( ) ) ) { // 加载扩展词典数据到主内存词典中
 logger . info ( theWord ) ; _MainDict . fillSegment ( theWord . trim ( ) . toLowerCase ( ) . toCharArray ( ) ) ; } } } }


Input:
从远程服务器上下载自定义词条 [CODESPLIT] private static List < String > getRemoteWordsUnprivileged ( String location ) { List < String > buffer = new ArrayList < String > ( ) ; RequestConfig rc = RequestConfig . custom ( ) . setConnectionRequestTimeout ( 10 * 1000 ) . setConnectTimeout ( 10 * 1000 ) . setSocketTimeout ( 60 * 1000 ) . build ( ) ; CloseableHttpClient httpclient = HttpClients . createDefault ( ) ; CloseableHttpResponse response ; BufferedReader in ; HttpGet get = new HttpGet ( location ) ; get . setConfig ( rc ) ; try { response = httpclient . execute ( get ) ; if ( response . getStatusLine ( ) . getStatusCode ( ) == 200 ) { String charset = "UTF-8" ; // 获取编码，默认为utf-8
 HttpEntity entity = response . getEntity ( ) ; if ( entity != null ) { Header contentType = entity . getContentType ( ) ; if ( contentType != null && contentType . getValue ( ) != null ) { String typeValue = contentType . getValue ( ) ; if ( typeValue != null && typeValue . contains ( "charset=" ) ) { charset = typeValue . substring ( typeValue . lastIndexOf ( "=" ) + 1 ) ; } } if ( entity . getContentLength ( ) > 0 ) { in = new BufferedReader ( new InputStreamReader ( entity . getContent ( ) , charset ) ) ; String line ; while ( ( line = in . readLine ( ) ) != null ) { buffer . add ( line ) ; } in . close ( ) ; response . close ( ) ; return buffer ; } } } response . close ( ) ; } catch ( IllegalStateException | IOException e ) { logger . error ( "getRemoteWords {} error" , e , location ) ; } return buffer ; }


Input:
加载用户扩展的停止词词典 [CODESPLIT] private void loadStopWordDict ( ) { // 建立主词典实例
 _StopWords = new DictSegment ( ( char ) 0 ) ; // 读取主词典文件
 Path file = PathUtils . get ( getDictRoot ( ) , Dictionary . PATH_DIC_STOP ) ; loadDictFile ( _StopWords , file , false , "Main Stopwords" ) ; // 加载扩展停止词典
 List < String > extStopWordDictFiles = getExtStopWordDictionarys ( ) ; if ( extStopWordDictFiles != null ) { for ( String extStopWordDictName : extStopWordDictFiles ) { logger . info ( "[Dict Loading] " + extStopWordDictName ) ; // 读取扩展词典文件
 file = PathUtils . get ( extStopWordDictName ) ; loadDictFile ( _StopWords , file , false , "Extra Stopwords" ) ; } } // 加载远程停用词典
 List < String > remoteExtStopWordDictFiles = getRemoteExtStopWordDictionarys ( ) ; for ( String location : remoteExtStopWordDictFiles ) { logger . info ( "[Dict Loading] " + location ) ; List < String > lists = getRemoteWords ( location ) ; // 如果找不到扩展的字典，则忽略
 if ( lists == null ) { logger . error ( "[Dict Loading] " + location + "加载失败");
   continue ; } for ( String theWord : lists ) { if ( theWord != null && ! "" . equals ( theWord . trim ( ) ) ) { // 加载远程词典数据到主内存中
 logger . info ( theWord ) ; _StopWords . fillSegment ( theWord . trim ( ) . toLowerCase ( ) . toCharArray ( ) ) ; } } } }


Input:
加载量词词典 [CODESPLIT] private void loadQuantifierDict ( ) { // 建立一个量词典实例
 _QuantifierDict = new DictSegment ( ( char ) 0 ) ; // 读取量词词典文件
 Path file = PathUtils . get ( getDictRoot ( ) , Dictionary . PATH_DIC_QUANTIFIER ) ; loadDictFile ( _QuantifierDict , file , false , "Quantifier" ) ; }


Input:
/ * ( non - Javadoc ) [CODESPLIT] public void analyze ( AnalyzeContext context ) { if ( CharacterUtil . CHAR_USELESS != context . getCurrentCharType ( ) ) { //优先处理tmpHits中的hit
 if ( ! this . tmpHits . isEmpty ( ) ) { //处理词段队列
 Hit [ ] tmpArray = this . tmpHits . toArray ( new Hit [ this . tmpHits . size ( ) ] ) ; for ( Hit hit : tmpArray ) { hit = Dictionary . getSingleton ( ) . matchWithHit ( context . getSegmentBuff ( ) , context . getCursor ( ) , hit ) ; if ( hit . isMatch ( ) ) { //输出当前的词
 Lexeme newLexeme = new Lexeme ( context . getBufferOffset ( ) , hit . getBegin ( ) , context . getCursor ( ) - hit . getBegin ( ) + 1 , Lexeme . TYPE_CNWORD ) ; context . addLexeme ( newLexeme ) ; if ( ! hit . isPrefix ( ) ) { //不是词前缀，hit不需要继续匹配，移除
 this . tmpHits . remove ( hit ) ; } } else if ( hit . isUnmatch ( ) ) { //hit不是词，移除
 this . tmpHits . remove ( hit ) ; } } } //*********************************
 //再对当前指针位置的字符进行单字匹配
 Hit singleCharHit = Dictionary . getSingleton ( ) . matchInMainDict ( context . getSegmentBuff ( ) , context . getCursor ( ) , 1 ) ; if ( singleCharHit . isMatch ( ) ) { //首字成词
 //输出当前的词
 Lexeme newLexeme = new Lexeme ( context . getBufferOffset ( ) , context . getCursor ( ) , 1 , Lexeme . TYPE_CNWORD ) ; context . addLexeme ( newLexeme ) ; //同时也是词前缀
 if ( singleCharHit . isPrefix ( ) ) { //前缀匹配则放入hit列表
 this . tmpHits . add ( singleCharHit ) ; } } else if ( singleCharHit . isPrefix ( ) ) { //首字为词前缀
 //前缀匹配则放入hit列表
 this . tmpHits . add ( singleCharHit ) ; } } else { //遇到CHAR_USELESS字符
 //清空队列
 this . tmpHits . clear ( ) ; } //判断缓冲区是否已经读完
 if ( context . isBufferConsumed ( ) ) { //清空队列
 this . tmpHits . clear ( ) ; } //判断是否锁定缓冲区
 if ( this . tmpHits . size ( ) == 0 ) { context . unlockBuffer ( SEGMENTER_NAME ) ; } else { context . lockBuffer ( SEGMENTER_NAME ) ; } }


Input: 监控流程： ①向词库服务器发送Head请求 ②从响应中获取Last - Modify、ETags字段值，判断是否变化 ③如果未变化，休眠1min，返回第①步 ④如果有变化，重新加载词典 ⑤休眠1min，返回第①步 [CODESPLIT] public void runUnprivileged ( ) { //超时设置 RequestConfig rc = RequestConfig . custom ( ) . setConnectionRequestTimeout ( 10 * 1000 ) . setConnectTimeout ( 10 * 1000 ) . setSocketTimeout ( 15 * 1000 ) . build ( ) ; HttpHead head = new HttpHead ( location ) ; head . setConfig ( rc ) ; //设置请求头 if ( last_modified != null ) { head . setHeader ( "If-Modified-Since" , last_modified ) ; } if ( eTags != null ) { head . setHeader ( "If-None-Match" , eTags ) ; } CloseableHttpResponse response = null ; try { response = httpclient . execute ( head ) ; //返回200 才做操作 if ( response . getStatusLine ( ) . getStatusCode ( ) == 200 ) { if ( ( ( response . getLastHeader ( "Last-Modified" ) != null ) && ! response . getLastHeader ( "Last-Modified" ) . getValue ( ) . equalsIgnoreCase ( last_modified ) ) || ( ( response . getLastHeader ( "ETag" ) != null ) && ! response . getLastHeader ( "ETag" ) . getValue ( ) . equalsIgnoreCase ( eTags ) ) ) { // 远程词库有更新,需要重新加载词典，并修改last_modified,eTags Dictionary . getSingleton ( ) . reLoadMainDict ( ) ; last_modified = response . getLastHeader ( "Last-Modified" ) == null ? null : response . getLastHeader ( "Last-Modified" ) . getValue ( ) ; eTags = response . getLastHeader ( "ETag" ) == null ? null : response . getLastHeader ( "ETag" ) . getValue ( ) ; } } else if ( response . getStatusLine ( ) . getStatusCode ( ) == 304 ) { //没有修改，不做操作 //noop } else { logger . info ( "remote_ext_dict {} return bad code {}" , location , response . getStatusLine ( ) . getStatusCode ( ) ) ; } } catch ( Exception e ) { logger . error ( "remote_ext_dict {} error!" , e , location ) ; } finally { try { if ( response != null ) { response . close ( ) ; } } catch ( IOException e ) { logger . error ( e . getMessage ( ) , e ) ; } } }


Input:
向链表集合添加词元 [CODESPLIT] boolean addLexeme ( Lexeme lexeme ) { Cell newCell = new Cell ( lexeme ) ; if ( this . size == 0 ) { this . head = newCell ; this . tail = newCell ; this . size ++ ; return true ; } else { if ( this . tail . compareTo ( newCell ) == 0 ) { //词元与尾部词元相同，不放入集合
 return false ; } else if ( this . tail . compareTo ( newCell ) < 0 ) { //词元接入链表尾部
 this . tail . next = newCell ; newCell . prev = this . tail ; this . tail = newCell ; this . size ++ ; return true ; } else if ( this . head . compareTo ( newCell ) > 0 ) { //词元接入链表头部
 this . head . prev = newCell ; newCell . next = this . head ; this . head = newCell ; this . size ++ ; return true ; } else { //从尾部上逆
 Cell index = this . tail ; while ( index != null && index . compareTo ( newCell ) > 0 ) { index = index . prev ; } if ( index . compareTo ( newCell ) == 0 ) { //词元与集合中的词元重复，不放入集合
 return false ; } else if ( index . compareTo ( newCell ) < 0 ) { //词元插入链表中的某个位置
 newCell . prev = index ; newCell . next = index . next ; index . next . prev = newCell ; index . next = newCell ; this . size ++ ; return true ; } } } return false ; }


Input: 取出链表集合的第一个元素 [CODESPLIT] Lexeme pollFirst ( ) { if ( this . size == 1 ) { Lexeme first = this . head . lexeme ; this . head = null ; this . tail = null ; this . size -- ; return first ; } else if ( this . size > 1 ) { Lexeme first = this . head . lexeme ; this . head = this . head . next ; this . size -- ; return first ; } else { return null ; } }


Input: 取出链表集合的最后一个元素 [CODESPLIT] Lexeme pollLast ( ) { if ( this . size == 1 ) { Lexeme last = this . head . lexeme ; this . head = null ; this . tail = null ; this . size -- ; return last ; } else if ( this . size > 1 ) { Lexeme last = this . tail . lexeme ; this . tail = this . tail . prev ; this . size -- ; return last ; } else { return null ; } }


Input:
分词 [CODESPLIT] public void analyze ( AnalyzeContext context ) { //处理中文数词
 this . processCNumber ( context ) ; //处理中文量词
 this . processCount ( context ) ; //判断是否锁定缓冲区
 if ( this . nStart == - 1 && this . nEnd == - 1 && countHits . isEmpty ( ) ) { //对缓冲区解锁
 context . unlockBuffer ( SEGMENTER_NAME ) ; } else { context . lockBuffer ( SEGMENTER_NAME ) ; } }


Input:
处理中文量词 [CODESPLIT] private void processCount ( AnalyzeContext context ) { // 判断是否需要启动量词扫描
 if ( ! this . needCountScan ( context ) ) { return ; } if ( CharacterUtil . CHAR_CHINESE == context . getCurrentCharType ( ) ) { //优先处理countHits中的hit
 if ( ! this . countHits . isEmpty ( ) ) { //处理词段队列
 Hit [ ] tmpArray = this . countHits . toArray ( new Hit [ this . countHits . size ( ) ] ) ; for ( Hit hit : tmpArray ) { hit = Dictionary . getSingleton ( ) . matchWithHit ( context . getSegmentBuff ( ) , context . getCursor ( ) , hit ) ; if ( hit . isMatch ( ) ) { //输出当前的词
 Lexeme newLexeme = new Lexeme ( context . getBufferOffset ( ) , hit . getBegin ( ) , context . getCursor ( ) - hit . getBegin ( ) + 1 , Lexeme . TYPE_COUNT ) ; context . addLexeme ( newLexeme ) ; if ( ! hit . isPrefix ( ) ) { //不是词前缀，hit不需要继续匹配，移除
 this . countHits . remove ( hit ) ; } } else if ( hit . isUnmatch ( ) ) { //hit不是词，移除
 this . countHits . remove ( hit ) ; } } } //*********************************
 //对当前指针位置的字符进行单字匹配
 Hit singleCharHit = Dictionary . getSingleton ( ) . matchInQuantifierDict ( context . getSegmentBuff ( ) , context . getCursor ( ) , 1 ) ; if ( singleCharHit . isMatch ( ) ) { //首字成量词词
 //输出当前的词
 Lexeme newLexeme = new Lexeme ( context . getBufferOffset ( ) , context . getCursor ( ) , 1 , Lexeme . TYPE_COUNT ) ; context . addLexeme ( newLexeme ) ; //同时也是词前缀
 if ( singleCharHit . isPrefix ( ) ) { //前缀匹配则放入hit列表
 this . countHits . add ( singleCharHit ) ; } } else if ( singleCharHit . isPrefix ( ) ) { //首字为量词前缀
 //前缀匹配则放入hit列表
 this . countHits . add ( singleCharHit ) ; } } else { //输入的不是中文字符
 //清空未成形的量词
 this . countHits . clear ( ) ; } //缓冲区数据已经读完，还有尚未输出的量词
 if ( context . isBufferConsumed ( ) ) { //清空未成形的量词
 this . countHits . clear ( ) ; } }


Input:
判断是否需要扫描量词 [CODESPLIT] private boolean needCountScan ( AnalyzeContext context ) { if ( ( nStart != - 1 && nEnd != - 1 ) || ! countHits . isEmpty ( ) ) { //正在处理中文数词,或者正在处理量词
 return true ; } else { //找到一个相邻的数词
 if ( ! context . getOrgLexemes ( ) . isEmpty ( ) ) { Lexeme l = context . getOrgLexemes ( ) . peekLast ( ) ; if ( ( Lexeme . TYPE_CNUM == l . getLexemeType ( ) || Lexeme . TYPE_ARABIC == l . getLexemeType ( ) ) && ( l . getBegin ( ) + l . getLength ( ) == context . getCursor ( ) ) ) { return true ; } } } return false ; }