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



我正在尝试了解RxJava的细节。

直觉上,我希望first()take(1)是平等的,并且做同样的事情。但是,通过挖掘源代码first()被定义为take(1).single()

这里的single()有什么用?take(1)不是已经保证输出单个项目了吗?

不同之处在于,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"));

实现的差异是由语义的差异驱动的。 在对语言及其内部工作原理一无所知的情况下,请考虑这两种方法的含义。

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

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

不同的

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

也有可能(同样,无需查看引擎盖以获得技术答案),这两种实现可能以非常不同的方式处理错误条件。 我个人希望first()为空集合抛出异常,因为没有第一个元素。 但是,如果初始集合的元素少于 x,我可能会合理地期望take(x)返回小于 x 大小的集合,而不会出错。 这可能会导致每当给定空集合时返回空集合而不会出错。

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

最新更新