在任何其他中间方法之前,如何在打开Java8流时运行单个函数?

在任何其他中间方法之前,如何在打开Java8流时运行单个函数?,java,java-8,handler,java-stream,Java,Java 8,Handler,Java Stream,老实说,在相邻的代码行之外,我甚至不确定这是否可行。然而,我想我会向社区询问 Java8允许通过流API管理其集合。过去我们需要外部迭代,现在我们可以简单地使用: <Collection>.stream().forEach([expression]); 然而,如果我可以这样做,那就太好了: labelData(); firstNames.stream().sequential().forEach(sz -> reportData(sz)); firstNames.strea

老实说,在相邻的代码行之外,我甚至不确定这是否可行。然而,我想我会向社区询问

Java8允许通过流API管理其集合。过去我们需要外部迭代,现在我们可以简单地使用:

<Collection>.stream().forEach([expression]);
然而,如果我可以这样做,那就太好了:

labelData();
firstNames.stream().sequential().forEach(sz -> reportData(sz));
firstNames.stream().sequential().
    .onOpen(labelData())
    .forEach(sz->reportData(sz));
我知道可以使用BaseStream.onClose(Runnable closeHandler)设置on close方法。开放式数据库是否存在这样的方法

谢谢您的时间。

这个怎么样:

labelData();
firstNames.forEach(this::reportData);
有时候简单的答案更好

这个怎么样:

labelData();
firstNames.forEach(this::reportData);
有时候简单的答案更好

这就是map()的用途

map()是一个中间操作,在处理每个元素时对其执行转换

例如,代码:

Stream.of("One","Two", "Three", "Four");
        .map(e -> "Number " + e)
        .forEach(System.out::println);
将输出:

Number One
Number Two
Number Three
Number Four
TEST OUTPUT:
------------
Number Five
Number Six
Number Seven
Number Eight
如果你真的只是想在流之前写些东西。。。就这么做吧。无论如何,在流内部调用它的效率要低得多。如果只需要在流包含元素时写出,可以执行以下操作:

package stream;

public class OneTimePrinter {
    private boolean shouldPrint = true;

    public void print(Object o){
        if (shouldPrint){
            System.out.println(o);
            shouldPrint = false;
        }
    }
}
然后在peek()操作中使用OneTimePrinter类:

OneTimePrinter printer1 = new OneTimePrinter();
Stream.of("Five","Six", "Seven", "Eight")
.peek((e) -> printer1.print("TEST OUTPUT:\n------------"))
.map(e -> "Number " + e)
.forEach(System.out::println);  

OneTimePrinter printer2 = new OneTimePrinter();
Stream.of()
.peek((e) -> printer2.print("TEST OUTPUT:\n------------"))
.map(e -> "Number " + e)
.forEach(System.out::println);  
这将输出:

Number One
Number Two
Number Three
Number Four
TEST OUTPUT:
------------
Number Five
Number Six
Number Seven
Number Eight
在执行forEach()之前,只调用labelData()函数更简单、更高效。出于好奇,我想出了三种不同的方法来实现这一点,并使用以下代码使用一百万个元素流对它们进行了测试:

首先,一种新类型的收集器,它执行操作并返回原始流:

public interface StreamOpenCollector<T> extends Collector<T, Object, Stream<T>> {   
    static <T> Collector<T, Object, Stream<T>> onOpen(Object arg, Consumer<Object> consumer){
        return Collectors.collectingAndThen(Collectors.toList(), (list) -> {
            consumer.accept(arg);
            return list.stream();
        });
    }   
}
正如您所看到的,skip方法始终更快,但不足以让您担心,除非您正在处理流中的数十亿项。

这就是map()的用途

map()是一个中间操作,在处理每个元素时对其执行转换

例如,代码:

Stream.of("One","Two", "Three", "Four");
        .map(e -> "Number " + e)
        .forEach(System.out::println);
将输出:

Number One
Number Two
Number Three
Number Four
TEST OUTPUT:
------------
Number Five
Number Six
Number Seven
Number Eight
如果你真的只是想在流之前写些东西。。。就这么做吧。无论如何,在流内部调用它的效率要低得多。如果只需要在流包含元素时写出,可以执行以下操作:

