Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

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

Tags:

I initialize my variable like this:-

 val user: BehaviorSubject<User?> user = BehaviorSubject.create()

But I can't do this. IDE throws an error:-

user.onNext(null)

And doing this, IDE says u will never be null:-

user.filter( u -> u!=null)
like image 616
Abhinav Nair Avatar asked Jul 25 '17 05:07

Abhinav Nair


People also ask

What is the use of nullable in Kotlin?

Nullability and Nullable Types in Kotlin That means You have the ability to declare whether a variable can hold a null value or not. By supporting nullability in the type system, the compiler can detect possible NullPointerException errors at compile time and reduce the possibility of having them thrown at runtime.

Can I use RxJava with Kotlin?

RxJava can be used even when using the Kotlin language for app development.

Is any nullable Kotlin?

type can hold either a string or null , whereas a String type can only hold a string. To declare a nullable variable, you need to explicitly add the nullable type. Without the nullable type, the Kotlin compiler infers that it's a non-nullable type.

How do you make an Observable in RxJava?

Following are the convenient methods to create observables in Observable class. just(T item) − Returns an Observable that signals the given (constant reference) item and then completes. fromIterable(Iterable source) − Converts an Iterable sequence into an ObservableSource that emits the items in the sequence.


2 Answers

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.

like image 171
nhaarman Avatar answered Sep 28 '22 06:09

nhaarman


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.

like image 27
guenhter Avatar answered Sep 28 '22 07:09

guenhter