Skip to content

Releases: ReactiveX/RxJava

1.0.9

09 Apr 13:35
Compare
Choose a tag to compare
  • Pull 2845 Fix for repeat: wrong target of request
  • Pull 2851 Add 'request(Long.MAX_VALUE)' in 'onStart' to fix the backpressure issue of debounce
  • Pull 2852 Change retryWhen to eagerly ignore an error'd source's subsequent events
  • Pull 2859 OperatorDoOnRequest should unsubscribe from upstream
  • Pull 2854 Fixes wrong request accounting in AbstractOnSubscribe
  • Pull 2860 OperatorSingle should request exactly what it needs
  • Pull 2817 Fix for non-deterministic: testOnBackpressureDropWithAction
  • Pull 2818 Small fix for the getValue javadoc in AsyncSubject and BehaviorSubject
  • Pull 2823 Enable maven central sync via bintray
  • Pull 2807 Corrected all Java interfaces declarations
  • Pull 2632 Implement hook to render specific types in OnNextValue
  • Pull 2837 Fixed a non-deterministic test and a few scheduler leaks (in tests)
  • Pull 2825 Fixed javadoc for Observable.repeat() method
  • Pull 2838 Fix typo in OnSubscribe interface's Javadoc
  • Pull 2864 IndexedRingBuffer.getInstance can infer type
  • Pull 2862 Cleanup warnings in test source
  • Pull 2868 Fixed reentrancy issue with the error producer.
  • Pull 2866 Use simpler naming in Action1, Func1 to assist IDEs

Artifacts: Maven Central

1.0.8

07 Mar 00:14
Compare
Choose a tag to compare
  • Pull 2809 Fixed takeUntil not unsubscribing from either of the observables in case of a terminal condition.
  • Pull 2804 ObserveOn throughput enhancements
  • Pull 2767 Optimized scalar observeOn/subscribeOn
  • Pull 2776 Experimental: add new operator onBackpressureDrop(Action1 onDrop)
  • Pull 2788 Fix the bug that 'publish' will cache items when no subscriber
  • Pull 2779 OperatorMulticast.connect(connection) should not return null
  • Pull 2771 OnSubscribeRange request overflow check
  • Pull 2770 OperatorOnBackpressureDrop request overflow check
  • Pull 2769 OperatorCombineLatest request overflow check

Artifacts: Maven Central

1.0.7

21 Feb 05:01
Compare
Choose a tag to compare

This release includes some bug fixes along with a new operator and performance enhancements.

Experimental Operator

Note that these APIs may still change or be removed altogether since they are marked as @Experimental.

withLatestFrom(Observable, Selector)

This allows combining all values from one Observable with the latest value from a second Observable at each onNext.

For example:

Observable<Long> a = Observable.interval(1, TimeUnit.SECONDS);
Observable<Long> b = Observable.interval(250, TimeUnit.MILLISECONDS);


a.withLatestFrom(b, (x, y) -> new long[] { x, y })
        .toBlocking()
        .forEach(pair -> System.out.println("a: " + pair[0] + " b: " + pair[1]));

This outputs:

a: 0 b: 3
a: 1 b: 6
a: 2 b: 11
a: 3 b: 15
a: 4 b: 19
a: 5 b: 23
a: 6 b: 27

Changes

#2760 Operator: WithLatestFrom
#2762 Optimized isUnsubscribed check
#2759 Observable.using should use unsafeSubscribe and enable eager disposal
#2655 SwitchOnNext: fix upstream producer replacing the ops own producer

Artifacts: Maven Central

1.0.6

11 Feb 21:38
Compare
Choose a tag to compare

This release adds an experimental operator and fixes several bugs.

flatMap(maxConcurrent)

Note that this API may still change or be removed altogether since it is marked as @Beta.

A flatMap overload was added that allows limiting concurrency, or the number of Observables being merged .

This now means that these are the same, one using merge directly, the other using flatMap and passing in 10 as the maxConcurrent:

Observable<Observable<Integer>> asyncWork = range(1, 1000000)
        .doOnNext(i -> System.out.println("Emitted Value: " + i))
        .map(item -> {
            return just(item)
                    .doOnNext(MergeMaxConcurrent::sleep)
                    .subscribeOn(Schedulers.io());
        });
merge(asyncWork, 10).toBlocking().forEach(v -> System.out.println("Received: " + v));
range(1, 1000000)
        .doOnNext(i -> System.out.println("Emitted Value: " + i))
        .flatMap(item -> {
            return just(item)
                    .doOnNext(MergeMaxConcurrent::sleep)
                    .subscribeOn(Schedulers.io());
        }, 10)
        .toBlocking().forEach(v -> System.out.println("Received: " + v));

