Skip to content

Commit 22cb682

Browse files
Common approach for IllegalArgumentException on subscribe methods
As brought up in ReactiveX#278 there were inconsistencies in how arguments were being validated on subscribe methods. All arguments to subscribe are now validated correctly at the beginning of method invocation and IllegalArgumentException thrown if null arguments are injected. According to Rx Guideline 6.5 a null argument is considered "a catastrophic error occurs that should bring down the whole program anyway" and thus we immediately throw. A null argument should be caught immediately in development and has nothing to do with subscribe invocation which is what guideline 6.5 is talking about (since a null Observer can't have onError called on it anyways).
1 parent acfbc75 commit 22cb682

File tree

1 file changed

+53
-32
lines changed

1 file changed

+53
-32
lines changed

rxjava-core/src/main/java/rx/Observable.java

Lines changed: 53 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -157,11 +157,16 @@ protected Observable() {
157157
* @param observer
158158
* @return a {@link Subscription} reference that allows observers
159159
* to stop receiving notifications before the provider has finished sending them
160+
* @throws IllegalArgumentException
161+
* if null argument provided
160162
*/
161163
public Subscription subscribe(Observer<T> observer) {
162164
// allow the hook to intercept and/or decorate
163165
Func1<Observer<T>, Subscription> onSubscribeFunction = hook.onSubscribeStart(this, onSubscribe);
164166
// validate and proceed
167+
if (observer == null) {
168+
throw new IllegalArgumentException("observer can not be null");
169+
}
165170
if (onSubscribeFunction == null) {
166171
throw new IllegalStateException("onSubscribe function can not be null.");
167172
// the subscribe function can also be overridden but generally that's not the appropriate approach so I won't mention that in the exception
@@ -224,6 +229,8 @@ public Subscription subscribe(Observer<T> observer) {
224229
* The {@link Scheduler} that the sequence is subscribed to on.
225230
* @return a {@link Subscription} reference that allows observers
226231
* to stop receiving notifications before the provider has finished sending them
232+
* @throws IllegalArgumentException
233+
* if null argument provided
227234
*/
228235
public Subscription subscribe(Observer<T> observer, Scheduler scheduler) {
229236
return subscribeOn(scheduler).subscribe(observer);
@@ -241,11 +248,14 @@ private Subscription protectivelyWrapAndSubscribe(Observer<T> o) {
241248

242249
@SuppressWarnings({ "rawtypes", "unchecked" })
243250
public Subscription subscribe(final Map<String, Object> callbacks) {
244-
// lookup and memoize onNext
251+
if (callbacks == null) {
252+
throw new RuntimeException("callbacks map can not be null");
253+
}
245254
Object _onNext = callbacks.get("onNext");
246255
if (_onNext == null) {
247-
throw new RuntimeException("onNext must be implemented");
256+
throw new RuntimeException("'onNext' key must contain an implementation");
248257
}
258+
// lookup and memoize onNext
249259
final FuncN onNext = Functions.from(_onNext);
250260

251261
/**
@@ -291,10 +301,11 @@ public Subscription subscribe(final Object o) {
291301
return subscribe((Observer) o);
292302
}
293303

294-
// lookup and memoize onNext
295304
if (o == null) {
296-
throw new RuntimeException("onNext must be implemented");
305+
throw new IllegalArgumentException("onNext can not be null");
297306
}
307+
308+
// lookup and memoize onNext
298309
final FuncN onNext = Functions.from(o);
299310

300311
/**
@@ -328,6 +339,9 @@ public Subscription subscribe(final Object o, Scheduler scheduler) {
328339
}
329340

330341
public Subscription subscribe(final Action1<T> onNext) {
342+
if (onNext == null) {
343+
throw new IllegalArgumentException("onNext can not be null");
344+
}
331345

332346
/**
333347
* Wrapping since raw functions provided by the user are being invoked.
@@ -349,9 +363,6 @@ public void onError(Exception e) {
349363

350364
@Override
351365
public void onNext(T args) {
352-
if (onNext == null) {
353-
throw new RuntimeException("onNext must be implemented");
354-
}
355366
onNext.call(args);
356367
}
357368

@@ -364,10 +375,14 @@ public Subscription subscribe(final Action1<T> onNext, Scheduler scheduler) {
364375

365376
@SuppressWarnings({ "rawtypes", "unchecked" })
366377
public Subscription subscribe(final Object onNext, final Object onError) {
367-
// lookup and memoize onNext
368378
if (onNext == null) {
369-
throw new RuntimeException("onNext must be implemented");
379+
throw new IllegalArgumentException("onNext can not be null");
380+
}
381+
if (onError == null) {
382+
throw new IllegalArgumentException("onError can not be null");
370383
}
384+
385+
// lookup and memoize onNext
371386
final FuncN onNextFunction = Functions.from(onNext);
372387

373388
/**
@@ -385,9 +400,7 @@ public void onCompleted() {
385400
@Override
386401
public void onError(Exception e) {
387402
handleError(e);
388-
if (onError != null) {
389-
Functions.from(onError).call(e);
390-
}
403+
Functions.from(onError).call(e);
391404
}
392405

393406
@Override
@@ -403,6 +416,12 @@ public Subscription subscribe(final Object onNext, final Object onError, Schedul
403416
}
404417

405418
public Subscription subscribe(final Action1<T> onNext, final Action1<Exception> onError) {
419+
if (onNext == null) {
420+
throw new IllegalArgumentException("onNext can not be null");
421+
}
422+
if (onError == null) {
423+
throw new IllegalArgumentException("onError can not be null");
424+
}
406425

407426
/**
408427
* Wrapping since raw functions provided by the user are being invoked.
@@ -419,16 +438,11 @@ public void onCompleted() {
419438
@Override
420439
public void onError(Exception e) {
421440
handleError(e);
422-
if (onError != null) {
423-
onError.call(e);
424-
}
441+
onError.call(e);
425442
}
426443

427444
@Override
428445
public void onNext(T args) {
429-
if (onNext == null) {
430-
throw new RuntimeException("onNext must be implemented");
431-
}
432446
onNext.call(args);
433447
}
434448

@@ -441,10 +455,17 @@ public Subscription subscribe(final Action1<T> onNext, final Action1<Exception>
441455

442456
@SuppressWarnings({ "rawtypes", "unchecked" })
443457
public Subscription subscribe(final Object onNext, final Object onError, final Object onComplete) {
444-
// lookup and memoize onNext
445458
if (onNext == null) {
446-
throw new RuntimeException("onNext must be implemented");
459+
throw new IllegalArgumentException("onNext can not be null");
460+
}
461+
if (onError == null) {
462+
throw new IllegalArgumentException("onError can not be null");
447463
}
464+
if (onComplete == null) {
465+
throw new IllegalArgumentException("onComplete can not be null");
466+
}
467+
468+
// lookup and memoize onNext
448469
final FuncN onNextFunction = Functions.from(onNext);
449470

450471
/**
@@ -456,17 +477,13 @@ public Subscription subscribe(final Object onNext, final Object onError, final O
456477

457478
@Override
458479
public void onCompleted() {
459-
if (onComplete != null) {
460-
Functions.from(onComplete).call();
461-
}
480+
Functions.from(onComplete).call();
462481
}
463482

464483
@Override
465484
public void onError(Exception e) {
466485
handleError(e);
467-
if (onError != null) {
468-
Functions.from(onError).call(e);
469-
}
486+
Functions.from(onError).call(e);
470487
}
471488

472489
@Override
@@ -482,6 +499,15 @@ public Subscription subscribe(final Object onNext, final Object onError, final O
482499
}
483500

484501
public Subscription subscribe(final Action1<T> onNext, final Action1<Exception> onError, final Action0 onComplete) {
502+
if (onNext == null) {
503+
throw new IllegalArgumentException("onNext can not be null");
504+
}
505+
if (onError == null) {
506+
throw new IllegalArgumentException("onError can not be null");
507+
}
508+
if (onComplete == null) {
509+
throw new IllegalArgumentException("onComplete can not be null");
510+
}
485511

486512
/**
487513
* Wrapping since raw functions provided by the user are being invoked.
@@ -498,16 +524,11 @@ public void onCompleted() {
498524
@Override
499525
public void onError(Exception e) {
500526
handleError(e);
501-
if (onError != null) {
502-
onError.call(e);
503-
}
527+
onError.call(e);
504528
}
505529

506530
@Override
507531
public void onNext(T args) {
508-
if (onNext == null) {
509-
throw new RuntimeException("onNext must be implemented");
510-
}
511532
onNext.call(args);
512533
}
513534

0 commit comments

Comments
 (0)