为了尝试深入理解java流和分裂器,我对spliterator特性有一些微妙的问题:
Q1:Stream.empty()vsStream.of()(没有args的Stream.of())
Stream.empty():SUBSIZED,SIZEDStream.of(): SUBSIZED,IMMUTABLE,SIZED,ORDERED为什么Stream.empty()没有相同的特征Stream.of()?请注意,与Stream.concat()(特别是没有ORDERED)一起使用时会产生影响.我会说不Stream.empty()应该只有IMMUTABLE和ORDERED,还有DISTINCT和NONNULL.也很有意义Stream.of()仅具有一个参数DISTICT.
Q2:LongStream.of()没有NONNULL
刚注意到NONNULL不可用LongStream.of.不是NONNULL所有LongStreams,IntStreams和DoubleStreams 的主要特征吗?
Q3:LongStream.range(,)vsLongStream.range(,).boxed()
LongRange.range(,):SUBSIZED,IMMUTABLE,NONNULL,SIZED,ORDERED,SORTED ,DISTINCTLongStream.range(,).boxed():SUBSIZED,SIZED,ORDERED为什么.boxed()失去所有这些特征?它不应该失去任何.
我明白.mapToObj()可以失去NONNULL,IMMUTABLE和DISTICT,但.boxed()......没有意义.
Q4:.peek()输掉IMMUTABLE和NONNULL
LongStream.of(1): …
是否stream.spliterator()隐式关闭stream,或者之后是否需要明确关闭它?
Stream<String> stream = Stream.of("a", "b", "c");
Spliterator<T> spliterator = stream.spliterator();
// Some low lever operation with the spliterator
stream.close(); // do we need to close?
Run Code Online (Sandbox Code Playgroud)
乍一看,似乎该.spliterator()方法关闭了stream,但没有调用stream.close().至少如果我在.spliterator()调用方法后立即将其关闭,似乎不会影响分裂器操作.
Stream<String> stream = Stream.of("a", "b", "c").limit(2);
Spliterator<T> spliterator = stream.spliterator();
stream.close();
// Some low lever operation with the spliterator
Run Code Online (Sandbox Code Playgroud)
这个问题可以扩展到其他stream方法,例如,.findAny().
stream.findAny() // Can I assume that I don't need to close the stream?
stream.onClose(() -> System.out.println("hi!")).findAny()`
// …Run Code Online (Sandbox Code Playgroud) 关于深化认识Java流spliterators的第一个问题后,这里为什么执行:约溪流另一个微妙的问题.flatMap()在Java中是如此低效(非懒惰)?
通常,流应该尽可能地保持懒惰,但.flatMap()方法不是.
例如:
stream.flatMap(this::getStreamWith10HeavyComputationElems).firstFirst() 在返回第一个繁重的计算结果之前,将消耗10个元素(10次重计算).
stream.flatMap(this::getStreamWith10HeavyComputationElems).limit(11).count() 在返回11之前将消耗20个元素(2x10重计算).
该问题是为什么Java使用非懒实施?
@Test
void flatMap_native() throws Exception {
AtomicInteger count = new AtomicInteger();
Stream<Long> stream = LongStream.range(0, 5).boxed()
.flatMap(num -> LongStream.range(0, 10).boxed()
.peek(x -> count.incrementAndGet()))
.limit(11);
assertThat(stream).hasSize(11);
assertThat(count).hasValue(20); //!why? - should be 11!
}
Run Code Online (Sandbox Code Playgroud)
作为解决方法,我创建了自己的flatMap实现,但与本机调用相比,它缺乏流畅性:flatMap(stream, mapper)vs native stream.flatMap(mapper).
public static <T, R> Stream<R> flatMap(Stream<? extends T> stream, Function<? super T, ? extends Stream<? extends R>> mapper) {
// Outside the class …Run Code Online (Sandbox Code Playgroud) 关于分裂者的问题乍一看并不简单.
在流中,.parallel()更改流处理的行为.但是我期望从顺序和并行流创建的分裂器是相同的.例如,在顺序流中,通常.trySplit()从不调用,而在并行流中,为了将拆分分裂器移交给另一个线程.
stream.spliterator()vs 之间的差异stream.parallel().spliterator():
它们可能具有不同的特征:
Stream.of(1L, 2L, 3L).limit(2); // ORDERED
Stream.of(1L, 2L, 3L).limit(2).parallel(); // SUBSIZED, SIZED, ORDERED
Run Code Online (Sandbox Code Playgroud)这里讨论了另一个无意义的流分裂器特征策略(并行似乎更好地计算):在java 8和java 9中理解深层分裂器特征
它们在拆分方面可能有不同的行为.trySplit():
Stream.of(1L, 2L, 3L); // NON NULL
Stream.of(1L, 2L, 3L).limit(2); // NULL
Stream.of(1L, 2L, 3L).limit(2).parallel(); // NON NULL
Run Code Online (Sandbox Code Playgroud)为什么最后两个有不同的行为?如果我愿意,为什么我不能拆分连续流?(例如,丢弃其中一个分割以进行快速处理可能很有用).
将分裂器转换为流时的重大影响:
spliterator = Stream.of(1L, 2L, 3L).limit(2).spliterator();
stream = StreamSupport.stream(spliterator, true); // No parallel processing!
Run Code Online (Sandbox Code Playgroud)在这种情况下,从顺序流创建了一个spliterator,它禁用了split(.trySplit()返回null)的能力.稍后,需要转换回流,该流不会受益于并行处理.丢人现眼.
最大的问题:作为一种解决方法,在调用之前始终将流转换为并行的主要影响是什么?.spliterator()
// Supports activation of parallel …Run Code Online (Sandbox Code Playgroud)