有没有办法重用流?

piwo6bdm  于 2021-07-13  发布在  Java
关注(0)|答案(7)|浏览(457)

这个问题在这里已经有答案了

复制流以避免“流已被操作或关闭”(10个答案)
12个月前关门了。
我正在学习Java8的新特性,并且在尝试流时( java.util.stream.Stream )我发现一条流不能用两次。
有没有办法再利用它?

pxiryf3j

pxiryf3j1#

如果希望具有重用流的效果,可以将流表达式 Package 在一个提供者中并调用 myStreamSupplier.get() 只要你想要一个新的。例如:

Supplier<Stream<String>> sup = () -> someList.stream();
List<String> nonEmptyStrings = sup.get().filter(s -> !s.isEmpty()).collect(Collectors.toList());
Set<String> uniqueStrings = sup.get().collect(Collectors.toSet());
nbysray5

nbysray52#

根据文件:
流只能操作一次(调用中间或终端流操作)。
如果流实现检测到流正在被重用,它可能会抛出illegalstateexception。
所以答案是否定的,流不是用来重用的。

rkue9o1l

rkue9o1l3#

正如其他人所说,“不,你不能”。
但是记住手边的 summaryStatistics() 对于许多基本操作:
所以不是:

List<Person> personList = getPersons();

personList.stream().mapToInt(p -> p.getAge()).average().getAsDouble();
personList.stream().mapToInt(p -> p.getAge()).min().getAsInt();
personList.stream().mapToInt(p -> p.getAge()).max().getAsInt();

你可以:

// Can also be DoubleSummaryStatistics from mapToDouble()

IntSummaryStatistics stats = personList.stream()
                                       .mapToInt(p-> p.getAge())
                                       .summaryStatistics();

stats.getAverage();
stats.getMin();
stats.getMax();
wqnecbli

wqnecbli4#

这条溪流的全部意思是它是一次性的。这允许您创建不可重入的源(例如,从网络连接读取行),而无需中间存储。但是,如果您希望重用流内容,可以将其转储到中间集合以获取“硬拷贝”:

Stream<MyType> stream = // get the stream from somewhere
List<MyType> list = stream.collect(Collectors.toList()); // materialize the stream contents
list.stream().doSomething // create a new stream from the list
list.stream().doSomethingElse // create one more stream from the list

如果您不想具体化流,在某些情况下,可以同时对同一个流执行多个操作。例如,您可以参考此问题或此问题了解详细信息。

mbzjlibv

mbzjlibv5#

想想看,这种“重用”流的意愿就是用一个好的内联操作来实现所需结果的意愿。所以,基本上,我们在这里讨论的是,在我们写了一个终端操作之后,我们能做些什么来继续处理?
1) 如果终端操作返回一个集合,那么问题马上就解决了,因为每个集合都可以转换回流(jdk8)。

List<Integer> l=Arrays.asList(5,10,14);
        l.stream()
            .filter(nth-> nth>5)
            .collect(Collectors.toList())
            .stream()
            .filter(nth-> nth%2==0).forEach(nth-> System.out.println(nth));

2) 如果您的终端操作返回一个optional,通过对optional类的jdk 9增强,您可以将可选结果转换为流,并获得所需的nice内联操作:

List<Integer> l=Arrays.asList(5,10,14);
        l.stream()
            .filter(nth-> nth>5)
            .findAny()
            .stream()
            .filter(nth-> nth%2==0).forEach(nth-> System.out.println(nth));

3) 如果您的终端操作返回其他内容,我真的怀疑您是否应该考虑使用流来处理这样的结果:

List<Integer> l=Arrays.asList(5,10,14);
        boolean allEven=l.stream()
            .filter(nth-> nth>5)
            .allMatch(nth-> nth%2==0);
        if(allEven){
            ...
        }
8ftvxx2r

8ftvxx2r6#

正如其他人所注意到的,流对象本身不能被重用。
但是获得重用流效果的一种方法是将流创建代码提取到函数中。
您可以通过创建包含流创建代码的方法或函数对象来实现这一点。你可以多次使用它。
例子:

public static void main(String[] args) {
    List<Integer> list = Arrays.asList(1, 2, 3, 4, 5);

    // The normal way to use a stream:
    List<String> result1 = list.stream()
        .filter(i -> i % 2 == 1)
        .map(i -> i * i)
        .limit(10)
        .map(i -> "i :" + i)
        .collect(toList());

    // The stream operation can be extracted to a local function to
    // be reused on multiple sources:
    Function<List<Integer>, List<String>> listOperation = l -> l.stream()
        .filter(i -> i % 2 == 1)
        .map(i -> i * i)
        .limit(10)
        .map(i -> "i :" + i)
        .collect(toList());

    List<String> result2 = listOperation.apply(list);
    List<String> result3 = listOperation.apply(Arrays.asList(1, 2, 3));

    // Or the stream operation can be extracted to a static method,
    // if it doesn't refer to any local variables:
    List<String> result4 = streamMethod(list);

    // The stream operation can also have Stream as argument and return value,
    // so that it can be used as a component of a longer stream pipeline:
    Function<Stream<Integer>, Stream<String>> streamOperation = s -> s
        .filter(i -> i % 2 == 1)
        .map(i -> i * i)
        .limit(10)
        .map(i -> "i :" + i);

    List<String> result5 = streamOperation.apply(list.stream().map(i -> i * 2))
        .filter(s -> s.length() < 7)
        .sorted()
        .collect(toCollection(LinkedList::new));
}

public static List<String> streamMethod(List<Integer> l) {
    return l.stream()
        .filter(i -> i % 2 == 1)
        .map(i -> i * i)
        .limit(10)
        .map(i -> "i :" + i)
        .collect(toList());
}

另一方面,如果已经有一个流对象要多次迭代,那么必须将流的内容保存在某个集合对象中。
然后,您可以从该集合中获得具有相同内容的多个流。
例子:

public void test(Stream<Integer> stream) {
    // Create a copy of the stream elements
    List<Integer> streamCopy = stream.collect(toList());

    // Use the copy to get multiple streams
    List<Integer> result1 = streamCopy.stream() ...
    List<Integer> result2 = streamCopy.stream() ...
}
qgzx9mmu

qgzx9mmu7#

函数式java库提供了自己的流,这些流执行您所要求的操作,即它们是内存化的和懒惰的。您可以使用它的转换方法在JavaSDK对象和fj对象之间进行转换,例如。 Java8.JavaStream_Stream(stream) 将返回一个可重用的fj流,给定一个jdk8流。

相关问题