java stream优点
Java 8流使我作为软件工程师的编程工作变得更加简单。 但是,通过合并RXJava库,还有很多可以改进的地方。 RXJava包含大量处理流或可观察对象的功能。
在Java 9中,有一个类似的概念称为Flow
[3]。 如果您正在考虑升级到Java 9或已经在使用Java 9,但尚未使用React式流编程概念,那么您可能需要事先尝试流程概念。
在本文中,我将重点介绍一部分RXJava功能,这些功能在我的代码中将是最有用的。 我不会介绍RXJava的所有功能,因为那太长了。 有关RXJava功能的更多信息,请阅读[1]。
有时,有些情况下您想在两个Collection之间一起进行迭代。 假设您有两个整数列表,并且想要“组合”列表1中具有相同索引的每个元素与列表2中的每个元素。那么您可能会想到这样的代码。
List list1 = IntStream.range(0 , 10 )
.boxed()
.collect(Collectors.toList());
List list2 = IntStream.range( 1 , 11 )
.boxed()
.collect(Collectors.toList());
for ( int i = 0 ; i < list1.size(); i++) {
System.out.println(list1.get(i) + list2.get(i));
}
在python中,有一个名为zip
的运算符,它使这段代码更短,幸运的是,我也可以使用RXJava的zip
运算符来做到这一点!
Observable.zip(
Observable.range(0 , 10 ),
Observable.range( 1 , 11 ),
(x, y) -> x + y)
.subscribe(System.out::println);
Java流被设计为只能使用一次。 如果您想知道为什么在stackoverflow [2]上对此有很好的解释,但是我在这里不做介绍。
现在,考虑这个例子
Stream intStream = IntStream.range(0 , 10 ).boxed();
intStream.forEach(System.out::println);
intStream.forEach(System.out::println);
此代码将打印从0到10的整数,但是将出现以下异常。
java.lang.IllegalStateException:流已被操作或关闭
Java 8流不应该多次使用。 据我了解,此行为背后的原因是非单发源和单发源的迭代器之间的统一行为[2]。 在一次读取的源代码中,就像从文件中读取行一样,很难确定是否需要重复两次的情况该怎么办?
使用Java 8流,您必须重新启动流才能使其正常工作。
Stream intStream = IntStream.range(0 , 10 ).boxed();
intStream.forEach(System.out::println);
intStream = IntStream.range( 0 , 10 ).boxed();
intStream.forEach(System.out::println);
RXJava编程概念的假设不同于Java 8流,因此允许我们重用Collection
的流。
Observable intObservable = Observable.range(0 , 10 );
intObservable.subscribe(System.out::println);
intObservable.subscribe(System.out::println);
考虑另一个例子。 您想进行除法运算,并使用-4到5之间的整数作为分母。
IntStream.range(-4 , 5 )
.map(i -> 1 / i)
.forEach(System.out::println);
您会注意到在某些情况下,在流的中间将计算1/0
,这将引发错误
java.lang.ArithmeticException:/减零
现在您有两种选择
filter(i != 0)
流操作。 map
功能,也许要使用try... catch...
好的,我对你说老实话, 这个选项很烂 。 在这种情况下,您可以轻松选择选项1,但在实际情况下则不能 。 在实际情况下,您很可能会选择选项2 。 您甚至都不知道导致错误的值是什么。 或者,如果您知道引起错误的值,则需要考虑将多少个值硬编码到过滤器操作中。 也许放置错误处理功能会更容易。
幸运的是,RXJava将帮助您处理这种错误情况,而无需编写try-catch块! 没有filter
功能,您可以通过以下几种方法处理导致错误的不想要的值。
附加错误订阅
subscription subscribe()
可能需要附加订阅来处理发生错误的情况,例如:
Observable.range(-4 , 5 )
.map(i -> 1 / i)
.subscribe(
System.out::println,
t -> System.out.println( "some error happened" ));
此代码块将打印“发生了一些错误”,因为它仍将尝试执行1/0
,尽管现在不会引发异常。
错误时替换值
使用onErrorReturnItem()
发生错误时提供默认值
Observable.range(-4 , 5 )
.map(i -> 1 / i)
.onErrorReturnItem(- 1 )
.subscribe(
System.out::println,
t -> System.out.println( "some error happened" ));
使用onErrorReturnItem()
时需要多加注意。 此代码不会调用错误订阅函数,因为发生错误后它将用-1
替换值。 这意味着, 无论下一个值是否产生错误,0之后的值都将由-1代替 。
RXJava有许多简化流代码的方法,但这并不是它唯一的功能。 本文尚未讨论RXJava的其他令人兴奋的功能,例如如何处理“热”或“冷”可观察对象,如何处理背压或如何并行化操作。 我鼓励读者探索更多关于React式概念的知识,并深入RXJava库以体验和思考使您的应用程序成为React式的。
[1] Samoylov,N.,Nield,T。2020。《学习RxJava第二版》。
[2] https://stackoverflow.com/questions/28459498/why-are-java-streams-once-off/28513908#28513908
[3] Java 9React流。 https://www.baeldung.com/java-9-reactive-streams
翻译自: https://hackernoon.com/advantages-of-using-rxjava-over-java-8-stream-q82a3whh
java stream优点