Changes

  • Pull 2627 FlatMap overloads with maximum concurrency parameter
  • Pull 2648 TakeWhile: don't unsubscribe downstream.
  • Pull 2580 Allow configuring the maximum number of computation scheduler threads
  • Pull 2601 Added common Exceptions.throwIfAny to throw a collection of exceptions
  • Pull 2644 Missing Unsafe class yields NoClassDefFoundError
  • Pull 2642 Fix a potential memory leak in schedulePeriodically
  • Pull 2630 Cast back Observer to Subscriber if passed to subscribe(Observer)
  • Pull 2622 Changed Observable.empty() into a stateless constant observable.
  • Pull 2607 OnSubscribeRefCount - improve comments

Artifacts: Maven Central

1.0.5

04 Feb 07:03
Compare
Choose a tag to compare

This release includes many bug fixes along with a few new operators and enhancements.

Experimental Operators

This release adds a few experimental operators.

Note that these APIs may still change or be removed altogether since they are marked as @Experimental.

takeUntil(predicate)

This operator allows conditionally unsubscribing an Observable but inclusively emitting the final onNext. This differs from takeWhile which excludes the final onNext.

// takeUntil(predicate) example
Observable.just(1, 2, 3, 4, 5, 6, 7)
        .doOnEach(System.out::println)
        .takeUntil(i -> i == 3)
        .forEach(System.out::println);

// takeWhile(predicate) example
Observable.just(1, 2, 3, 4, 5, 6, 7)
        .doOnEach(System.out::println)
        .takeWhile(i -> i <= 3)
        .forEach(System.out::println);

This outputs:

// takeUntil(predicate)
[rx.Notification@30e84925 OnNext 1]
1
[rx.Notification@30e84926 OnNext 2]
2
[rx.Notification@30e84927 OnNext 3]
3

// takeWhile(predicate)
[rx.Notification@30e84925 OnNext 1]
1
[rx.Notification@30e84926 OnNext 2]
2
[rx.Notification@30e84927 OnNext 3]
3
[rx.Notification@30e84928 OnNext 4]

Note how takeWhile produces 4 values and takeUntil produces 3.

switchIfEmpty

The new switchIfEmpty operator is a companion to defaultIfEmpty that switches to a different Observable if the primary Observable is empty.

Observable.empty()
        .switchIfEmpty(Observable.just(1, 2, 3))
        .forEach(System.out::println);

Enhancements

merge(maxConcurrent) with backpressure

This release adds backpressure to merge(maxConcurrent) so that horizontal buffer bloat can also be controll with the maxConcurrent parameter.

This allows parallel execution such as the following to work with backpressure:

public class MergeMaxConcurrent {

    public static void main(String[] args) {
        // define 1,000,000 async tasks
        Observable<Observable<Integer>> asyncWork = range(1, 1000000)
                      .doOnNext(i -> System.out.println("Value: " + i))
                .doOnRequest(r -> System.out.println("request1 " + r))
                .map(item -> {
                    return just(item)
                            // simulate slow IO or computation
                            .doOnNext(MergeMaxConcurrent::sleep)
                            .subscribeOn(Schedulers.io());
                })
                .doOnRequest(r -> System.out.println("request2 " + r));

        // allow 10 outstanding tasks at a time
        merge(asyncWork, 10).toBlocking().forEach(System.out::println);
    }