package stream;

public class OneTimePrinter {
    private boolean shouldPrint = true;

    public void print(Object o){
        if (shouldPrint){
            System.out.println(o);
            shouldPrint = false;
        }
    }
}
然后在peek()操作中使用OneTimePrinter类:

OneTimePrinter printer1 = new OneTimePrinter();
Stream.of("Five","Six", "Seven", "Eight")
.peek((e) -> printer1.print("TEST OUTPUT:\n------------"))
.map(e -> "Number " + e)
.forEach(System.out::println);  

OneTimePrinter printer2 = new OneTimePrinter();
Stream.of()
.peek((e) -> printer2.print("TEST OUTPUT:\n------------"))
.map(e -> "Number " + e)
.forEach(System.out::println);  
这将输出:

Number One
Number Two
Number Three
Number Four
TEST OUTPUT:
------------
Number Five
Number Six
Number Seven
Number Eight
在执行forEach()之前,只调用labelData()函数更简单、更高效。出于好奇,我想出了三种不同的方法来实现这一点,并使用以下代码使用一百万个元素流对它们进行了测试:

首先,一种新类型的收集器,它执行操作并返回原始流:

public interface StreamOpenCollector<T> extends Collector<T, Object, Stream<T>> {   
    static <T> Collector<T, Object, Stream<T>> onOpen(Object arg, Consumer<Object> consumer){
        return Collectors.collectingAndThen(Collectors.toList(), (list) -> {
            consumer.accept(arg);
            return list.stream();
        });
    }   
}
正如您所看到的,skip方法始终更快,但不足以让您担心,除非您正在处理流中的数十亿项。

如前所述,.map()是您需要的

但我想指出一些我认为需要指出的事情:labelData()对名字有副作用(它看起来像是一个字段/全局变量)

在函数式编程中,副作用对我来说并不好,因为它们会引入状态。这也是流来避免状态的原因之一

另外,听起来很奇怪,你不是在最后收集流,而是报告每个元素。但这可能是由于您的示例的简化。

如前所述,.map()是您需要的

但我想指出一些我认为需要指出的事情:labelData()对名字有副作用(它看起来像是一个字段/全局变量)

在函数式编程中,副作用对我来说并不好,因为它们会引入状态。这也是流来避免状态的原因之一


另外,听起来很奇怪,你不是在最后收集流,而是报告每个元素。但这可能是因为您的示例简化了。

第一个示例更短、更简单、更快、更清楚地说明了它在做什么。你能解释一下第二个例子“更好”的地方是什么吗?好吧,这个例子是有点结构的,通常这是一个实例问题。然而,在某些情况下,我更喜欢在输出之前加上标签甚至函数标记,并且我更喜欢在可能的情况下使用流API。@PeterLawrey,为了清晰起见,我对这两个都进行了编辑。希望这会有帮助。然后你必须使用
收集
。您的任务与执行的任务类似(请注意prefix参数)。看看它的后端。第一个例子更短、更简单、更快、更清楚地说明了它在做什么。你能解释一下第二个例子“更好”的地方是什么吗?好吧,这个例子是有点结构的,通常这是一个实例问题。然而,在某些情况下,我更喜欢在输出之前加上标签甚至函数标记,并且我更喜欢在可能的情况下使用流API。@PeterLawrey,为了清晰起见,我对这两个都进行了编辑。希望这会有帮助。然后你必须使用
收集
。您的任务与执行的任务类似(请注意prefix参数)。看看它的后端。谢谢,这正是我要找的。我很清楚效率问题,这主要是一个理论问题,你的回答很好。谢谢,这正是我想要的。我很清楚效率的问题,这主要是一个理论问题,你的回答很好。labelData()纯粹是一个符号捷径。可以将其视为psuedo代码。它不是一个实际的方法,只是在报告任意流之前的前置方法。
firstnameslabel=labelData(firstNames);firstnameslabel.stream().forEach(sz->reportData(sz))我认为这更能说明为什么需要地图。如果
labelData()
是以这种方式构造的,就像一个纯函数,并且没有副作用,那么代码将变成
firstNames.stream().map(f->