diff --git a/rxjava/pom.xml b/rxjava/pom.xml
index 578eda3fcf..7b78d09eb6 100644
--- a/rxjava/pom.xml
+++ b/rxjava/pom.xml
@@ -19,6 +19,12 @@
rxjava
${rx.java.version}
+
+
+ io.reactivex.rxjava2
+ rxjava
+ 2.1.3
+
diff --git a/rxjava/src/test/java/com/baeldung/rxjava/onerror/ExceptionHandlingTest.java b/rxjava/src/test/java/com/baeldung/rxjava/onerror/ExceptionHandlingTest.java
new file mode 100644
index 0000000000..297cfa980b
--- /dev/null
+++ b/rxjava/src/test/java/com/baeldung/rxjava/onerror/ExceptionHandlingTest.java
@@ -0,0 +1,141 @@
+package com.baeldung.rxjava.onerror;
+
+import io.reactivex.Observable;
+import io.reactivex.exceptions.CompositeException;
+import io.reactivex.observers.TestObserver;
+import org.junit.Test;
+
+import java.util.concurrent.atomic.AtomicBoolean;
+
+import static org.junit.Assert.assertTrue;
+
+/**
+ * @author aiet
+ */
+public class ExceptionHandlingTest {
+
+ private Error UNKNOWN_ERROR = new Error("unknown error");
+ private Exception UNKNOWN_EXCEPTION = new Exception("unknown exception");
+
+ @Test
+ public void givenSubscriberAndError_whenHandleOnErrorReturn_thenResumed() {
+ TestObserver testObserver = new TestObserver();
+
+ Observable
+ .error(UNKNOWN_ERROR)
+ .onErrorReturn(Throwable::getMessage)
+ .subscribe(testObserver);
+
+ testObserver.assertNoErrors();
+ testObserver.assertComplete();
+ testObserver.assertValueCount(1);
+ testObserver.assertValue("unknown error");
+ }
+
+ @Test
+ public void givenSubscriberAndError_whenHandleOnErrorResume_thenResumed() {
+ TestObserver testObserver = new TestObserver();
+
+ Observable
+ .error(UNKNOWN_ERROR)
+ .onErrorResumeNext(Observable.just("one", "two"))
+ .subscribe(testObserver);
+
+ testObserver.assertNoErrors();
+ testObserver.assertComplete();
+ testObserver.assertValueCount(2);
+ testObserver.assertValues("one", "two");
+ }
+
+ @Test
+ public void givenSubscriberAndError_whenHandleOnErrorResumeItem_thenResumed() {
+ TestObserver testObserver = new TestObserver();
+
+ Observable
+ .error(UNKNOWN_ERROR)
+ .onErrorReturnItem("singleValue")
+ .subscribe(testObserver);
+
+ testObserver.assertNoErrors();
+ testObserver.assertComplete();
+ testObserver.assertValueCount(1);
+ testObserver.assertValue("singleValue");
+ }
+
+ @Test
+ public void givenSubscriberAndError_whenHandleOnErrorResumeFunc_thenResumed() {
+ TestObserver testObserver = new TestObserver();
+
+ Observable
+ .error(UNKNOWN_ERROR)
+ .onErrorResumeNext(throwable -> {
+ return Observable.just(throwable.getMessage(), "nextValue");
+ })
+ .subscribe(testObserver);
+
+ testObserver.assertNoErrors();
+ testObserver.assertComplete();
+ testObserver.assertValueCount(2);
+ testObserver.assertValues("unknown error", "nextValue");
+ }
+
+ @Test
+ public void givenSubscriberAndError_whenChangeStateOnError_thenErrorThrown() {
+ TestObserver testObserver = new TestObserver();
+ final AtomicBoolean state = new AtomicBoolean(false);
+
+ Observable
+ .error(UNKNOWN_ERROR)
+ .doOnError(throwable -> state.set(true))
+ .subscribe(testObserver);
+
+ testObserver.assertError(UNKNOWN_ERROR);
+ testObserver.assertNotComplete();
+ testObserver.assertNoValues();
+ assertTrue("state should be changed", state.get());
+ }
+
+ @Test
+ public void givenSubscriberAndError_whenExceptionOccurOnError_thenCompositeExceptionThrown() {
+ TestObserver testObserver = new TestObserver();
+
+ Observable
+ .error(UNKNOWN_ERROR)
+ .doOnError(throwable -> {
+ throw new RuntimeException("unexcepted");
+ })
+ .subscribe(testObserver);
+
+ testObserver.assertError(CompositeException.class);
+ testObserver.assertNotComplete();
+ testObserver.assertNoValues();
+ }
+
+ @Test
+ public void givenSubscriberAndException_whenHandleOnException_thenResumed() {
+ TestObserver testObserver = new TestObserver();
+
+ Observable
+ .error(UNKNOWN_EXCEPTION)
+ .onExceptionResumeNext(Observable.just("exceptionResumed"))
+ .subscribe(testObserver);
+
+ testObserver.assertNoErrors();
+ testObserver.assertComplete();
+ testObserver.assertValueCount(1);
+ testObserver.assertValue("exceptionResumed");
+ }
+
+ @Test
+ public void givenSubscriberAndError_whenHandleOnException_thenNotResumed() {
+ TestObserver testObserver = new TestObserver();
+ Observable
+ .error(UNKNOWN_ERROR)
+ .onExceptionResumeNext(Observable.just("exceptionResumed"))
+ .subscribe(testObserver);
+
+ testObserver.assertError(UNKNOWN_ERROR);
+ testObserver.assertNotComplete();
+ }
+
+}
diff --git a/rxjava/src/test/java/com/baeldung/rxjava/onerror/OnErrorRetryTest.java b/rxjava/src/test/java/com/baeldung/rxjava/onerror/OnErrorRetryTest.java
new file mode 100644
index 0000000000..0f9c39ad1b
--- /dev/null
+++ b/rxjava/src/test/java/com/baeldung/rxjava/onerror/OnErrorRetryTest.java
@@ -0,0 +1,149 @@
+package com.baeldung.rxjava.onerror;
+
+import io.reactivex.Observable;
+import io.reactivex.observers.TestObserver;
+import org.junit.Test;
+
+import java.util.concurrent.TimeUnit;
+import java.util.concurrent.atomic.AtomicInteger;
+
+import static org.junit.Assert.assertTrue;
+
+/**
+ * @author aiet
+ */
+public class OnErrorRetryTest {
+
+ private Error UNKNOWN_ERROR = new Error("unknown error");
+
+ @Test
+ public void givenSubscriberAndError_whenRetryOnError_thenRetryConfirmed() {
+ TestObserver testObserver = new TestObserver();
+ AtomicInteger atomicCounter = new AtomicInteger(0);
+
+ Observable
+ .error(() -> {
+ atomicCounter.incrementAndGet();
+ return UNKNOWN_ERROR;
+ })
+ .retry(1)
+ .subscribe(testObserver);
+
+ testObserver.assertError(UNKNOWN_ERROR);
+ testObserver.assertNotComplete();
+ testObserver.assertNoValues();
+ assertTrue("should call twice", atomicCounter.get() == 2);
+ }
+
+ @Test
+ public void givenSubscriberAndError_whenRetryConditionallyOnError_thenRetryConfirmed() {
+ TestObserver testObserver = new TestObserver();
+
+ AtomicInteger atomicCounter = new AtomicInteger(0);
+
+ Observable
+ .error(() -> {
+ atomicCounter.incrementAndGet();
+ return UNKNOWN_ERROR;
+ })
+ .retry((integer, throwable) -> integer < 4)
+ .subscribe(testObserver);
+
+ testObserver.assertError(UNKNOWN_ERROR);
+ testObserver.assertNotComplete();
+ testObserver.assertNoValues();
+ assertTrue("should call 4 times", atomicCounter.get() == 4);
+ }
+
+ @Test
+ public void givenSubscriberAndError_whenRetryUntilOnError_thenRetryConfirmed() {
+ TestObserver testObserver = new TestObserver();
+ AtomicInteger atomicCounter = new AtomicInteger(0);
+
+ Observable
+ .error(UNKNOWN_ERROR)
+ .retryUntil(() -> atomicCounter.incrementAndGet() > 3)
+ .subscribe(testObserver);
+
+ testObserver.assertError(UNKNOWN_ERROR);
+ testObserver.assertNotComplete();
+ testObserver.assertNoValues();
+ assertTrue("should call 4 times", atomicCounter.get() == 4);
+ }
+
+ @Test
+ public void givenSubscriberAndError_whenRetryWhenOnError_thenRetryConfirmed() {
+ TestObserver testObserver = new TestObserver();
+ Exception noretryException = new Exception("don't retry");
+
+ Observable
+ .error(UNKNOWN_ERROR)
+ .retryWhen(throwableObservable -> Observable.error(noretryException))
+ .subscribe(testObserver);
+
+ testObserver.assertError(noretryException);
+ testObserver.assertNotComplete();
+ testObserver.assertNoValues();
+ }
+
+ @Test
+ public void givenSubscriberAndError_whenRetryWhenOnError_thenCompleted() {
+ TestObserver testObserver = new TestObserver();
+ AtomicInteger atomicCounter = new AtomicInteger(0);
+
+ Observable
+ .error(() -> {
+ atomicCounter.incrementAndGet();
+ return UNKNOWN_ERROR;
+ })
+ .retryWhen(throwableObservable -> Observable.empty())
+ .subscribe(testObserver);
+
+ testObserver.assertNoErrors();
+ testObserver.assertComplete();
+ testObserver.assertNoValues();
+ assertTrue("should not retry", atomicCounter.get() == 0);
+ }
+
+ @Test
+ public void givenSubscriberAndError_whenRetryWhenOnError_thenResubscribed() {
+ TestObserver testObserver = new TestObserver();
+ AtomicInteger atomicCounter = new AtomicInteger(0);
+
+ Observable
+ .error(() -> {
+ atomicCounter.incrementAndGet();
+ return UNKNOWN_ERROR;
+ })
+ .retryWhen(throwableObservable -> Observable.just("anything"))
+ .subscribe(testObserver);
+
+ testObserver.assertNoErrors();
+ testObserver.assertComplete();
+ testObserver.assertNoValues();
+ assertTrue("should retry once", atomicCounter.get() == 1);
+ }
+
+ @Test
+ public void givenSubscriberAndError_whenRetryWhenForMultipleTimesOnError_thenResumed() {
+ TestObserver testObserver = new TestObserver();
+ long before = System.currentTimeMillis();
+
+ Observable
+ .error(UNKNOWN_ERROR)
+ .retryWhen(throwableObservable -> throwableObservable
+ .zipWith(Observable.range(1, 3), (throwable, integer) -> integer)
+ .flatMap(integer -> {
+ System.out.println("retried " + integer + " times");
+ return Observable.timer(integer, TimeUnit.SECONDS);
+ }))
+ .blockingSubscribe(testObserver);
+
+ testObserver.assertNoErrors();
+ testObserver.assertComplete();
+ testObserver.assertNoValues();
+ long secondsElapsed = (System.currentTimeMillis() - before) / 1000;
+ assertTrue("6 seconds should elapse", secondsElapsed == 6);
+ }
+
+}