加入收藏 | 设为首页 | 会员中心 | 我要投稿 李大同 (https://www.lidatong.com.cn/)- 科技、建站、经验、云计算、5G、大数据,站长网!
当前位置: 首页 > 编程开发 > Java > 正文

在Java 8 Stream中设置布尔标志

发布时间:2020-12-15 04:49:13 所属栏目:Java 来源:网络整理
导读:我想知道从 java流设置布尔标志值的最佳实践是什么.这是我想要做的一个例子: ListInteger list = Arrays.asList(1,2,3,4,5); boolean flag = false; ListInteger newList = list.stream() //many other filters,flatmaps,etc... .filter(i - { if(condition
我想知道从 java流设置布尔标志值的最佳实践是什么.这是我想要做的一个例子:

List<Integer> list = Arrays.asList(1,2,3,4,5);
    boolean flag = false;
    List<Integer> newList = list.stream()
                                //many other filters,flatmaps,etc...
                                .filter(i -> {
                                    if(condition(i)){
                                        flag = true;
                                    }
                                    return condition(i);
                                })
                                //many other filters,etc...
                                .collect(Collectors.toList());
    //do some work with the new list and the flag

但是,这违反了语言限制“lambda表达式中使用的变量应该是最终的或有效的最终结果”.我能想到一些解决方案,但我不确定哪种解决方案最好.我的第一个解决方案是添加匹配条件的元素到列表并检查List :: isEmpty.也可以在AtomicReference中包装标志.

请注意,我的问题类似于这个question,但我试图在最后提取一个布尔值而不是设置一个变量.

解决方法

不要使用完全不相关的任务来修改生成newList的任务.只是用

boolean flag = list.stream().anyMatch(i -> condition(i));

其次是其他流代码.

有两个典型的反对意见

>但这是两次迭代.

是的,确实如此,但是谁说迭代一次ArrayList是个问题呢?不要试图避免多个流操作,除非您知道您确实有一个昂贵的遍历流源,如外部文件.如果您拥有如此昂贵的资源,那么首先将元素收集到集合中可能仍然更容易,您可以遍历两次.
>但它不止一次地评估条件(……).

嗯,实际上它的评估比原始代码要少

.filter(i -> {
    if(condition(i)){
        flag = true;
    }
    return condition(i);
})

因为anyMatch在第一个匹配时停止,而原始谓词在每个元素上无条件地评估条件(i)两次.

如果在条件之前有几个中间步骤,则可以收集到中间列表中

List<Integer> intermediate = list.stream()
    //many other filters,etc...
    .filter(i -> condition(i))
    .collect(Collectors.toList());
boolean flag = !intermediate.isEmpty();
List<Integer> newList = intermediate.stream()
    //many other filters,etc...
    .collect(Collectors.toList());

但更常见的是,中间步骤并不像乍看之下那么昂贵.类似的中间步骤的性能特征可以根据实际终端操作在不同的流操作中变化.因此,它可能仍然可以在飞行中充分执行这些步骤:

boolean flag = list.stream()
    //many other filters,etc...
    .anyMatch(i -> condition(i));
List<Integer> newList = list.stream()
    //many other filters,etc...
    .filter(i -> condition(i))
    //many other filters,etc...
    .collect(Collectors.toList());

如果您担心代码重复本身,您仍然可以将公共代码放入流返回实用程序方法中.

只有在非常罕见的情况下,进入低级API并像this answer一样窥视Stream是值得的.如果你这样做,你不应该走迭代器的路线,它会丢失有关内容的元信息,但是使用Spliterator:

Spliterator<Integer> sp = list.stream()
    //many other filters,etc...
    .filter(i -> condition(i))
    .spliterator();
Stream.Builder<Integer> first = Stream.builder();
boolean flag = sp.tryAdvance(first);
List<Integer> newList = Stream.concat(first.build(),StreamSupport.stream(sp,false))
    //many other filters,etc...
    .collect(Collectors.toList());

请注意,在所有这些情况下,如果flag为false,则可以快捷方式,因为结果只能是空列表:

List<Integer> newList = !flag? Collections.emptyList():
/*
   subsequent stream operation
 */;

(编辑:李大同)

【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容!

    推荐文章
      热点阅读