java-番石榴的Streams :: findLast实现
内容导读
互联网集市收集整理的这篇技术教程文章主要介绍了java-番石榴的Streams :: findLast实现,小编现在分享给大家,供广大互联网技能从业者学习和参考。文章包含4953字,纯文字阅读大概需要8分钟。
内容图文
![java-番石榴的Streams :: findLast实现](/upload/InfoBanner/zyjiaocheng/687/ca2ec0fe44db450c98996c6e30abea79.jpg)
我正在研究番石榴中Streams :: findLast的实现,并且在尝试理解它的同时,有些事情我根本无法掌握.这是它的实现:
public static <T> java.util.Optional<T> findLast(Stream<T> stream) {
class OptionalState {
boolean set = false;
T value = null;
void set(@Nullable T value) {
set = true;
this.value = value;
}
T get() {
checkState(set);
return value;
}
}
OptionalState state = new OptionalState();
Deque<Spliterator<T>> splits = new ArrayDeque<>();
splits.addLast(stream.spliterator());
while (!splits.isEmpty()) {
Spliterator<T> spliterator = splits.removeLast();
if (spliterator.getExactSizeIfKnown() == 0) {
continue; // drop this split
}
// Many spliterators will have trySplits that are SUBSIZED even if they are not themselves
// SUBSIZED.
if (spliterator.hasCharacteristics(Spliterator.SUBSIZED)) {
// we can drill down to exactly the smallest nonempty spliterator
while (true) {
Spliterator<T> prefix = spliterator.trySplit();
if (prefix == null || prefix.getExactSizeIfKnown() == 0) {
break;
} else if (spliterator.getExactSizeIfKnown() == 0) {
spliterator = prefix;
break;
}
}
// spliterator is known to be nonempty now
spliterator.forEachRemaining(state::set);
return java.util.Optional.of(state.get());
}
Spliterator<T> prefix = spliterator.trySplit();
if (prefix == null || prefix.getExactSizeIfKnown() == 0) {
// we can't split this any further
spliterator.forEachRemaining(state::set);
if (state.set) {
return java.util.Optional.of(state.get());
}
// fall back to the last split
continue;
}
splits.addLast(prefix);
splits.addLast(spliterator);
}
return java.util.Optional.empty();
}
实质上,说实话,实现并不是那么复杂,但是我发现有些奇怪(如果这个问题以“基于观点的观点”结束,我会对此负责,我知道这可能会发生) .
首先是OptionalState类的创建,可以用单个元素的数组代替它:
T[] state = (T[]) new Object[1];
并简单地用作:
spliterator.forEachRemaining(x -> state[0] = x);
然后将整个方法分为三部分:
1)当已知某个分隔符为空时:
if (spliterator.getExactSizeIfKnown() == 0)
在这种情况下,很简单-放下它.
2)然后,如果已知分隔符已被SUBSIZED.这是“幸福之路”的情景;因为在这种情况下,我们可以将其拆分,直到到达最后一个元素.基本上,实现说:拆分直到前缀为null或为空(在这种情况下,使用“正确的”分隔符),或者如果在拆分之后已知“正确的”分隔符为空,则使用前缀1..这是通过以下方式完成的:
// spliterator is known to be nonempty now
spliterator.forEachRemaining(state::set);
return java.util.Optional.of(state.get());
我的第二个问题实际上是关于此评论的:
// Many spliterators will have trySplits that are SUBSIZED
// even if they are not themselves SUBSIZED.
这很有趣,但是我找不到这样的例子,如果有人将我介绍给我,我将不胜感激.实际上,由于存在此注释,因此下一个代码(方法的第3部分不能像第二个代码那样用while(true)完成),因为它假定在trySplit之后我们可以获得一个即使没有我们的第一个分离器,它也得到了补贴,因此必须转到findLast的最开始.
3)该方法的这一部分是在已知未对分割器进行补贴且这种情况下其大小未知的情况下;因此,它依赖于如何实现源代码中的Spliterator,在这种情况下,实际上findLast毫无意义…例如,来自HashSet的Splitter将返回最后一个存储桶中的最后一个条目…
解决方法:
>迭代未知大小的分隔符时,必须跟踪是否遇到了元素.这可以通过调用tryAdvance并使用返回值来完成,也可以通过与用于记录是否遇到元素的消费者的forEachRemaining一起使用.当您走后一条路线时,专用类比数组简单.一旦有了专用的类,为什么不也将其用于SIZED拆分器.
对我来说,奇怪的是,这个本地类(仅作为使用者使用)不实现消费者,而是需要通过state :: set进行绑定.
>考虑
Stream.concat(
Stream.of("foo").filter(s -> !s.isEmpty()),
Stream.of("bar", "baz"))
代表整个流的分隔符不能具有SIZED特性.但是,当拆分具有未知大小的第一个子流时,其余的流具有已知的大小.
测试代码:
Spliterator<String> sp = Stream.concat(
Stream.of("foo").filter(s -> !s.isEmpty()),
Stream.of("bar", "baz"))
.spliterator();
do {
System.out.println(
"SIZED: "+sp.hasCharacteristics(Spliterator.SIZED)
+ ", SUBSIZED: "+sp.hasCharacteristics(Spliterator.SUBSIZED)
+ ", exact size if known: "+sp.getExactSizeIfKnown());
} while(sp.trySplit() != null);
结果:
SIZED: false, SUBSIZED: false, exact size if known: -1
SIZED: true, SUBSIZED: true, exact size if known: 2
SIZED: true, SUBSIZED: true, exact size if known: 1
但是对我来说,当有人在评论中告知您知道拆分可以更改特征,然后使用SUBSIZED进行预测试时,看起来似乎很奇怪,而不是仅拆分并检查结果是否具有已知大小.毕竟,当特征不存在时,代码仍然会在备用分支中进行拆分.在my old answer中,我进行了预测试以避免分配数据结构,但是在此始终创建并使用ArrayDeque.但我认为,即使是我以前的答案也可以简化.
>我不确定您的目标是什么.当分割器具有ORDERED特性时,遍历和分割的顺序是明确定义的.由于HashSet没有排序,因此术语“ last”是没有意义的.如果您是激进的,则可以优化操作以仅返回无序流的第一个元素;是有效的,而且速度更快.
奇怪的是,这种情况是:
if (prefix == null || prefix.getExactSizeIfKnown() == 0) {
// we can't split this any further
(以及SUBSIZED路径中的类似循环终止)
仅仅因为一个前缀的大小已知为零,并不意味着后缀不能进一步分开.规范中没有任何内容说明这一点.
由于这种情况,Stream.concat(Stream.of(“ foo”),Stream.of(“ bar”,“ baz”)))可以得到最佳处理,而对于Stream.concat(Stream.of(), Stream.of(“ bar”,“ baz”)),它将回退遍历,因为第一个前缀的已知大小为零.
内容总结
以上是互联网集市为您收集整理的java-番石榴的Streams :: findLast实现全部内容,希望文章能够帮你解决java-番石榴的Streams :: findLast实现所遇到的程序开发问题。 如果觉得互联网集市技术教程内容还不错,欢迎将互联网集市网站推荐给程序员好友。
内容备注
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 gblab@vip.qq.com 举报,一经查实,本站将立刻删除。
内容手机端
扫描二维码推送至手机访问。