Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/java/330.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
从流和元素Java8生成流_Java_Java 8_Java Stream - Fatal编程技术网

从流和元素Java8生成流

从流和元素Java8生成流,java,java-8,java-stream,Java,Java 8,Java Stream,我正在研究一些Java8流特性。我对FP相当熟悉,三十年前写过一些Lisp,我想我可能会尝试做一些这个新工具并不真正针对的事情。无论如何,如果这个问题很愚蠢,我很高兴知道我的错误 我将给出一个具体的问题,尽管这是我试图解决的一个普遍概念 假设我想从流的每三个元素中得到一个流。在常规FP中,我将(大约)创建一个递归函数,该函数通过在删除两个元素后将列表的第一个元素与列表其余部分的(调用thyself)连接起来来运行。很简单。但要在流中实现这一点,我觉得我需要两种工具中的一种: 1) 一种让操作从流

我正在研究一些Java8流特性。我对FP相当熟悉,三十年前写过一些Lisp,我想我可能会尝试做一些这个新工具并不真正针对的事情。无论如何,如果这个问题很愚蠢,我很高兴知道我的错误

我将给出一个具体的问题,尽管这是我试图解决的一个普遍概念

假设我想从流的每三个元素中得到一个流。在常规FP中,我将(大约)创建一个递归函数,该函数通过在删除两个元素后将列表的第一个元素与列表其余部分的(调用thyself)连接起来来运行。很简单。但要在流中实现这一点,我觉得我需要两种工具中的一种:

1) 一种让操作从流中提取多个项目进行处理的方法(然后我只需要抓取三个,使用第一个,然后转储其余的)

2) 制造供应商的一种方法,它接受一个项目和一个流并创建一个流。然后我感觉我可以从第一个项目和缩短的流中创建一个下游流,尽管我仍然不清楚这是否会产生实际工作所需的递归魔法

开始编辑

因此,有一些有趣和有用的反馈;谢谢大家。特别是,这些评论帮助我澄清了我的大脑试图更好地处理的问题

首先,一个人可以——至少在概念上——拥有/需要序列中的顺序知识不应该阻止他允许完全并行的操作。我想到了一个例子,那就是图形人员倾向于做的卷积运算。想象一下模糊图像。每个像素都会根据其附近的像素进行修改,但这些像素本身只会被读取,而不会被修改

我的理解是(在这个阶段非常不确定!)streams机制是虚拟机管理的并行性的奇妙世界的主要入口点,迭代器仍然是他们一直以来的样子(是吗?不是?),如果这是正确的,那么使用迭代器来解决我正在讨论的问题域似乎并不太好

因此,至少在这一点上,创建分块拆分器的建议似乎是最有希望的,但是,男孩,支持该示例的代码似乎是一项艰巨的工作!我想我更愿意使用ForkJoin机制,尽管它现在是“旧帽子”:

不管怎样,我仍然对人们希望提供的更多见解感兴趣

结束编辑


有什么想法吗?我是在尝试使用这些流来做一些他们不打算做的事情,还是我遗漏了一些显而易见的事情

干杯,
Toby.

需要记住的一点是,
主要是为了利用并行处理的优势而设计的。这意味着它们有许多与之相关的条件,这些条件旨在给予VM以任何方便的顺序处理元素的大量自由。这方面的一个例子是坚持约化函数是关联的。另一个是局部变量是最终的。这些类型的条件意味着可以按任何顺序评估和收集流项目

这样做的一个自然结果是,
的最佳用例不涉及流值之间的依赖关系。在LISP这样的语言中,将整数流映射到它们的累积值这样的事情并不重要,但对于Java流来说却非常不自然(请参阅)

通过使用
顺序
来强制
不并行,有一些巧妙的方法可以绕过这些限制,但我的经验是,这些都是不值得的麻烦。如果您的问题涉及本质上连续的一系列项,在这些项中,状态是处理值所必需的,那么我建议使用传统的集合和迭代。由于流无论如何都无法并行化,代码将变得更清晰,并且不会执行更差的操作

话虽如此,如果您真的想这样做,那么最简单的方法是让收集器存储每三个项目,然后再次将它们作为流发送出去:

class EveryThird {

    private final List<Integer> list = new ArrayList<>();
    private int count = 0;

    public void accept(Integer i) {
        if (count++ % 3 == 0)
            list.add(i);
    }

    public EveryThird combine(EveryThird other) {
        list.addAll(other.list);
        count += other.count;
        return this;
    }

    public Stream<Integer> stream() {
        return list.stream();
    }
}

但这并不是收集器设计的真正目的,这是非常低效的,因为它不必要地收集流。如上所述,我的建议是在这种情况下使用传统的迭代。

Java的流与FP的(惰性)序列完全不同。如果您熟悉Clojure,其区别与lazy seq和reducer之间的区别完全相同。lazy-seq将所有处理单独打包到每个元素中,从而允许获得单独处理的元素,而reducer则在单个原子操作中折叠整个序列

<>具体地说,对于您所描述的示例,请考虑依赖于流分区转换,如详细描述的那样。你很容易就能做到

partition(originalStream, 3).map(xs -> xs.get(0));
产生一个每三个元素都是原始元素的流

这将保持效率、惰性和并行性。

您可以使用 然后给定
aStream
,您可以创建一个由大小为3的列表组成的流(最后一个除外),并使用该列表的第一个元素

Stream<T> aStream = ...;
Stream<List<T>> batchedStream =  
    new BatchingSpliterator.Builder().wrap(aStream).batchSize(3).stream();

batchedStream.map(l -> l.get(0) ). ... 
我的库增强了标准流API。特别是,它添加了允许递归定义自定义操作的方法。它接受一个函数,该函数接收流头(第一个元素)和流尾(其余元素的流),并应返回将要使用的结果流,而不是原始流。例如,您可以按如下方式定义
every3
操作:

public static <T> StreamEx<T> every3(StreamEx<T> input) {
    return input.headTail(
        (first, tail1) -> tail1.<T>headTail(
            (second, tail2) -> tail2.headTail(
                (third, tail3) -> every3(tail3))).prepend(first));
}
public static streamx every3(streamx输入){
返回输入.headTail(
(首先,tail1)->tail1.headTail(
(第二,tail2)->tail2
batchedStream.parallel().map(l -> l.get(0) ). ....    
public static <T> StreamEx<T> every3(StreamEx<T> input) {
    return input.headTail(
        (first, tail1) -> tail1.<T>headTail(
            (second, tail2) -> tail2.headTail(
                (third, tail3) -> every3(tail3))).prepend(first));
}