@@ -1453,57 +1453,39 @@ class Observable[+T](val asJava: rx.Observable[_ <: T])
1453
1453
def product [U >: T ](implicit num : Numeric [U ]): Observable [U ] = {
1454
1454
fold(num.one)(num.times)
1455
1455
}
1456
-
1456
+
1457
1457
/**
1458
- * TODO doc&test
1458
+ * Returns an Observable that emits only the very first item emitted by the source Observable, or
1459
+ * a default value if the source Observable is empty.
1460
+ * <p>
1461
+ * <img width="640" src="https://raw.github.com/wiki/Netflix/RxJava/images/rx-operators/firstOrDefault.png">
1462
+ *
1463
+ * @param defaultValue
1464
+ * The default value to emit if the source Observable doesn't emit anything.
1465
+ * This is a by-name parameter, so it is only evaluated if the source Observable doesn't emit anything.
1466
+ * @return an Observable that emits only the very first item from the source, or a default value
1467
+ * if the source Observable completes without emitting any item.
1459
1468
*/
1460
1469
def firstOrElse [U >: T ](default : => U ): Observable [U ] = {
1461
- this .materialize.take(1 ).map((n : Notification [T ]) => {
1462
- if (n.getKind() == rx.Notification .Kind .OnNext )
1463
- n.getValue
1464
- else
1465
- default
1470
+ this .take(1 ).fold[Option [U ]](None )((v : Option [U ], e : U ) => Some (e)).map({
1471
+ case Some (element) => element
1472
+ case None => default
1466
1473
})
1467
1474
}
1468
-
1469
- // TODO which of these two find variants do we want?
1470
-
1475
+
1471
1476
/**
1472
- * Finds the first element of the list satisfying a predicate, if any.
1473
- * @param p
1474
- * the predicate used to test elements.
1475
- * @return an Observable emitting an Option containing the first element in the source
1476
- * Observable that satisfies p, or None if none exists or onError was called.
1477
- */
1478
- def find (p : T => Boolean ): Observable [Option [T ]] = {
1479
- this .filter(p).materialize.take(1 ).map((n : Notification [T ]) => {
1480
- if (n.getKind() == rx.Notification .Kind .OnNext )
1481
- Some (n.getValue())
1482
- else
1483
- None
1484
- })
1477
+ * Returns an Observable that emits only the very first item emitted by the source Observable.
1478
+ * This is just a shorthand for {@code take(1)}.
1479
+ * <p>
1480
+ * <img width="640" src="https://raw.github.com/wiki/Netflix/RxJava/images/rx-operators/first.png">
1481
+ *
1482
+ * @return an Observable that emits only the very first item from the source, or none if the
1483
+ * source Observable completes without emitting a single item.
1484
+ */
1485
+ def first : Observable [T ] = {
1486
+ take(1 )
1485
1487
}
1486
1488
1487
- /**
1488
- * Finds the first element of the list satisfying a predicate, if any.
1489
- * @param p
1490
- * the predicate used to test elements.
1491
- * @return an Observable emitting an Option containing the first element in the source
1492
- * Observable that satisfies p, or None if none exists.
1493
- */
1494
- private def findWhichTransmitsError (p : T => Boolean ): Observable [Option [T ]] = {
1495
- val o : Observable [Notification [Option [T ]]] =
1496
- this .filter(p).materialize.take(1 ).map((n : Notification [T ]) => {
1497
- if (n.getKind() == rx.Notification .Kind .OnCompleted )
1498
- Notification (None )
1499
- else if (n.getKind() == rx.Notification .Kind .OnNext )
1500
- Notification (Some (n.getValue()))
1501
- else
1502
- Notification (n.getThrowable())
1503
- })
1504
- o.dematerialize
1505
- }
1506
-
1507
1489
/**
1508
1490
* Converts an Observable into a {@link BlockingObservable} (an Observable with blocking
1509
1491
* operators).
@@ -1586,8 +1568,8 @@ object Observable {
1586
1568
* the type of the items (ostensibly) emitted by the Observable
1587
1569
* @return an Observable that invokes the {@link Observer}'s {@link Observer#onError onError} method when the Observer subscribes to it
1588
1570
*/
1589
- def apply (exception : Throwable ): Observable [Nothing ] = {
1590
- Observable [Nothing ](JObservable .error(exception))
1571
+ def apply [ T ] (exception : Throwable ): Observable [T ] = {
1572
+ Observable [T ](JObservable .error(exception))
1591
1573
}
1592
1574
1593
1575
/**
@@ -1886,13 +1868,39 @@ class UnitTestSuite extends JUnitSuite {
1886
1868
1887
1869
assertEquals(demat.toBlockingObservable.toIterable.toList, List (1 , 2 , 3 ))
1888
1870
}
1871
+
1872
+ // Test that Java's firstOrDefault propagates errors.
1873
+ // If this changes (i.e. it suppresses errors and returns default) then Scala's firstOrElse
1874
+ // should be changed accordingly.
1875
+ @ Test def testJavaFirstOrDefault () {
1876
+ assertEquals(1 , rx.Observable .from(1 , 2 ).firstOrDefault(10 ).toBlockingObservable().single)
1877
+ assertEquals(10 , rx.Observable .empty().firstOrDefault(10 ).toBlockingObservable().single)
1878
+ val msg = " msg6251"
1879
+ var receivedMsg = " none"
1880
+ try {
1881
+ rx.Observable .error(new Exception (msg)).firstOrDefault(10 ).toBlockingObservable().single
1882
+ } catch {
1883
+ case e : Exception => receivedMsg = e.getCause().getMessage()
1884
+ }
1885
+ assertEquals(receivedMsg, msg)
1886
+ }
1889
1887
1890
- @ Test def testFind () {
1891
- assertEquals(Some (3 ), Observable (1 , 3 , 5 ).find(_ >= 2 ).toBlockingObservable.single)
1892
- assertEquals(Some (1 ), Observable (1 , 3 , 5 ).find(_ => true ).toBlockingObservable.single)
1893
- assertEquals(None , Observable (1 , 3 , 5 ).find(_ > 10 ).toBlockingObservable.single)
1894
- assertEquals(None , Observable (new Exception ()).find((i : Int ) => i > 10 ).toBlockingObservable.single)
1895
- assertEquals(None , Observable ().find((i : Int ) => i > 10 ).toBlockingObservable.single)
1888
+ @ Test def testFirstOrElse () {
1889
+ def mustNotBeCalled : String = error(" this method should not be called" )
1890
+ def mustBeCalled : String = " this is the default value"
1891
+ assertEquals(" hello" , Observable (" hello" ).firstOrElse(mustNotBeCalled).toBlockingObservable.single)
1892
+ assertEquals(" this is the default value" , Observable ().firstOrElse(mustBeCalled).toBlockingObservable.single)
1893
+ }
1894
+
1895
+ @ Test def testFirstOrElseWithError () {
1896
+ val msg = " msg6251"
1897
+ var receivedMsg = " none"
1898
+ try {
1899
+ Observable [Int ](new Exception (msg)).firstOrElse(10 ).toBlockingObservable.single
1900
+ } catch {
1901
+ case e : Exception => receivedMsg = e.getCause().getMessage()
1902
+ }
1903
+ assertEquals(receivedMsg, msg)
1896
1904
}
1897
1905
1898
1906
@ Test def testTest () = {
0 commit comments