How to pass null to an Observable with nullable type in RxJava 2 and Kotlin

As Guenhter explained, this is not possible. However, instead of proposing the null-object pattern, I'd recommend an implementation of the Optional type:

data class Optional<T>(val value: T?)
fun <T> T?.asOptional() = Optional(this)

This makes your intent much clearer, and you can use a destructuring declaration in your functions:

Observable.just(Optional("Test"))
  .map { (text: String?) -> text?.substring(1)?.asOptional() }
  .subscribe()

Using the null-object pattern here can cause more bugs than it solves.


Thank you very much for all your answers but I ultimately went with this solution:-

class UserEnvelope(val user:User?) {}

And using this in the observables.

This best suited my requirements.

I am new to Kotlin so I don't know how to use Optionals. But from what I understand, I would have to typecast it to User type everytime I need to observe the values right?


If you use rxkotlin/rxjava 2.0 (I assume so) than the answer is: you can't. The reason is explained here.

This is a break of the interface. Have a look at the Observable Interface

public interface Observer<T> {

    /** ... */
    void onSubscribe(@NonNull Disposable d);

    /** ... */
    void onNext(@NonNull T t);

    /** ... */
    void onError(@NonNull Throwable e);

    /** ... */
    void onSubscribe(@NonNull Disposable d);

    /** ... */
    void onNext(@NonNull T t);

    /** ... */
    void onError(@NonNull Throwable e);
...

The @NonNull will be considered by the Kotlin compiler and therefore you CAN'T pass null.

Even if you could, the onNext would immediately throw an error:

@Override
public void onNext(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;
    }
    ...
}

If you really need such a thing as null you have to fake it. e.g. by creating a static object of User which represents your null-element.

e.g.

data class User(val username, val password) {

    companion object {
        val NULL_USER = User("", "")
    }
}
...
val user = BehaviorSubject.create<User>()
...
user.onNext(User.NULL_USER)
...
user.filter { it !== User.NULL_USER }

But if is somehow possible, try to avoid the null concept and maybe think of another solution where this isn't needed.