first()和take(1)之间的区别

时间:2016-01-26 19:41:40

标签: java reactive-programming rx-java

我想了解RxJava的详细信息。

直观地,我期望first()take(1)相等并做同样的事情。但是,通过挖掘源代码first()定义为take(1).single()

single()这里有什么用处?没有take(1)已经保证输出单个项目吗?

2 个答案:

答案 0 :(得分:35)

区别在于take(1)将从上游中继0..1项,而first将中继第一个元素或如果上游为空则发出错误(NoSuchElementException)。他们都没有阻止。

确实为first == take(1).single(),其中take(1)将上游项目数限制为1,single()确保上游不为空。

此示例打印"完成"仅

Observable.empty().take(1)
.subscribe(System.out::println, Throwable::printStackTrace, 
    () -> System.out.println("Done"));

此示例打印" 1"然后是"完成":

Observable.just(1).take(1)
.subscribe(System.out::println, Throwable::printStackTrace, 
    () -> System.out.println("Done"));

此示例还打印" 1"然后是"完成":

Observable.just(1, 2, 3).take(1)
.subscribe(System.out::println, Throwable::printStackTrace, 
    () -> System.out.println("Done"));

此示例因NoSuchElementException

而失败
Observable.empty().first()
.subscribe(System.out::println, Throwable::printStackTrace, 
    () -> System.out.println("Done"));

此示例再次打印" 1"然后是"完成":

Observable.just(1).first()
.subscribe(System.out::println, Throwable::printStackTrace, 
    () -> System.out.println("Done"));

此示例再次打印" 1"然后是"完成":

Observable.just(1, 2, 3).first()
.subscribe(System.out::println, Throwable::printStackTrace, 
    () -> System.out.println("Done"));

此示例打印的堆栈跟踪为NoSuchElementException,因为源包含的元素太少:

Observable.empty().single()
.subscribe(System.out::println, Throwable::printStackTrace, 
    () -> System.out.println("Done"));

此示例打印了一个IllegalArgumentException的堆栈跟踪,因为源包含太多元素:

Observable.just(1, 2, 3).single()
.subscribe(System.out::println, Throwable::printStackTrace, 
    () -> System.out.println("Done"));

答案 1 :(得分:5)

实现的差异是由语义的差异驱动的。如果不了解语言及其内部运作,请考虑这两种方法的含义。

first()意味着它将返回一个元素。集合中的第一个元素。

take(x)意味着它将返回元素集合。集合中的第一个x元素。

不同的语义需要不同的名称。不同的回报值需要不同的技术实现。

这也是可能的(再次,无需深入了解技术答案),这两种实现可能会以非常不同的方式处理错误情况。我个人希望first()为空集合抛出异常,因为没有第一个元素。但是,如果初始集合的元素少于take(x),我可能会合理地期望x返回小于x大小的集合,而不会出现错误。 可能导致在给定空集合时返回空集合而没有错误。

此外,作为一个技术问题,像take(x)这样的东西更有可能不会立即迭代底层集合,而是推迟到某些东西迭代它的结果。但是,first()需要迭代并具体化底层集合的第一个元素。