    public static void sleep(int value) {
        try {
            Thread.sleep(1000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
}

In prior versions all 1,000,000 tasks are immediately emitted and queued for execution. As of this release it correctly allows 10 at a time to be emitted.

Changes

  • Pull 2493 Experimental Operator TakeUntil with predicate
  • Pull 2585 Experimental Operator: switchIfEmpty
  • Pull 2470 Experimental Subject state information methods & bounded ReplaySubject termination
  • Pull 2540 Merge with max concurrency now supports backpressure.
  • Pull 2332 Operator retry test fix attempt
  • Pull 2244 OperatorTakeLast add check for isUnsubscribed to fast path
  • Pull 2469 Remove the execute permission from source files
  • Pull 2455 Fix for #2191 - OperatorMulticast fails to unsubscribe from source
  • Pull 2474 MergeTest.testConcurrency timeout to let other tests run
  • Pull 2335 A set of stateless operators that don't need to be instantiated
  • Pull 2447 Fail early if a null subscription is added to a CompositeSubscription.
  • Pull 2475 SynchronousQueue.clone fix
  • Pull 2477 Backpressure tests fix0121
  • Pull 2476 Fixed off-by-one error and value-drop in the window operator.
  • Pull 2478 RefCountAsync: adjusted time values as 1 ms is unreliable
  • Pull 2238 Fix the bug that cache doesn't unsubscribe the source Observable when the source is terminated
  • Pull 1840 Unsubscribe when thread is interrupted
  • Pull 2471 Fixes NPEs reported in #1702 by synchronizing queue.
  • Pull 2482 Merge: fixed hangs & missed scalar emissions
  • Pull 2547 Warnings cleanup
  • Pull 2465 ScheduledExecutorService: call purge periodically on JDK 6 to avoid cancelled task-retention
  • Pull 2591 Changed the naming of the NewThreadWorker's system parameters
  • Pull 2543 OperatorMerge handle request overflow
  • Pull 2548 Subscriber.request should throw exception if negative request made
  • Pull 2550 Subscriber.onStart requests should be additive (and check for overflow)
  • Pull 2553 RxRingBuffer with synchronization
  • Pull 2565 Obstruction detection in tests.
  • Pull 2563 Retry backpressure test: split error conditions into separate test lines.
  • Pull 2572 Give more time to certain concurrency tests.
  • Pull 2559 OnSubscribeFromIterable - add request overflow check
  • Pull 2574 SizeEviction test needs to return false
  • Pull 2561 Updating queue code from JCTools
  • Pull 2566 CombineLatest: fixed concurrent requestUpTo yielding -1 requests
  • Pull 2552 Publish: fixed incorrect subscriber requested accounting
  • Pull 2583 Added perf tests for various container-like subscriptions
  • Pull 1955 OnBackpressureXXX: support for common drain manager & fix for former concurrency bugs
  • Pull 2590 Zip: fixed unbounded downstream requesting above Long.MAX_VALUE
  • Pull 2589 Repeat/retry: fixed unbounded downstream requesting above Long.MAX_VALUE
  • Pull 2567 RefCount: disconnect all if upstream terminates
  • Pull 2593 Zip: emit onCompleted without waiting for request + avoid re-reading fields

Artifacts: Maven Central

1.0.4

29 Dec 19:54
Compare
Choose a tag to compare
  • Pull 2156 Fix the issue that map may swallow fatal exceptions
  • Pull 1967 Fix the issue that GroupBy may not call 'unsubscribe'
  • Pull 2052 OperatorDoOnRequest.ParentSubscriber should be static class
  • Pull 2237 Make Publish Operator Release RingBuffer
  • Pull 2053 Fixed wrong bounded ReplaySubject use in test

Artifacts: Maven Central

1.0.3

16 Dec 04:37
Compare
Choose a tag to compare
  • Pull 1928 Experimental: Add onBackpressureBuffer with capacity
  • Pull 1946 Experimental: AbstractOnSubscribe to help build Observables one onNext at a time.
  • Pull 1960 Beta: doOnRequest
  • Pull 1965 Fix the issue that Sample doesn't call 'unsubscribe'
  • Pull 1966 Fix NPE when the key is null in GroupBy
  • Pull 1964 Handle 0 or negative request in Buffer
  • Pull 1957 Fix 'request(0)' issue in Scan
  • Pull 1950 Add "Subscriptions.unsubscribed" to fix the 'isUnsubscribed' issue
  • Pull 1938 Any/All should not unsubscribe downstream.
  • Pull 1968 Upgrade to Gradle 2.2
  • Pull 1961 Remove Request Batching in Merge
  • Pull 1953 Fixed timer cast-to-int crash causing incorrect benchmark.
  • Pull 1952 Remove ActionSubscription
  • Pull 1951 Remove extraneous request(n) and onCompleted() calls when unsubscribed.
  • Pull 1947 Fixed first emission racing with pre and post subscription.
  • Pull 1937 Scheduler.Worker to be finally unsubscribed to avoid interference
  • Pull 1926 Move the codes out of the finally block
  • Pull 1922 Set removeOnCancelPolicy on the threadpool if supported

Artifacts: Maven Central

1.0.2

02 Dec 06:35
Compare
Choose a tag to compare

This release adds @Beta and @Experimental annotations to mark APIs that are not yet stable.

An example of how this looks in the Javadocs is:

@Experimental
public final Observable<T> onBackpressureBlock()

The lifecycle and stability of these are documented in the README as follows:

@beta

APIs marked with the @Beta annotation at the class or method level are subject to change. They can be modified in any way, or even removed, at any time. If your code is a library itself (i.e. it is used on the CLASSPATH of users outside your own control), you should not use beta APIs, unless you repackage them (e.g. using ProGuard, shading, etc).

@experimental

APIs marked with the @Experimental annotation at the class or method level will almost certainly change. They can be modified in any way, or even removed, at any time. You should not use or rely on them in any production code. They are purely to allow broad testing and feedback.

  • Pull 1905 Beta & Experimental Annotations
  • Pull 1907 Experimental: onBackpressureBlock
  • Pull 1903 Fix TestScheduler Handling of Immediate vs Virtual Time
  • Pull 1898 Scheduled action no interrupt
  • Pull 1904 Fix the bug that Scan may request 0 when n is 1
  • Pull 1912 Fixed retry without backpressure & test function to support bp

Artifacts: Maven Central

1.0.1

29 Nov 05:27
Compare
Choose a tag to compare
  • Pull 1893 Fixed incorrect error merging.
  • Pull 1901 Fixed redo & groupBy backpressure management

Artifacts: Maven Central

1.0.0

18 Nov 14:21
Compare
Choose a tag to compare

After 2+ years of internal and open source development, 3600+ commits, 100+ releases, and with the help of 97 contributors RxJava has hit version 1.0.0.

Thank you @headinthebox @zsxwing @samuelgruetter @akarnokd @quidryan @DavidMGross @abersnaze @jmhofer @mairbek @mttkay @daveray @mattrjacobs @michaeldejong @MarioAriasC @johngmyers @pron @jbripley @davidmoten @gliptak @johnhmarks @jloisel @billyy @prabirshrestha @ragalie @abliss @dpsm @daschl @thegeez and the many other contributors and those who have reported bugs, tweeted, blogged or presented about RxJava.

The quality of this release could not have been achieved without all of your help. Thank you for your involvement and for building a community around this project.

JVM Language Adaptors & Subprojects

As of 1.0 the JVM language adapters and other subprojects no longer live under RxJava but have been separated out into their own projects with their own release cycles:

Versioning

Version 1.x is now a stable API and will be supported for several years.

Minor 1.x increments (such as 1.1, 1.2, etc) will occur when non-trivial new functionality is added or significant enhancements or bug fixes occur that may have behavioral changes that may affect some edge cases (such as dependence on behavior resulting from a bug). An example of an enhancement that would classify as this is adding reactive pull backpressure support to an operator that previously did not support it. This should be backwards compatible but does behave differently.

Patch 1.x.y increments (such as 1.0.0 -> 1.0.1, 1.3.1 -> 1.3.2, etc) will occur for bug fixes and trivial functionality (like adding a method overload).

Roadmap and Known Issues

  • 1.0.x milestone with known issues
  • 1.1 milestone with additional support for reactive pull backpressure
  • 1.x is a catch all for other items that may be pursued in 1.2, 1.3 and later versions.

Change Log

  • all deprecated methods and types from v0.20 and earlier are deleted
  • now published to groupId io.reactivex instead of com.netflix.rxjava
  • artifactId is now rxjava instead of rxjava-core
io.reactivex:rxjava:1.0.0

Following are specific changes from 0.20 to 1.0 to be aware of:

groupBy/groupByUntil

The groupByUntil operator was removed by collapsing its behavior into groupBy. Previously on groupBy when a child GroupedObservable was unsubscribed it would internally retain the state and ignore all future onNext for that key.

This matched behavior in Rx.Net but was found to be non-obvious and almost everyone using groupBy on long-lived streams actually wanted the behavior of groupByUntil where an unsubscribed GroupedObservable would clean up the resources and then if onNext for that key arrived again a new GroupedObservable would be emitted.

Adding backpressure (reactive pull) to groupByUntil was found to not work easily with its signatures so before 1.0 Final it was decided to collapse groupBy and groupByUntil. Further details on this can be found in Pull Request 1727.

Here is an example of how groupBy now behaves when a child GroupedObservable is unsubscribed (using take here):

// odd/even into lists of 10
Observable.range(1, 100)
        .groupBy(n -> n % 2 == 0)
        .flatMap(g -> {
            return g.take(10).toList();
        }).forEach(System.out::println);
[1, 3, 5, 7, 9, 11, 13, 15, 17, 19]
[2, 4, 6, 8, 10, 12, 14, 16, 18, 20]
[21, 23, 25, 27, 29, 31, 33, 35, 37, 39]
[22, 24, 26, 28, 30, 32, 34, 36, 38, 40]
[41, 43, 45, 47, 49, 51, 53, 55, 57, 59]
[42, 44, 46, 48, 50, 52, 54, 56, 58, 60]
[61, 63, 65, 67, 69, 71, 73, 75, 77, 79]
[62, 64, 66, 68, 70, 72, 74, 76, 78, 80]
[81, 83, 85, 87, 89, 91, 93, 95, 97, 99]
[82, 84, 86, 88, 90, 92, 94, 96, 98, 100]

Previously this would have only emitted 2 groups and ignored all subsequent values:

[1, 3, 5, 7, 9, 11, 13, 15, 17, 19]
[2, 4, 6, 8, 10, 12, 14, 16, 18, 20]

On a finite stream, similar behavior of the previous groupBy implementation that would filter can be achieved like this:

//odd/even into lists of 10
Observable.range(1, 100)
        .groupBy(n -> n % 2 == 0)
        .flatMap(g -> {
            return g.filter(i -> i <= 20).toList();
        }).forEach(System.out::println);
[1, 3, 5, 7, 9, 11, 13, 15, 17, 19]
[2, 4, 6, 8, 10, 12, 14, 16, 18, 20]

That however does allow the stream to complete (which may not be wanted).

To unsubscribe here are some choices that get the same output but efficiently unsubscribe up so the source only emits 40 values:

Observable.timer(0, 1, TimeUnit.MILLISECONDS)
        .groupBy(n -> n % 2 == 0)
        .flatMap(g -> {
            return g.take(10).toList();
        }).take(2).toBlocking().forEach(System.out::println);

or

Observable.timer(0, 1, TimeUnit.MILLISECONDS)
        .take(20)
        .groupBy(n -> n % 2 == 0)
        .flatMap(g -> {
            return g.toList();
        }).toBlocking().forEach(System.out::println);

These show that now groupBy composes like any other operator without the nuanced and hidden behavior of ignoring values after a child GroupedObservable is unsubscribed.

Uses of groupByUntil can now all be done by just using operators like take, takeWhile and takeUntil on the GroupedObservable directly, such as this:

Observable.from(Arrays.asList("a", "b", "c", "a", "b", "c", "a", "b", "c", "a", "b", "c", "a", "b", "c", "a", "b", "c"))
        .groupBy(n -> n)
        .flatMap(g -> {
            return g.take(3).reduce((s, s2) -> s + s2);
        }).forEach(System.out::println);
aaa
bbb
ccc
aaa
bbb
ccc

retryWhen/repeatWhen

The retryWhen and repeatWhen method signatures both emitted a Observable<Notification> type which could be queried to represent either onError in the retryWhen case or onCompleted in the repeatWhen case. This was found to be confusing and unnecessary. The signatures were changed to emit Observable<Throwable> for retryWhen and Observable<Void> for repeatWhen to better signal the type of notification they are emitting without the need to then query the Notification.

The following contrived examples shows how the Observable<Throwable> is used to get the error that occurred when deciding to retry:

    AtomicInteger count = new AtomicInteger();
    Observable.create((Subscriber<? super String> s) -> {
        if (count.getAndIncrement() == 0) {
            s.onError(new RuntimeException("always fails"));
        } else {
            s.onError(new IllegalArgumentException("user error"));
        }
    }).retryWhen(attempts -> {
        return attempts.flatMap(throwable -> {
            if (throwable instanceof IllegalArgumentException) {
                System.out.println("don't retry on IllegalArgumentException... allow failure");
                return Observable.error(throwable);
            } else {
                System.out.println(throwable + " => retry after 1 second");
                return Observable.timer(1, TimeUnit.SECONDS);
            }
        });
    })
    .toBlocking().forEach(System.out::println);

collect

The collect operator was changed to require a factory method for the initial value. This allows the Observable to be executed multiple times and get a new value (typically a mutable data structure) each time. Prior to this the Observable could only be subscribed to once since it would retain the original mutable data structure and keep mutating it.

Observable.range(0, 10).collect(() -> new ArrayList<Integer>(), (list, i) -> {
    list.add(i);
}).forEach(System.out::println);

Removed Scheduler.parallelism

The Scheduler.parallelism method was no longer being used by anything so was removed.

Removed Observable.parallel

The parallel operator was a failed experiment and almost all uses of it were wrong and led to confusion and often bad performance. Due to this it was removed.

Here is example code to show approaches to adding concurrency:

import rx.Observable;
import rx.Subscriber;
import rx.schedulers.Schedulers;

public class ParallelExecution {

    public static void main(String[] args) {
        System.out.println("------------ mergingAsync");
        mergingAsync();
        System.out.println("------------ mergingSync");
        mergingSync();
        System.out.println("------------ mergingSyncMadeAsync");
        mergingSyncMadeAsync();
        System.o...
Read more