Implementing your own ObservableOperator (as well as FlowableOperator) is more involved than creating an ObservableTransformer (or FlowableTransformer, correspondingly). Instead of composing a series of existing operators, you intercept the onNext(), onComplete(), onError(), and onSubscribe() calls from the upstream by implementing your own Observer instead. This Observer will then logically pass the onNext(), onComplete(), and onError() events to the downstream Observer in a way that fulfills the desired operation.
Let's say you want to create your own doOnEmpty() operator that will execute an Action when onComplete() is called and no emissions have occurred. To create your own ObservableOperator<Downstream, ...