7

I am stuck at this problem, which should be fairly simple. I need subscriber to execute a code block when the Maybe has completed as an Empty Maybe. I found that

  1. we can pass default Maybe value or use switchIfEmpty but I feel both are hacky.
  2. Also there is a subscribe function which takes onComplete function (along with handlers for other two events), but onComplete does not take any argument which can be used to find if maybe was completed empty.
  3. Another way could be Maybe.isEmpty.blockingGet(), but it is dirty too.

I have tried following (Kotlin Syntax):-

fun <T> Maybe<T>.subscribeWithEmptyHandler(onSuccess: (T) -> Unit, onError: (Throwable) -> Unit, onEmpty: () -> Unit) {
    this.isEmpty.subscribe({ if (it) onEmpty() }, { onError(it) })
    this.subscribe({ onSuccess(it) }, { onError(it) })
}

But as expected it is running subscription twice, tested here:-

Maybe.create<Int> {
    println("subscribing")
    //Remove line below to create Empty Maybe
    it.onSuccess(5)
    it.onComplete()
}
    .subscribeWithEmptyHandler({println("success")},{println("error")},{println("empty")})

Could somebody please suggest neater way to solve this?

Vadim Kotov
  • 8,084
  • 8
  • 48
  • 62
Mangat Rai Modi
  • 5,397
  • 8
  • 45
  • 75

3 Answers3

13

Use Maybe.doOnEvent (java example):

Maybe
 .empty()
 .doOnEvent((value, error)-> {
    if (value==null && error == null) {
      System.out.println("empty!");
    }})
 .subscribe();
Dave Moten
  • 11,957
  • 2
  • 40
  • 47
3

There is a solution using flatMap

return Maybe.just<String>(smth)
                .flatMap(
                    Function {
                        Maybe.just(it) // onSuccess
                    },
                    Function {
                        Maybe.error(it) // onError
                    },
                    Callable { // onComplete
                        Maybe.just("Empty")
                    }
                )

Or

return Maybe.just<String>(smth)
                .flatMap(
                    {
                        Maybe.just<String>(it) // onSuccess
                    },
                    {
                        Maybe.error(it) // onError
                    },
                    {
                        Maybe.just("Empty") // onComplete
                    }
                )
guest
  • 432
  • 3
  • 8
2

I did the following which is neater than any I wrote in the question:-

fun <T> Maybe<T>.subscribeWithEmptyHandler(onSuccess: (T) -> Unit, onError: (Throwable) -> Unit, onEmpty: () -> Unit) {
    this.toSingle()
        .subscribe(
            { onSuccess(it) },
            { if (it is NoSuchElementException) onEmpty() else onError(it) }
        )
}

Here it subscribes only once and doesn't involve creating new default values. Still not sure if this is the best way.

Mangat Rai Modi
  • 5,397
  • 8
  • 45
  • 75
  • Note that relying on the throwing of an Exception for this use case has a performance penalty (building stack traces is expensive). I wouldn't recommend it for this reason. – Dave Moten Oct 22 '20 at 21:23